changeset 8133:f23a84a1cf8e

Merge
author mullan
date Fri, 06 Sep 2013 12:10:30 -0400
parents 0aba8b6232af 2064b2077a62
children 257de3e3a278
files src/share/classes/java/util/stream/CloseableStream.java src/share/classes/java/util/stream/DelegatingStream.java test/java/util/Map/TreeBinSplitBackToEntries.java test/sun/tools/jconsole/ImmutableResourceTest.java test/sun/tools/jconsole/ImmutableResourceTest.sh
diffstat 163 files changed, 8801 insertions(+), 4966 deletions(-) [+]
line wrap: on
line diff
--- a/src/macosx/classes/sun/lwawt/LWToolkit.java	Fri Sep 06 12:04:18 2013 -0400
+++ b/src/macosx/classes/sun/lwawt/LWToolkit.java	Fri Sep 06 12:10:30 2013 -0400
@@ -38,6 +38,7 @@
 import sun.awt.*;
 import sun.lwawt.macosx.*;
 import sun.print.*;
+import sun.security.util.SecurityConstants;
 
 public abstract class LWToolkit extends SunToolkit implements Runnable {
 
@@ -502,7 +503,7 @@
     public Clipboard getSystemClipboard() {
         SecurityManager security = System.getSecurityManager();
         if (security != null) {
-            security.checkSystemClipboardAccess();
+            security.checkPermission(SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION);
         }
 
         synchronized (this) {
--- a/src/macosx/classes/sun/nio/ch/KQueueArrayWrapper.java	Fri Sep 06 12:04:18 2013 -0400
+++ b/src/macosx/classes/sun/nio/ch/KQueueArrayWrapper.java	Fri Sep 06 12:10:30 2013 -0400
@@ -87,6 +87,7 @@
     private int incomingInterruptFD;
 
     static {
+        IOUtil.load();
         initStructSizes();
         String datamodel = java.security.AccessController.doPrivileged(
             new sun.security.action.GetPropertyAction("sun.arch.data.model")
--- a/src/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java	Fri Sep 06 12:04:18 2013 -0400
+++ b/src/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java	Fri Sep 06 12:10:30 2013 -0400
@@ -246,9 +246,4 @@
         }
         return this;
     }
-
-
-    static {
-        Util.load();
-    }
 }
--- a/src/share/back/SDE.c	Fri Sep 06 12:04:18 2013 -0400
+++ b/src/share/back/SDE.c	Fri Sep 06 12:10:30 2013 -0400
@@ -28,6 +28,12 @@
 #include "util.h"
 #include "SDE.h"
 
+#ifdef __APPLE__
+/* use setjmp/longjmp versions that do not save/restore the signal mask */
+#define setjmp _setjmp
+#define longjmp _longjmp
+#endif
+
 /**
  * This SourceDebugExtension code does not
  * allow concurrent translation - due to caching method.
--- a/src/share/classes/java/awt/TextComponent.java	Fri Sep 06 12:04:18 2013 -0400
+++ b/src/share/classes/java/awt/TextComponent.java	Fri Sep 06 12:10:30 2013 -0400
@@ -35,6 +35,7 @@
 import javax.swing.text.AttributeSet;
 import javax.accessibility.*;
 import java.awt.im.InputMethodRequests;
+import sun.security.util.SecurityConstants;
 
 /**
  * The <code>TextComponent</code> class is the superclass of
@@ -728,7 +729,7 @@
         SecurityManager sm = System.getSecurityManager();
         if (sm == null) return true;
         try {
-            sm.checkSystemClipboardAccess();
+            sm.checkPermission(SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION);
             return true;
         } catch (SecurityException e) {}
         return false;
--- a/src/share/classes/java/awt/Toolkit.java	Fri Sep 06 12:04:18 2013 -0400
+++ b/src/share/classes/java/awt/Toolkit.java	Fri Sep 06 12:10:30 2013 -0400
@@ -1270,12 +1270,8 @@
      * <p>
      * Each actual implementation of this method should first check if there
      * is a security manager installed. If there is, the method should call
-     * the security manager's <code>checkSystemClipboardAccess</code> method
-     * to ensure it's ok to to access the system clipboard. If the default
-     * implementation of <code>checkSystemClipboardAccess</code> is used (that
-     * is, that method is not overriden), then this results in a call to the
-     * security manager's <code>checkPermission</code> method with an <code>
-     * AWTPermission("accessClipboard")</code> permission.
+     * the security manager's {@link SecurityManager#checkPermission
+     * checkPermission} method to check {@code AWTPermission("accessClipboard")}.
      *
      * @return    the system Clipboard
      * @exception HeadlessException if GraphicsEnvironment.isHeadless()
@@ -1318,14 +1314,9 @@
      * system selection <code>Clipboard</code> as described above.
      * <p>
      * Each actual implementation of this method should first check if there
-     * is a <code>SecurityManager</code> installed. If there is, the method
-     * should call the <code>SecurityManager</code>'s
-     * <code>checkSystemClipboardAccess</code> method to ensure that client
-     * code has access the system selection. If the default implementation of
-     * <code>checkSystemClipboardAccess</code> is used (that is, if the method
-     * is not overridden), then this results in a call to the
-     * <code>SecurityManager</code>'s <code>checkPermission</code> method with
-     * an <code>AWTPermission("accessClipboard")</code> permission.
+     * is a security manager installed. If there is, the method should call
+     * the security manager's {@link SecurityManager#checkPermission
+     * checkPermission} method to check {@code AWTPermission("accessClipboard")}.
      *
      * @return the system selection as a <code>Clipboard</code>, or
      *         <code>null</code> if the native platform does not support a
@@ -1699,25 +1690,20 @@
      * therefore not assume that the EventQueue instance returned
      * by this method will be shared by other applets or the system.
      *
-     * <p>First, if there is a security manager, its
-     * <code>checkAwtEventQueueAccess</code>
-     * method is called.
-     * If  the default implementation of <code>checkAwtEventQueueAccess</code>
-     * is used (that is, that method is not overriden), then this results in
-     * a call to the security manager's <code>checkPermission</code> method
-     * with an <code>AWTPermission("accessEventQueue")</code> permission.
+     * <p> If there is a security manager then its
+     * {@link SecurityManager#checkPermission checkPermission} method
+     * is called to check {@code AWTPermission("accessEventQueue")}.
      *
      * @return    the <code>EventQueue</code> object
      * @throws  SecurityException
-     *          if a security manager exists and its <code>{@link
-     *          java.lang.SecurityManager#checkAwtEventQueueAccess}</code>
-     *          method denies access to the <code>EventQueue</code>
+     *          if a security manager is set and it denies access to
+     *          the {@code EventQueue}
      * @see     java.awt.AWTPermission
     */
     public final EventQueue getSystemEventQueue() {
         SecurityManager security = System.getSecurityManager();
         if (security != null) {
-          security.checkAwtEventQueueAccess();
+            security.checkPermission(SecurityConstants.AWT.CHECK_AWT_EVENTQUEUE_PERMISSION);
         }
         return getSystemEventQueueImpl();
     }
--- a/src/share/classes/java/awt/Window.java	Fri Sep 06 12:04:18 2013 -0400
+++ b/src/share/classes/java/awt/Window.java	Fri Sep 06 12:10:30 2013 -0400
@@ -195,10 +195,9 @@
     /**
      * This represents the warning message that is
      * to be displayed in a non secure window. ie :
-     * a window that has a security manager installed for
-     * which calling SecurityManager.checkTopLevelWindow()
-     * is false.  This message can be displayed anywhere in
-     * the window.
+     * a window that has a security manager installed that denies
+     * {@code AWTPermission("showWindowWithoutWarningBanner")}.
+     * This message can be displayed anywhere in the window.
      *
      * @serial
      * @see #getWarningString
@@ -417,11 +416,10 @@
      * Constructs a new, initially invisible window in default size with the
      * specified {@code GraphicsConfiguration}.
      * <p>
-     * If there is a security manager, this method first calls
-     * the security manager's {@code checkTopLevelWindow}
-     * method with {@code this}
-     * as its argument to determine whether or not the window
-     * must be displayed with a warning banner.
+     * If there is a security manager, then it is invoked to check
+     * {@code AWTPermission("showWindowWithoutWarningBanner")}
+     * to determine whether or not the window must be displayed with
+     * a warning banner.
      *
      * @param gc the {@code GraphicsConfiguration} of the target screen
      *     device. If {@code gc} is {@code null}, the system default
@@ -432,7 +430,6 @@
      *     {@code GraphicsEnvironment.isHeadless()} returns {@code true}
      *
      * @see java.awt.GraphicsEnvironment#isHeadless
-     * @see java.lang.SecurityManager#checkTopLevelWindow
      */
     Window(GraphicsConfiguration gc) {
         init(gc);
@@ -511,25 +508,16 @@
 
     /**
      * Constructs a new, initially invisible window in the default size.
-     *
-     * <p>First, if there is a security manager, its
-     * {@code checkTopLevelWindow}
-     * method is called with {@code this}
-     * as its argument
-     * to see if it's ok to display the window without a warning banner.
-     * If the default implementation of {@code checkTopLevelWindow}
-     * is used (that is, that method is not overriden), then this results in
-     * a call to the security manager's {@code checkPermission} method
-     * with an {@code AWTPermission("showWindowWithoutWarningBanner")}
-     * permission. It that method raises a SecurityException,
-     * {@code checkTopLevelWindow} returns false, otherwise it
-     * returns true. If it returns false, a warning banner is created.
+     * <p>
+     * If there is a security manager set, it is invoked to check
+     * {@code AWTPermission("showWindowWithoutWarningBanner")}.
+     * If that check fails with a {@code SecurityException} then a warning
+     * banner is created.
      *
      * @exception HeadlessException when
      *     {@code GraphicsEnvironment.isHeadless()} returns {@code true}
      *
      * @see java.awt.GraphicsEnvironment#isHeadless
-     * @see java.lang.SecurityManager#checkTopLevelWindow
      */
     Window() throws HeadlessException {
         GraphicsEnvironment.checkHeadless();
@@ -541,11 +529,10 @@
      * {@code Frame} as its owner. The window will not be focusable
      * unless its owner is showing on the screen.
      * <p>
-     * If there is a security manager, this method first calls
-     * the security manager's {@code checkTopLevelWindow}
-     * method with {@code this}
-     * as its argument to determine whether or not the window
-     * must be displayed with a warning banner.
+     * If there is a security manager set, it is invoked to check
+     * {@code AWTPermission("showWindowWithoutWarningBanner")}.
+     * If that check fails with a {@code SecurityException} then a warning
+     * banner is created.
      *
      * @param owner the {@code Frame} to act as owner or {@code null}
      *    if this window has no owner
@@ -555,7 +542,6 @@
      *    {@code GraphicsEnvironment.isHeadless} returns {@code true}
      *
      * @see java.awt.GraphicsEnvironment#isHeadless
-     * @see java.lang.SecurityManager#checkTopLevelWindow
      * @see #isShowing
      */
     public Window(Frame owner) {
@@ -570,11 +556,10 @@
      * unless its nearest owning {@code Frame} or {@code Dialog}
      * is showing on the screen.
      * <p>
-     * If there is a security manager, this method first calls
-     * the security manager's {@code checkTopLevelWindow}
-     * method with {@code this}
-     * as its argument to determine whether or not the window
-     * must be displayed with a warning banner.
+     * If there is a security manager set, it is invoked to check
+     * {@code AWTPermission("showWindowWithoutWarningBanner")}.
+     * If that check fails with a {@code SecurityException} then a
+     * warning banner is created.
      *
      * @param owner the {@code Window} to act as owner or
      *     {@code null} if this window has no owner
@@ -585,7 +570,6 @@
      *     {@code true}
      *
      * @see       java.awt.GraphicsEnvironment#isHeadless
-     * @see       java.lang.SecurityManager#checkTopLevelWindow
      * @see       #isShowing
      *
      * @since     1.2
@@ -603,11 +587,10 @@
      * its nearest owning {@code Frame} or {@code Dialog}
      * is showing on the screen.
      * <p>
-     * If there is a security manager, this method first calls
-     * the security manager's {@code checkTopLevelWindow}
-     * method with {@code this}
-     * as its argument to determine whether or not the window
-     * must be displayed with a warning banner.
+     * If there is a security manager set, it is invoked to check
+     * {@code AWTPermission("showWindowWithoutWarningBanner")}. If that
+     * check fails with a {@code SecurityException} then a warning banner
+     * is created.
      *
      * @param owner the window to act as owner or {@code null}
      *     if this window has no owner
@@ -621,7 +604,6 @@
      *     {@code true}
      *
      * @see       java.awt.GraphicsEnvironment#isHeadless
-     * @see       java.lang.SecurityManager#checkTopLevelWindow
      * @see       GraphicsConfiguration#getBounds
      * @see       #isShowing
      * @since     1.3
@@ -1362,10 +1344,9 @@
      * Gets the warning string that is displayed with this window.
      * If this window is insecure, the warning string is displayed
      * somewhere in the visible area of the window. A window is
-     * insecure if there is a security manager, and the security
-     * manager's {@code checkTopLevelWindow} method returns
-     * {@code false} when this window is passed to it as an
-     * argument.
+     * insecure if there is a security manager and the security
+     * manager denies
+     * {@code AWTPermission("showWindowWithoutWarningBanner")}.
      * <p>
      * If the window is secure, then {@code getWarningString}
      * returns {@code null}. If the window is insecure, this
@@ -1373,7 +1354,6 @@
      * {@code awt.appletWarning}
      * and returns the string value of that property.
      * @return    the warning string for this window.
-     * @see       java.lang.SecurityManager#checkTopLevelWindow(java.lang.Object)
      */
     public final String getWarningString() {
         return warningString;
@@ -1383,10 +1363,12 @@
         warningString = null;
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
-            if (!sm.checkTopLevelWindow(this)) {
+            try {
+                sm.checkPermission(SecurityConstants.AWT.TOPLEVEL_WINDOW_PERMISSION);
+            } catch (SecurityException se) {
                 // make sure the privileged action is only
                 // for getting the property! We don't want the
-                // above checkTopLevelWindow call to always succeed!
+                // above checkPermission call to always succeed!
                 warningString = AccessController.doPrivileged(
                       new GetPropertyAction("awt.appletWarning",
                                             "Java Applet Window"));
--- a/src/share/classes/java/awt/event/InputEvent.java	Fri Sep 06 12:04:18 2013 -0400
+++ b/src/share/classes/java/awt/event/InputEvent.java	Fri Sep 06 12:10:30 2013 -0400
@@ -33,6 +33,7 @@
 
 import sun.awt.AWTAccessor;
 import sun.util.logging.PlatformLogger;
+import sun.security.util.SecurityConstants;
 
 /**
  * The root event class for all component-level input events.
@@ -350,7 +351,7 @@
             SecurityManager sm = System.getSecurityManager();
             if (sm != null) {
                 try {
-                    sm.checkSystemClipboardAccess();
+                    sm.checkPermission(SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION);
                     b = true;
                 } catch (SecurityException se) {
                     if (logger.isLoggable(PlatformLogger.Level.FINE)) {
--- a/src/share/classes/java/io/Console.java	Fri Sep 06 12:04:18 2013 -0400
+++ b/src/share/classes/java/io/Console.java	Fri Sep 06 12:10:30 2013 -0400
@@ -124,9 +124,11 @@
     * {@link java.io.Reader#read(java.nio.CharBuffer) read(java.nio.CharBuffer)}
     * on the returned object will not read in characters beyond the line
     * bound for each invocation, even if the destination buffer has space for
-    * more characters. A line bound is considered to be any one of a line feed
-    * (<tt>'\n'</tt>), a carriage return (<tt>'\r'</tt>), a carriage return
-    * followed immediately by a linefeed, or an end of stream.
+    * more characters. The {@code Reader}'s {@code read} methods may block if a
+    * line bound has not been entered or reached on the console's input device.
+    * A line bound is considered to be any one of a line feed (<tt>'\n'</tt>),
+    * a carriage return (<tt>'\r'</tt>), a carriage return followed immediately
+    * by a linefeed, or an end of stream.
     *
     * @return  The reader associated with this console
     */
--- a/src/share/classes/java/lang/AutoCloseable.java	Fri Sep 06 12:04:18 2013 -0400
+++ b/src/share/classes/java/lang/AutoCloseable.java	Fri Sep 06 12:10:30 2013 -0400
@@ -26,7 +26,24 @@
 package java.lang;
 
 /**
- * A resource that must be closed when it is no longer needed.
+ * An object that may hold resources (such as file or socket handles)
+ * until it is closed. The {@link #close()} method of an {@code AutoCloseable}
+ * object is called automatically when exiting a {@code
+ * try}-with-resources block for which the object has been declared in
+ * the resource specification header. This construction ensures prompt
+ * release, avoiding resource exhaustion exceptions and errors that
+ * may otherwise occur.
+ *
+ * @apiNote
+ * <p>It is possible, and in fact common, for a base class to
+ * implement AutoCloseable even though not all of its subclasses or
+ * instances will hold releasable resources.  For code that must operate
+ * in complete generality, or when it is known that the {@code AutoCloseable}
+ * instance requires resource release, it is recommended to use {@code
+ * try}-with-resources constructions. However, when using facilities such as
+ * {@link java.util.stream.Stream} that support both I/O-based and
+ * non-I/O-based forms, {@code try}-with-resources blocks are in
+ * general unnecessary when using non-I/O-based forms.
  *
  * @author Josh Bloch
  * @since 1.7
--- a/src/share/classes/java/lang/Class.java	Fri Sep 06 12:04:18 2013 -0400
+++ b/src/share/classes/java/lang/Class.java	Fri Sep 06 12:10:30 2013 -0400
@@ -1484,22 +1484,24 @@
     /**
      * Returns an array containing {@code Field} objects reflecting all
      * the accessible public fields of the class or interface represented by
-     * this {@code Class} object.  The elements in the array returned are
-     * not sorted and are not in any particular order.  This method returns an
-     * array of length 0 if the class or interface has no accessible public
-     * fields, or if it represents an array class, a primitive type, or void.
+     * this {@code Class} object.
      *
-     * <p> Specifically, if this {@code Class} object represents a class,
-     * this method returns the public fields of this class and of all its
-     * superclasses.  If this {@code Class} object represents an
-     * interface, this method returns the fields of this interface and of all
-     * its superinterfaces.
+     * <p> If this {@code Class} object represents a class or interface with no
+     * no accessible public fields, then this method returns an array of length
+     * 0.
      *
-     * <p> The implicit length field for array class is not reflected by this
-     * method. User code should use the methods of class {@code Array} to
-     * manipulate arrays.
+     * <p> If this {@code Class} object represents a class, then this method
+     * returns the public fields of the class and of all its superclasses.
      *
-     * <p> See <em>The Java Language Specification</em>, sections 8.2 and 8.3.
+     * <p> If this {@code Class} object represents an interface, then this
+     * method returns the fields of the interface and of all its
+     * superinterfaces.
+     *
+     * <p> If this {@code Class} object represents an array type, a primitive
+     * type, or void, then this method returns an array of length 0.
+     *
+     * <p> The elements in the array returned are not sorted and are not in any
+     * particular order.
      *
      * @return the array of {@code Field} objects representing the
      *         public fields
@@ -1512,6 +1514,8 @@
      *         of this class.
      *
      * @since JDK1.1
+     * @jls 8.2 Class Members
+     * @jls 8.3 Field Declarations
      */
     @CallerSensitive
     public Field[] getFields() throws SecurityException {
@@ -1595,13 +1599,14 @@
 
 
     /**
-     * Returns a {@code Field} object that reflects the specified public
-     * member field of the class or interface represented by this
-     * {@code Class} object. The {@code name} parameter is a
-     * {@code String} specifying the simple name of the desired field.
+     * Returns a {@code Field} object that reflects the specified public member
+     * field of the class or interface represented by this {@code Class}
+     * object. The {@code name} parameter is a {@code String} specifying the
+     * simple name of the desired field.
      *
      * <p> The field to be reflected is determined by the algorithm that
-     * follows.  Let C be the class represented by this object:
+     * follows.  Let C be the class or interface represented by this object:
+     *
      * <OL>
      * <LI> If C declares a public field with the name specified, that is the
      *      field to be reflected.</LI>
@@ -1614,7 +1619,8 @@
      *      is thrown.</LI>
      * </OL>
      *
-     * <p> See <em>The Java Language Specification</em>, sections 8.2 and 8.3.
+     * <p> If this {@code Class} object represents an array type, then this
+     * method does not find the {@code length} field of the array type.
      *
      * @param name the field name
      * @return the {@code Field} object of this class specified by
@@ -1631,6 +1637,8 @@
      *         of this class.
      *
      * @since JDK1.1
+     * @jls 8.2 Class Members
+     * @jls 8.3 Field Declarations
      */
     @CallerSensitive
     public Field getField(String name)
@@ -1800,12 +1808,15 @@
      * declared by the class or interface represented by this
      * {@code Class} object. This includes public, protected, default
      * (package) access, and private fields, but excludes inherited fields.
-     * The elements in the array returned are not sorted and are not in any
-     * particular order.  This method returns an array of length 0 if the class
-     * or interface declares no fields, or if this {@code Class} object
-     * represents a primitive type, an array class, or void.
      *
-     * <p> See <em>The Java Language Specification</em>, sections 8.2 and 8.3.
+     * <p> If this {@code Class} object represents a class or interface with no
+     * declared fields, then this method returns an array of length 0.
+     *
+     * <p> If this {@code Class} object represents an array type, a primitive
+     * type, or void, then this method returns an array of length 0.
+     *
+     * <p> The elements in the array returned are not sorted and are not in any
+     * particular order.
      *
      * @return  the array of {@code Field} objects representing all the
      *          declared fields of this class
@@ -1831,6 +1842,8 @@
      *          </ul>
      *
      * @since JDK1.1
+     * @jls 8.2 Class Members
+     * @jls 8.3 Field Declarations
      */
     @CallerSensitive
     public Field[] getDeclaredFields() throws SecurityException {
@@ -1935,9 +1948,11 @@
     /**
      * Returns a {@code Field} object that reflects the specified declared
      * field of the class or interface represented by this {@code Class}
-     * object. The {@code name} parameter is a {@code String} that
-     * specifies the simple name of the desired field.  Note that this method
-     * will not reflect the {@code length} field of an array class.
+     * object. The {@code name} parameter is a {@code String} that specifies
+     * the simple name of the desired field.
+     *
+     * <p> If this {@code Class} object represents an array type, then this
+     * method does not find the {@code length} field of the array type.
      *
      * @param name the name of the field
      * @return  the {@code Field} object for the specified field in this
@@ -1967,6 +1982,8 @@
      *          </ul>
      *
      * @since JDK1.1
+     * @jls 8.2 Class Members
+     * @jls 8.3 Field Declarations
      */
     @CallerSensitive
     public Field getDeclaredField(String name)
--- a/src/share/classes/java/lang/SecurityManager.java	Fri Sep 06 12:04:18 2013 -0400
+++ b/src/share/classes/java/lang/SecurityManager.java	Fri Sep 06 12:10:30 2013 -0400
@@ -1336,9 +1336,16 @@
      *             top-level windows; <code>false</code> otherwise.
      * @exception  NullPointerException if the <code>window</code> argument is
      *             <code>null</code>.
+     * @deprecated The dependency on {@code AWTPermission} creates an
+     *             impediment to future modularization of the Java platform.
+     *             Users of this method should instead invoke
+     *             {@link #checkPermission} directly.
+     *             This method will be changed in a future release to check
+     *             the permission {@code java.security.AllPermission}.
      * @see        java.awt.Window
      * @see        #checkPermission(java.security.Permission) checkPermission
      */
+    @Deprecated
     public boolean checkTopLevelWindow(Object window) {
         if (window == null) {
             throw new NullPointerException("window can't be null");
@@ -1398,8 +1405,15 @@
      * @since   JDK1.1
      * @exception  SecurityException  if the calling thread does not have
      *             permission to access the system clipboard.
+     * @deprecated The dependency on {@code AWTPermission} creates an
+     *             impediment to future modularization of the Java platform.
+     *             Users of this method should instead invoke
+     *             {@link #checkPermission} directly.
+     *             This method will be changed in a future release to check
+     *             the permission {@code java.security.AllPermission}.
      * @see        #checkPermission(java.security.Permission) checkPermission
      */
+    @Deprecated
     public void checkSystemClipboardAccess() {
         Permission perm = SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION;
         if (perm == null) {
@@ -1427,8 +1441,15 @@
      * @since   JDK1.1
      * @exception  SecurityException  if the calling thread does not have
      *             permission to access the AWT event queue.
+     * @deprecated The dependency on {@code AWTPermission} creates an
+     *             impediment to future modularization of the Java platform.
+     *             Users of this method should instead invoke
+     *             {@link #checkPermission} directly.
+     *             This method will be changed in a future release to check
+     *             the permission {@code java.security.AllPermission}.
      * @see        #checkPermission(java.security.Permission) checkPermission
      */
+    @Deprecated
     public void checkAwtEventQueueAccess() {
         Permission perm = SecurityConstants.AWT.CHECK_AWT_EVENTQUEUE_PERMISSION;
         if (perm == null) {
--- a/src/share/classes/java/lang/String.java	Fri Sep 06 12:04:18 2013 -0400
+++ b/src/share/classes/java/lang/String.java	Fri Sep 06 12:10:30 2013 -0400
@@ -2457,8 +2457,8 @@
      *     String message = String.join(" ", strings);
      *     //message returned is: "Java is cool"
      *
-     *     Set<String> strings = new HashSet<>();
-     *     Strings.add("Java"); strings.add("is");
+     *     Set<String> strings = new LinkedHashSet<>();
+     *     strings.add("Java"); strings.add("is");
      *     strings.add("very"); strings.add("cool");
      *     String message = String.join("-", strings);
      *     //message returned is: "Java-is-very-cool"
@@ -2652,7 +2652,7 @@
      * returns {@code "t\u005Cu0131tle"}, where '\u005Cu0131' is the
      * LATIN SMALL LETTER DOTLESS I character.
      * To obtain correct results for locale insensitive strings, use
-     * {@code toLowerCase(Locale.ENGLISH)}.
+     * {@code toLowerCase(Locale.ROOT)}.
      * <p>
      * @return  the {@code String}, converted to lowercase.
      * @see     java.lang.String#toLowerCase(Locale)
@@ -2815,7 +2815,7 @@
      * returns {@code "T\u005Cu0130TLE"}, where '\u005Cu0130' is the
      * LATIN CAPITAL LETTER I WITH DOT ABOVE character.
      * To obtain correct results for locale insensitive strings, use
-     * {@code toUpperCase(Locale.ENGLISH)}.
+     * {@code toUpperCase(Locale.ROOT)}.
      * <p>
      * @return  the {@code String}, converted to uppercase.
      * @see     java.lang.String#toUpperCase(Locale)
--- a/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java	Fri Sep 06 12:04:18 2013 -0400
+++ b/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java	Fri Sep 06 12:10:30 2013 -0400
@@ -124,7 +124,7 @@
         this.samMethodType  = samMethodType;
 
         this.implMethod = implMethod;
-        this.implInfo = new MethodHandleInfo(implMethod);
+        this.implInfo = caller.revealDirect(implMethod);
         // @@@ Temporary work-around pending resolution of 8005119
         this.implKind = (implInfo.getReferenceKind() == MethodHandleInfo.REF_invokeSpecial)
                         ? MethodHandleInfo.REF_invokeVirtual
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/lang/invoke/InfoFromMemberName.java	Fri Sep 06 12:10:30 2013 -0400
@@ -0,0 +1,145 @@
+/*
+ * 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.lang.invoke;
+
+import java.security.*;
+import java.lang.reflect.*;
+import java.lang.invoke.MethodHandleNatives.Constants;
+import java.lang.invoke.MethodHandles.Lookup;
+import static java.lang.invoke.MethodHandleStatics.*;
+
+/*
+ * Auxiliary to MethodHandleInfo, wants to nest in MethodHandleInfo but must be non-public.
+ */
+/*non-public*/
+final
+class InfoFromMemberName implements MethodHandleInfo {
+    private final MemberName member;
+    private final int referenceKind;
+
+    InfoFromMemberName(Lookup lookup, MemberName member, byte referenceKind) {
+        assert(member.isResolved() || member.isMethodHandleInvoke());
+        assert(member.referenceKindIsConsistentWith(referenceKind));
+        this.member = member;
+        this.referenceKind = referenceKind;
+    }
+
+    @Override
+    public Class<?> getDeclaringClass() {
+        return member.getDeclaringClass();
+    }
+
+    @Override
+    public String getName() {
+        return member.getName();
+    }
+
+    @Override
+    public MethodType getMethodType() {
+        return member.getMethodOrFieldType();
+    }
+
+    @Override
+    public int getModifiers() {
+        return member.getModifiers();
+    }
+
+    @Override
+    public int getReferenceKind() {
+        return referenceKind;
+    }
+
+    @Override
+    public String toString() {
+        return MethodHandleInfo.toString(getReferenceKind(), getDeclaringClass(), getName(), getMethodType());
+    }
+
+    @Override
+    public <T extends Member> T reflectAs(Class<T> expected, Lookup lookup) {
+        if (member.isMethodHandleInvoke() && !member.isVarargs()) {
+            // This member is an instance of a signature-polymorphic method, which cannot be reflected
+            // A method handle invoker can come in either of two forms:
+            // A generic placeholder (present in the source code, and varargs)
+            // and a signature-polymorphic instance (synthetic and not varargs).
+            // For more information see comments on {@link MethodHandleNatives#linkMethod}.
+            throw new IllegalArgumentException("cannot reflect signature polymorphic method");
+        }
+        Member mem = AccessController.doPrivileged(new PrivilegedAction<Member>() {
+                public Member run() {
+                    try {
+                        return reflectUnchecked();
+                    } catch (ReflectiveOperationException ex) {
+                        throw new IllegalArgumentException(ex);
+                    }
+                }
+            });
+        try {
+            Class<?> defc = getDeclaringClass();
+            byte refKind = (byte) getReferenceKind();
+            lookup.checkAccess(refKind, defc, convertToMemberName(refKind, mem));
+        } catch (IllegalAccessException ex) {
+            throw new IllegalArgumentException(ex);
+        }
+        return expected.cast(mem);
+    }
+
+    private Member reflectUnchecked() throws ReflectiveOperationException {
+        byte refKind = (byte) getReferenceKind();
+        Class<?> defc = getDeclaringClass();
+        boolean isPublic = Modifier.isPublic(getModifiers());
+        if (MethodHandleNatives.refKindIsMethod(refKind)) {
+            if (isPublic)
+                return defc.getMethod(getName(), getMethodType().parameterArray());
+            else
+                return defc.getDeclaredMethod(getName(), getMethodType().parameterArray());
+        } else if (MethodHandleNatives.refKindIsConstructor(refKind)) {
+            if (isPublic)
+                return defc.getConstructor(getMethodType().parameterArray());
+            else
+                return defc.getDeclaredConstructor(getMethodType().parameterArray());
+        } else if (MethodHandleNatives.refKindIsField(refKind)) {
+            if (isPublic)
+                return defc.getField(getName());
+            else
+                return defc.getDeclaredField(getName());
+        } else {
+            throw new IllegalArgumentException("referenceKind="+refKind);
+        }
+    }
+
+    private static MemberName convertToMemberName(byte refKind, Member mem) throws IllegalAccessException {
+        if (mem instanceof Method) {
+            boolean wantSpecial = (refKind == REF_invokeSpecial);
+            return new MemberName((Method) mem, wantSpecial);
+        } else if (mem instanceof Constructor) {
+            return new MemberName((Constructor) mem);
+        } else if (mem instanceof Field) {
+            boolean isSetter = (refKind == REF_putField || refKind == REF_putStatic);
+            return new MemberName((Field) mem, isSetter);
+        }
+        throw new InternalError(mem.getClass().getName());
+    }
+}
--- a/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java	Fri Sep 06 12:04:18 2013 -0400
+++ b/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java	Fri Sep 06 12:10:30 2013 -0400
@@ -612,6 +612,12 @@
             return false;  // inner class of some sort
         if (cls.getClassLoader() != MethodHandle.class.getClassLoader())
             return false;  // not on BCP
+        MethodType mtype = member.getMethodOrFieldType();
+        if (!isStaticallyNameable(mtype.returnType()))
+            return false;
+        for (Class<?> ptype : mtype.parameterArray())
+            if (!isStaticallyNameable(ptype))
+                return false;
         if (!member.isPrivate() && VerifyAccess.isSamePackage(MethodHandle.class, cls))
             return true;   // in java.lang.invoke package
         if (member.isPublic() && isStaticallyNameable(cls))
--- a/src/share/classes/java/lang/invoke/Invokers.java	Fri Sep 06 12:04:18 2013 -0400
+++ b/src/share/classes/java/lang/invoke/Invokers.java	Fri Sep 06 12:10:30 2013 -0400
@@ -87,6 +87,7 @@
             lform = invokeForm(mtype, true, MethodTypeForm.LF_EX_INVOKER);
             invoker = SimpleMethodHandle.make(invokerType, lform);
         }
+        invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke("invokeExact", mtype));
         assert(checkInvoker(invoker));
         exactInvoker = invoker;
         return invoker;
@@ -110,6 +111,7 @@
             lform = invokeForm(mtype, true, MethodTypeForm.LF_GEN_INVOKER);
             invoker = SimpleMethodHandle.make(invokerType, lform);
         }
+        invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke("invoke", mtype));
         assert(checkInvoker(invoker));
         generalInvoker = invoker;
         return invoker;
--- a/src/share/classes/java/lang/invoke/MemberName.java	Fri Sep 06 12:04:18 2013 -0400
+++ b/src/share/classes/java/lang/invoke/MemberName.java	Fri Sep 06 12:10:30 2013 -0400
@@ -320,14 +320,18 @@
 
     /** Utility method to query if this member is a method handle invocation (invoke or invokeExact). */
     public boolean isMethodHandleInvoke() {
-        final int bits = Modifier.NATIVE | Modifier.FINAL;
+        final int bits = MH_INVOKE_MODS;
         final int negs = Modifier.STATIC;
         if (testFlags(bits | negs, bits) &&
             clazz == MethodHandle.class) {
-            return name.equals("invoke") || name.equals("invokeExact");
+            return isMethodHandleInvokeName(name);
         }
         return false;
     }
+    public static boolean isMethodHandleInvokeName(String name) {
+        return name.equals("invoke") || name.equals("invokeExact");
+    }
+    private static final int MH_INVOKE_MODS = Modifier.NATIVE | Modifier.FINAL | Modifier.PUBLIC;
 
     /** Utility method to query the modifier flags of this member. */
     public boolean isStatic() {
@@ -482,12 +486,27 @@
         m.getClass();  // NPE check
         // fill in vmtarget, vmindex while we have m in hand:
         MethodHandleNatives.init(this, m);
+        if (clazz == null) {  // MHN.init failed
+            if (m.getDeclaringClass() == MethodHandle.class &&
+                isMethodHandleInvokeName(m.getName())) {
+                // The JVM did not reify this signature-polymorphic instance.
+                // Need a special case here.
+                // See comments on MethodHandleNatives.linkMethod.
+                MethodType type = MethodType.methodType(m.getReturnType(), m.getParameterTypes());
+                int flags = flagsMods(IS_METHOD, m.getModifiers(), REF_invokeVirtual);
+                init(MethodHandle.class, m.getName(), type, flags);
+                if (isMethodHandleInvoke())
+                    return;
+            }
+            throw new LinkageError(m.toString());
+        }
         assert(isResolved() && this.clazz != null);
         this.name = m.getName();
         if (this.type == null)
             this.type = new Object[] { m.getReturnType(), m.getParameterTypes() };
         if (wantSpecial) {
-            assert(!isAbstract()) : this;
+            if (isAbstract())
+                throw new AbstractMethodError(this.toString());
             if (getReferenceKind() == REF_invokeVirtual)
                 changeReferenceKind(REF_invokeSpecial, REF_invokeVirtual);
             else if (getReferenceKind() == REF_invokeInterface)
@@ -562,6 +581,22 @@
         initResolved(true);
     }
 
+    /**
+     * Create a name for a signature-polymorphic invoker.
+     * This is a placeholder for a signature-polymorphic instance
+     * (of MH.invokeExact, etc.) that the JVM does not reify.
+     * See comments on {@link MethodHandleNatives#linkMethod}.
+     */
+    static MemberName makeMethodHandleInvoke(String name, MethodType type) {
+        return makeMethodHandleInvoke(name, type, MH_INVOKE_MODS | SYNTHETIC);
+    }
+    static MemberName makeMethodHandleInvoke(String name, MethodType type, int mods) {
+        MemberName mem = new MemberName(MethodHandle.class, name, type, REF_invokeVirtual);
+        mem.flags |= mods;  // it's not resolved, but add these modifiers anyway
+        assert(mem.isMethodHandleInvoke()) : mem;
+        return mem;
+    }
+
     // bare-bones constructor; the JVM will fill it in
     MemberName() { }
 
--- a/src/share/classes/java/lang/invoke/MethodHandle.java	Fri Sep 06 12:04:18 2013 -0400
+++ b/src/share/classes/java/lang/invoke/MethodHandle.java	Fri Sep 06 12:10:30 2013 -0400
@@ -1285,6 +1285,21 @@
     }
 
     /*non-public*/
+    MethodHandle withInternalMemberName(MemberName member) {
+        if (member != null) {
+            return MethodHandleImpl.makeWrappedMember(this, member);
+        } else if (internalMemberName() == null) {
+            // The required internaMemberName is null, and this MH (like most) doesn't have one.
+            return this;
+        } else {
+            // The following case is rare. Mask the internalMemberName by wrapping the MH in a BMH.
+            MethodHandle result = rebind();
+            assert (result.internalMemberName() == null);
+            return result;
+        }
+    }
+
+    /*non-public*/
     boolean isInvokeSpecial() {
         return false;  // DMH.Special returns true
     }
@@ -1356,7 +1371,7 @@
     MethodHandle rebind() {
         // Bind 'this' into a new invoker, of the known class BMH.
         MethodType type2 = type();
-        LambdaForm form2 = reinvokerForm(type2.basicType());
+        LambdaForm form2 = reinvokerForm(this);
         // form2 = lambda (bmh, arg*) { thismh = bmh[0]; invokeBasic(thismh, arg*) }
         return BoundMethodHandle.bindSingle(type2, form2, this);
     }
@@ -1369,23 +1384,38 @@
     /** Create a LF which simply reinvokes a target of the given basic type.
      *  The target MH must override {@link #reinvokerTarget} to provide the target.
      */
-    static LambdaForm reinvokerForm(MethodType mtype) {
-        mtype = mtype.basicType();
+    static LambdaForm reinvokerForm(MethodHandle target) {
+        MethodType mtype = target.type().basicType();
         LambdaForm reinvoker = mtype.form().cachedLambdaForm(MethodTypeForm.LF_REINVOKE);
         if (reinvoker != null)  return reinvoker;
-        MethodHandle MH_invokeBasic = MethodHandles.basicInvoker(mtype);
+        if (mtype.parameterSlotCount() >= MethodType.MAX_MH_ARITY)
+            return makeReinvokerForm(target.type(), target);  // cannot cache this
+        reinvoker = makeReinvokerForm(mtype, null);
+        return mtype.form().setCachedLambdaForm(MethodTypeForm.LF_REINVOKE, reinvoker);
+    }
+    private static LambdaForm makeReinvokerForm(MethodType mtype, MethodHandle customTargetOrNull) {
+        boolean customized = (customTargetOrNull != null);
+        MethodHandle MH_invokeBasic = customized ? null : MethodHandles.basicInvoker(mtype);
         final int THIS_BMH    = 0;
         final int ARG_BASE    = 1;
         final int ARG_LIMIT   = ARG_BASE + mtype.parameterCount();
         int nameCursor = ARG_LIMIT;
-        final int NEXT_MH     = nameCursor++;
+        final int NEXT_MH     = customized ? -1 : nameCursor++;
         final int REINVOKE    = nameCursor++;
         LambdaForm.Name[] names = LambdaForm.arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
-        names[NEXT_MH] = new LambdaForm.Name(NF_reinvokerTarget, names[THIS_BMH]);
-        Object[] targetArgs = Arrays.copyOfRange(names, THIS_BMH, ARG_LIMIT, Object[].class);
-        targetArgs[0] = names[NEXT_MH];  // overwrite this MH with next MH
-        names[REINVOKE] = new LambdaForm.Name(MH_invokeBasic, targetArgs);
-        return mtype.form().setCachedLambdaForm(MethodTypeForm.LF_REINVOKE, new LambdaForm("BMH.reinvoke", ARG_LIMIT, names));
+        Object[] targetArgs;
+        MethodHandle targetMH;
+        if (customized) {
+            targetArgs = Arrays.copyOfRange(names, ARG_BASE, ARG_LIMIT, Object[].class);
+            targetMH = customTargetOrNull;
+        } else {
+            names[NEXT_MH] = new LambdaForm.Name(NF_reinvokerTarget, names[THIS_BMH]);
+            targetArgs = Arrays.copyOfRange(names, THIS_BMH, ARG_LIMIT, Object[].class);
+            targetArgs[0] = names[NEXT_MH];  // overwrite this MH with next MH
+            targetMH = MethodHandles.basicInvoker(mtype);
+        }
+        names[REINVOKE] = new LambdaForm.Name(targetMH, targetArgs);
+        return new LambdaForm("BMH.reinvoke", ARG_LIMIT, names);
     }
 
     private static final LambdaForm.NamedFunction NF_reinvokerTarget;
--- a/src/share/classes/java/lang/invoke/MethodHandleImpl.java	Fri Sep 06 12:04:18 2013 -0400
+++ b/src/share/classes/java/lang/invoke/MethodHandleImpl.java	Fri Sep 06 12:10:30 2013 -0400
@@ -317,7 +317,7 @@
         private MethodHandle cache;
 
         AsVarargsCollector(MethodHandle target, MethodType type, Class<?> arrayType) {
-            super(type, reinvokerForm(type));
+            super(type, reinvokerForm(target));
             this.target = target;
             this.arrayType = arrayType;
             this.cache = target.asCollector(arrayType, 0);
@@ -778,16 +778,27 @@
     }
     static <T extends Throwable> Empty throwException(T t) throws T { throw t; }
 
-    static MethodHandle FAKE_METHOD_HANDLE_INVOKE;
-    static
-    MethodHandle fakeMethodHandleInvoke(MemberName method) {
-        MethodType type = method.getInvocationType();
-        assert(type.equals(MethodType.methodType(Object.class, Object[].class)));
-        MethodHandle mh = FAKE_METHOD_HANDLE_INVOKE;
+    static MethodHandle[] FAKE_METHOD_HANDLE_INVOKE = new MethodHandle[2];
+    static MethodHandle fakeMethodHandleInvoke(MemberName method) {
+        int idx;
+        assert(method.isMethodHandleInvoke());
+        switch (method.getName()) {
+        case "invoke":       idx = 0; break;
+        case "invokeExact":  idx = 1; break;
+        default:             throw new InternalError(method.getName());
+        }
+        MethodHandle mh = FAKE_METHOD_HANDLE_INVOKE[idx];
         if (mh != null)  return mh;
-        mh = throwException(type.insertParameterTypes(0, UnsupportedOperationException.class));
+        MethodType type = MethodType.methodType(Object.class, UnsupportedOperationException.class,
+                                                MethodHandle.class, Object[].class);
+        mh = throwException(type);
         mh = mh.bindTo(new UnsupportedOperationException("cannot reflectively invoke MethodHandle"));
-        FAKE_METHOD_HANDLE_INVOKE = mh;
+        if (!method.getInvocationType().equals(mh.type()))
+            throw new InternalError(method.toString());
+        mh = mh.withInternalMemberName(method);
+        mh = mh.asVarargsCollector(Object[].class);
+        assert(method.isVarargs());
+        FAKE_METHOD_HANDLE_INVOKE[idx] = mh;
         return mh;
     }
 
@@ -821,7 +832,7 @@
             MethodHandle vamh = prepareForInvoker(mh);
             // Cache the result of makeInjectedInvoker once per argument class.
             MethodHandle bccInvoker = CV_makeInjectedInvoker.get(hostClass);
-            return restoreToType(bccInvoker.bindTo(vamh), mh.type());
+            return restoreToType(bccInvoker.bindTo(vamh), mh.type(), mh.internalMemberName());
         }
 
         private static MethodHandle makeInjectedInvoker(Class<?> hostClass) {
@@ -876,8 +887,11 @@
         }
 
         // Undo the adapter effect of prepareForInvoker:
-        private static MethodHandle restoreToType(MethodHandle vamh, MethodType type) {
-            return vamh.asCollector(Object[].class, type.parameterCount()).asType(type);
+        private static MethodHandle restoreToType(MethodHandle vamh, MethodType type, MemberName member) {
+            MethodHandle mh = vamh.asCollector(Object[].class, type.parameterCount());
+            mh = mh.asType(type);
+            mh = mh.withInternalMemberName(member);
+            return mh;
         }
 
         private static final MethodHandle MH_checkCallerClass;
@@ -939,4 +953,41 @@
             }
         }
     }
+
+
+    /** This subclass allows a wrapped method handle to be re-associated with an arbitrary member name. */
+    static class WrappedMember extends MethodHandle {
+        private final MethodHandle target;
+        private final MemberName member;
+
+        private WrappedMember(MethodHandle target, MethodType type, MemberName member) {
+            super(type, reinvokerForm(target));
+            this.target = target;
+            this.member = member;
+        }
+
+        @Override
+        MethodHandle reinvokerTarget() {
+            return target;
+        }
+        @Override
+        MemberName internalMemberName() {
+            return member;
+        }
+        @Override
+        boolean isInvokeSpecial() {
+            return target.isInvokeSpecial();
+        }
+        @Override
+        MethodHandle viewAsType(MethodType newType) {
+            return new WrappedMember(target, newType, member);
+        }
+    }
+
+    static MethodHandle makeWrappedMember(MethodHandle target, MemberName member) {
+        if (member.equals(target.internalMemberName()))
+            return target;
+        return new WrappedMember(target, target.type(), member);
+    }
+
 }
--- a/src/share/classes/java/lang/invoke/MethodHandleInfo.java	Fri Sep 06 12:04:18 2013 -0400
+++ b/src/share/classes/java/lang/invoke/MethodHandleInfo.java	Fri Sep 06 12:10:30 2013 -0400
@@ -24,80 +24,246 @@
  */
 
 package java.lang.invoke;
+
+import java.lang.reflect.*;
+import java.util.*;
 import java.lang.invoke.MethodHandleNatives.Constants;
+import java.lang.invoke.MethodHandles.Lookup;
+import static java.lang.invoke.MethodHandleStatics.*;
 
 /**
- * Cracking (reflecting) method handles back into their constituent symbolic parts.
+ * A symbolic reference obtained by cracking a method handle into its consitutent symbolic parts.
+ * To crack a direct method handle, call {@link Lookup#revealDirect Lookup.revealDirect}.
+ * <p>
+ * A <em>direct method handle</em> represents a method, constructor, or field without
+ * any intervening argument bindings or other transformations.
+ * The method, constructor, or field referred to by a direct method handle is called
+ * its <em>underlying member</em>.
+ * Direct method handles may be obtained in any of these ways:
+ * <ul>
+ * <li>By executing an {@code ldc} instruction on a {@code CONSTANT_MethodHandle} constant.
+ *     (See the Java Virtual Machine Specification, sections 4.4.8 and 5.4.3.)
+ * <li>By calling one of the <a href="MethodHandles.Lookup.html#lookups">Lookup Factory Methods</a>,
+ *     such as {@link Lookup#findVirtual Lookup.findVirtual},
+ *     to resolve a symbolic reference into a method handle.
+ *     A symbolic reference consists of a class, name string, and type.
+ * <li>By calling the factory method {@link Lookup#unreflect Lookup.unreflect}
+ *     or {@link Lookup#unreflectSpecial Lookup.unreflectSpecial}
+ *     to convert a {@link Method} into a method handle.
+ * <li>By calling the factory method {@link Lookup#unreflectConstructor Lookup.unreflectConstructor}
+ *     to convert a {@link Constructor} into a method handle.
+ * <li>By calling the factory method {@link Lookup#unreflectGetter Lookup.unreflectGetter}
+ *     or {@link Lookup#unreflectSetter Lookup.unreflectSetter}
+ *     to convert a {@link Field} into a method handle.
+ * </ul>
+ * In all of these cases, it is possible to crack the resulting direct method handle
+ * to recover a symbolic reference for the underlying method, constructor, or field.
+ * Cracking must be done via a {@code Lookup} object equivalent to that which created
+ * the target method handle, or which has enough access permissions to recreate
+ * an equivalent method handle.
  *
+ * <h1><a name="refkinds"></a>Reference kinds</h1>
+ * The <a href="MethodHandles.Lookup.html#lookups">Lookup Factory Methods</a>
+ * correspond to all major use cases for methods, constructors, and fields.
+ * These use cases may be distinguished using small integers as follows:
+ * <table border=1 cellpadding=5 summary="reference kinds">
+ * <tr><th>reference kind</th><th>descriptive name</th><th>scope</th><th>member</th><th>behavior</th></tr>
+ * <tr>
+ *     <td>{@code 1}</td><td>{@code REF_getField}</td><td>{@code class}</td>
+ *     <td>{@code FT f;}</td><td>{@code (T) this.f;}</td>
+ * </tr>
+ * <tr>
+ *     <td>{@code 2}</td><td>{@code REF_getStatic}</td><td>{@code class} or {@code interface}</td>
+ *     <td>{@code static}<br>{@code FT f;}</td><td>{@code (T) C.f;}</td>
+ * </tr>
+ * <tr>
+ *     <td>{@code 3}</td><td>{@code REF_putField}</td><td>{@code class}</td>
+ *     <td>{@code FT f;}</td><td>{@code this.f = x;}</td>
+ * </tr>
+ * <tr>
+ *     <td>{@code 4}</td><td>{@code REF_putStatic}</td><td>{@code class}</td>
+ *     <td>{@code static}<br>{@code FT f;}</td><td>{@code C.f = arg;}</td>
+ * </tr>
+ * <tr>
+ *     <td>{@code 5}</td><td>{@code REF_invokeVirtual}</td><td>{@code class}</td>
+ *     <td>{@code T m(A*);}</td><td>{@code (T) this.m(arg*);}</td>
+ * </tr>
+ * <tr>
+ *     <td>{@code 6}</td><td>{@code REF_invokeStatic}</td><td>{@code class} or {@code interface}</td>
+ *     <td>{@code static}<br>{@code T m(A*);}</td><td>{@code (T) C.m(arg*);}</td>
+ * </tr>
+ * <tr>
+ *     <td>{@code 7}</td><td>{@code REF_invokeSpecial}</td><td>{@code class} or {@code interface}</td>
+ *     <td>{@code T m(A*);}</td><td>{@code (T) super.m(arg*);}</td>
+ * </tr>
+ * <tr>
+ *     <td>{@code 8}</td><td>{@code REF_newInvokeSpecial}</td><td>{@code class}</td>
+ *     <td>{@code C(A*);}</td><td>{@code new C(arg*);}</td>
+ * </tr>
+ * <tr>
+ *     <td>{@code 9}</td><td>{@code REF_invokeInterface}</td><td>{@code interface}</td>
+ *     <td>{@code T m(A*);}</td><td>{@code (T) this.m(arg*);}</td>
+ * </tr>
+ * </table>
+ * @since 1.8
  */
-final class MethodHandleInfo {
-   public static final int
-       REF_getField                = Constants.REF_getField,
-       REF_getStatic               = Constants.REF_getStatic,
-       REF_putField                = Constants.REF_putField,
-       REF_putStatic               = Constants.REF_putStatic,
-       REF_invokeVirtual           = Constants.REF_invokeVirtual,
-       REF_invokeStatic            = Constants.REF_invokeStatic,
-       REF_invokeSpecial           = Constants.REF_invokeSpecial,
-       REF_newInvokeSpecial        = Constants.REF_newInvokeSpecial,
-       REF_invokeInterface         = Constants.REF_invokeInterface;
+public
+interface MethodHandleInfo {
+    /**
+     * A direct method handle reference kind,
+     * as defined in the <a href="MethodHandleInfo.html#refkinds">table above</a>.
+     */
+    public static final int
+        REF_getField                = Constants.REF_getField,
+        REF_getStatic               = Constants.REF_getStatic,
+        REF_putField                = Constants.REF_putField,
+        REF_putStatic               = Constants.REF_putStatic,
+        REF_invokeVirtual           = Constants.REF_invokeVirtual,
+        REF_invokeStatic            = Constants.REF_invokeStatic,
+        REF_invokeSpecial           = Constants.REF_invokeSpecial,
+        REF_newInvokeSpecial        = Constants.REF_newInvokeSpecial,
+        REF_invokeInterface         = Constants.REF_invokeInterface;
 
-   private final Class<?> declaringClass;
-   private final String name;
-   private final MethodType methodType;
-   private final int referenceKind;
+    /**
+     * Returns the reference kind of the cracked method handle, which in turn
+     * determines whether the method handle's underlying member was a constructor, method, or field.
+     * See the <a href="MethodHandleInfo.html#refkinds">table above</a> for definitions.
+     * @return the integer code for the kind of reference used to access the underlying member
+     */
+    public int getReferenceKind();
 
-   public MethodHandleInfo(MethodHandle mh) {
-       MemberName mn = mh.internalMemberName();
-       if (mn == null)  throw new IllegalArgumentException("not a direct method handle");
-       this.declaringClass = mn.getDeclaringClass();
-       this.name = mn.getName();
-       this.methodType = mn.getMethodOrFieldType();
-       byte refKind = mn.getReferenceKind();
-       if (refKind == REF_invokeSpecial && !mh.isInvokeSpecial())
-           // Devirtualized method invocation is usually formally virtual.
-           refKind = REF_invokeVirtual;
-       this.referenceKind = refKind;
-   }
+    /**
+     * Returns the class in which the cracked method handle's underlying member was defined.
+     * @return the declaring class of the underlying member
+     */
+    public Class<?> getDeclaringClass();
 
-   public Class<?> getDeclaringClass() {
-       return declaringClass;
-   }
+    /**
+     * Returns the name of the cracked method handle's underlying member.
+     * This is {@code "&lt;init&gt;"} if the underlying member was a constructor,
+     * else it is a simple method name or field name.
+     * @return the simple name of the underlying member
+     */
+    public String getName();
 
-   public String getName() {
-       return name;
-   }
+    /**
+     * Returns the nominal type of the cracked symbolic reference, expressed as a method type.
+     * If the reference is to a constructor, the return type will be {@code void}.
+     * If it is to a non-static method, the method type will not mention the {@code this} parameter.
+     * If it is to a field and the requested access is to read the field,
+     * the method type will have no parameters and return the field type.
+     * If it is to a field and the requested access is to write the field,
+     * the method type will have one parameter of the field type and return {@code void}.
+     * <p>
+     * Note that original direct method handle may include a leading {@code this} parameter,
+     * or (in the case of a constructor) will replace the {@code void} return type
+     * with the constructed class.
+     * The nominal type does not include any {@code this} parameter,
+     * and (in the case of a constructor) will return {@code void}.
+     * @return the type of the underlying member, expressed as a method type
+     */
+    public MethodType getMethodType();
 
-   public MethodType getMethodType() {
-       return methodType;
-   }
+    // Utility methods.
+    // NOTE: class/name/type and reference kind constitute a symbolic reference
+    // member and modifiers are an add-on, derived from Core Reflection (or the equivalent)
 
-   public int getModifiers() {
-       return -1; //TODO
-   }
+    /**
+     * Reflects the underlying member as a method, constructor, or field object.
+     * If the underlying member is public, it is reflected as if by
+     * {@code getMethod}, {@code getConstructor}, or {@code getField}.
+     * Otherwise, it is reflected as if by
+     * {@code getDeclaredMethod}, {@code getDeclaredConstructor}, or {@code getDeclaredField}.
+     * The underlying member must be accessible to the given lookup object.
+     * @param <T> the desired type of the result, either {@link Member} or a subtype
+     * @param expected a class object representing the desired result type {@code T}
+     * @param lookup the lookup object that created this MethodHandleInfo, or one with equivalent access privileges
+     * @return a reference to the method, constructor, or field object
+     * @exception ClassCastException if the member is not of the expected type
+     * @exception NullPointerException if either argument is {@code null}
+     * @exception IllegalArgumentException if the underlying member is not accessible to the given lookup object
+     */
+    public <T extends Member> T reflectAs(Class<T> expected, Lookup lookup);
 
-   public int getReferenceKind() {
-       return referenceKind;
-   }
+    /**
+     * Returns the access modifiers of the underlying member.
+     * @return the Java language modifiers for underlying member,
+     *         or -1 if the member cannot be accessed
+     * @see Modifier
+     * @see reflectAs
+     */
+    public int getModifiers();
 
-   static String getReferenceKindString(int referenceKind) {
-        switch (referenceKind) {
-            case REF_getField: return "getfield";
-            case REF_getStatic: return "getstatic";
-            case REF_putField: return "putfield";
-            case REF_putStatic: return "putstatic";
-            case REF_invokeVirtual: return "invokevirtual";
-            case REF_invokeStatic: return "invokestatic";
-            case REF_invokeSpecial: return "invokespecial";
-            case REF_newInvokeSpecial: return "newinvokespecial";
-            case REF_invokeInterface: return "invokeinterface";
-            default: return "UNKNOWN_REFENCE_KIND" + "[" + referenceKind + "]";
-        }
+    /**
+     * Determines if the underlying member was a variable arity method or constructor.
+     * Such members are represented by method handles that are varargs collectors.
+     * @implSpec
+     * This produces a result equivalent to:
+     * <pre>{@code
+     *     getReferenceKind() >= REF_invokeVirtual && Modifier.isTransient(getModifiers())
+     * }</pre>
+     *
+     *
+     * @return {@code true} if and only if the underlying member was declared with variable arity.
+     */
+    // spelling derived from java.lang.reflect.Executable, not MethodHandle.isVarargsCollector
+    public default boolean isVarArgs()  {
+        // fields are never varargs:
+        if (MethodHandleNatives.refKindIsField((byte) getReferenceKind()))
+            return false;
+        // not in the public API: Modifier.VARARGS
+        final int ACC_VARARGS = 0x00000080;  // from JVMS 4.6 (Table 4.20)
+        assert(ACC_VARARGS == Modifier.TRANSIENT);
+        return Modifier.isTransient(getModifiers());
     }
 
-    @Override
-    public String toString() {
-        return String.format("%s %s.%s:%s", getReferenceKindString(referenceKind),
-                             declaringClass.getName(), name, methodType);
+    /**
+     * Returns the descriptive name of the given reference kind,
+     * as defined in the <a href="MethodHandleInfo.html#refkinds">table above</a>.
+     * The conventional prefix "REF_" is omitted.
+     * @param referenceKind an integer code for a kind of reference used to access a class member
+     * @return a mixed-case string such as {@code "getField"}
+     * @exception IllegalArgumentException if the argument is not a valid
+     *            <a href="MethodHandleInfo.html#refkinds">reference kind number</a>
+     */
+    public static String referenceKindToString(int referenceKind) {
+        if (!MethodHandleNatives.refKindIsValid(referenceKind))
+            throw newIllegalArgumentException("invalid reference kind", referenceKind);
+        return MethodHandleNatives.refKindName((byte)referenceKind);
+    }
+
+    /**
+     * Returns a string representation for a {@code MethodHandleInfo},
+     * given the four parts of its symbolic reference.
+     * This is defined to be of the form {@code "RK C.N:MT"}, where {@code RK} is the
+     * {@linkplain #referenceKindToString reference kind string} for {@code kind},
+     * {@code C} is the {@linkplain java.lang.Class#getName name} of {@code defc}
+     * {@code N} is the {@code name}, and
+     * {@code MT} is the {@code type}.
+     * These four values may be obtained from the
+     * {@linkplain #getReferenceKind reference kind},
+     * {@linkplain #getDeclaringClass declaring class},
+     * {@linkplain #getName member name},
+     * and {@linkplain #getMethodType method type}
+     * of a {@code MethodHandleInfo} object.
+     *
+     * @implSpec
+     * This produces a result equivalent to:
+     * <pre>{@code
+     *     String.format("%s %s.%s:%s", referenceKindToString(kind), defc.getName(), name, type)
+     * }</pre>
+     *
+     * @param kind the {@linkplain #getReferenceKind reference kind} part of the symbolic reference
+     * @param defc the {@linkplain #getDeclaringClass declaring class} part of the symbolic reference
+     * @param name the {@linkplain #getName member name} part of the symbolic reference
+     * @param type the {@linkplain #getMethodType method type} part of the symbolic reference
+     * @return a string of the form {@code "RK C.N:MT"}
+     * @exception IllegalArgumentException if the first argument is not a valid
+     *            <a href="MethodHandleInfo.html#refkinds">reference kind number</a>
+     * @exception NullPointerException if any reference argument is {@code null}
+     */
+    public static String toString(int kind, Class<?> defc, String name, MethodType type) {
+        Objects.requireNonNull(name); Objects.requireNonNull(type);
+        return String.format("%s %s.%s:%s", referenceKindToString(kind), defc.getName(), name, type);
     }
 }
--- a/src/share/classes/java/lang/invoke/MethodHandleNatives.java	Fri Sep 06 12:04:18 2013 -0400
+++ b/src/share/classes/java/lang/invoke/MethodHandleNatives.java	Fri Sep 06 12:10:30 2013 -0400
@@ -205,6 +205,9 @@
     static boolean refKindIsMethod(byte refKind) {
         return !refKindIsField(refKind) && (refKind != REF_newInvokeSpecial);
     }
+    static boolean refKindIsConstructor(byte refKind) {
+        return (refKind == REF_newInvokeSpecial);
+    }
     static boolean refKindHasReceiver(byte refKind) {
         assert(refKindIsValid(refKind));
         return (refKind & 1) != 0;
@@ -313,7 +316,65 @@
      * The method assumes the following arguments on the stack:
      * 0: the method handle being invoked
      * 1-N: the arguments to the method handle invocation
-     * N+1: an implicitly added type argument (the given MethodType)
+     * N+1: an optional, implicitly added argument (typically the given MethodType)
+     * <p>
+     * The nominal method at such a call site is an instance of
+     * a signature-polymorphic method (see @PolymorphicSignature).
+     * Such method instances are user-visible entities which are
+     * "split" from the generic placeholder method in {@code MethodHandle}.
+     * (Note that the placeholder method is not identical with any of
+     * its instances.  If invoked reflectively, is guaranteed to throw an
+     * {@code UnsupportedOperationException}.)
+     * If the signature-polymorphic method instance is ever reified,
+     * it appears as a "copy" of the original placeholder
+     * (a native final member of {@code MethodHandle}) except
+     * that its type descriptor has shape required by the instance,
+     * and the method instance is <em>not</em> varargs.
+     * The method instance is also marked synthetic, since the
+     * method (by definition) does not appear in Java source code.
+     * <p>
+     * The JVM is allowed to reify this method as instance metadata.
+     * For example, {@code invokeBasic} is always reified.
+     * But the JVM may instead call {@code linkMethod}.
+     * If the result is an * ordered pair of a {@code (method, appendix)},
+     * the method gets all the arguments (0..N inclusive)
+     * plus the appendix (N+1), and uses the appendix to complete the call.
+     * In this way, one reusable method (called a "linker method")
+     * can perform the function of any number of polymorphic instance
+     * methods.
+     * <p>
+     * Linker methods are allowed to be weakly typed, with any or
+     * all references rewritten to {@code Object} and any primitives
+     * (except {@code long}/{@code float}/{@code double})
+     * rewritten to {@code int}.
+     * A linker method is trusted to return a strongly typed result,
+     * according to the specific method type descriptor of the
+     * signature-polymorphic instance it is emulating.
+     * This can involve (as necessary) a dynamic check using
+     * data extracted from the appendix argument.
+     * <p>
+     * The JVM does not inspect the appendix, other than to pass
+     * it verbatim to the linker method at every call.
+     * This means that the JDK runtime has wide latitude
+     * for choosing the shape of each linker method and its
+     * corresponding appendix.
+     * Linker methods should be generated from {@code LambdaForm}s
+     * so that they do not become visible on stack traces.
+     * <p>
+     * The {@code linkMethod} call is free to omit the appendix
+     * (returning null) and instead emulate the required function
+     * completely in the linker method.
+     * As a corner case, if N==255, no appendix is possible.
+     * In this case, the method returned must be custom-generated to
+     * to perform any needed type checking.
+     * <p>
+     * If the JVM does not reify a method at a call site, but instead
+     * calls {@code linkMethod}, the corresponding call represented
+     * in the bytecodes may mention a valid method which is not
+     * representable with a {@code MemberName}.
+     * Therefore, use cases for {@code linkMethod} tend to correspond to
+     * special cases in reflective code such as {@code findVirtual}
+     * or {@code revealDirect}.
      */
     static MemberName linkMethod(Class<?> callerClass, int refKind,
                                  Class<?> defc, String name, Object type,
--- a/src/share/classes/java/lang/invoke/MethodHandles.java	Fri Sep 06 12:04:18 2013 -0400
+++ b/src/share/classes/java/lang/invoke/MethodHandles.java	Fri Sep 06 12:10:30 2013 -0400
@@ -26,8 +26,6 @@
 package java.lang.invoke;
 
 import java.lang.reflect.*;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
 import java.util.List;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -54,6 +52,7 @@
  * </ul>
  * <p>
  * @author John Rose, JSR 292 EG
+ * @since 1.7
  */
 public class MethodHandles {
 
@@ -97,6 +96,38 @@
     }
 
     /**
+     * Performs an unchecked "crack" of a direct method handle.
+     * The result is as if the user had obtained a lookup object capable enough
+     * to crack the target method handle, called
+     * {@link java.lang.invoke.MethodHandles.Lookup#revealDirect Lookup.revealDirect}
+     * on the target to obtain its symbolic reference, and then called
+     * {@link java.lang.invoke.MethodHandleInfo#reflectAs MethodHandleInfo.reflectAs}
+     * to resolve the symbolic reference to a member.
+     * <p>
+     * If there is a security manager, its {@code checkPermission} method
+     * is called with a {@code ReflectPermission("suppressAccessChecks")} permission.
+     * @param <T> the desired type of the result, either {@link Member} or a subtype
+     * @param target a direct method handle to crack into symbolic reference components
+     * @param expected a class object representing the desired result type {@code T}
+     * @return a reference to the method, constructor, or field object
+     * @exception SecurityException if the caller is not privileged to call {@code setAccessible}
+     * @exception NullPointerException if either argument is {@code null}
+     * @exception IllegalArgumentException if the target is not a direct method handle
+     * @exception ClassCastException if the member is not of the expected type
+     * @since 1.8
+     */
+    public static <T extends Member> T
+    reflectAs(Class<T> expected, MethodHandle target) {
+        SecurityManager smgr = System.getSecurityManager();
+        if (smgr != null)  smgr.checkPermission(ACCESS_PERMISSION);
+        Lookup lookup = Lookup.IMPL_LOOKUP;  // use maximally privileged lookup
+        return lookup.revealDirect(target).reflectAs(expected, lookup);
+    }
+    // Copied from AccessibleObject, as used by Method.setAccessible, etc.:
+    static final private java.security.Permission ACCESS_PERMISSION =
+        new ReflectPermission("suppressAccessChecks");
+
+    /**
      * A <em>lookup object</em> is a factory for creating method handles,
      * when the creation requires access checking.
      * Method handles do not perform
@@ -647,6 +678,7 @@
                 return invoker(type);
             if ("invokeExact".equals(name))
                 return exactInvoker(type);
+            assert(!MemberName.isMethodHandleInvokeName(name));
             return null;
         }
 
@@ -892,6 +924,10 @@
          * @throws NullPointerException if the argument is null
          */
         public MethodHandle unreflect(Method m) throws IllegalAccessException {
+            if (m.getDeclaringClass() == MethodHandle.class) {
+                MethodHandle mh = unreflectForMH(m);
+                if (mh != null)  return mh;
+            }
             MemberName method = new MemberName(m);
             byte refKind = method.getReferenceKind();
             if (refKind == REF_invokeSpecial)
@@ -900,6 +936,12 @@
             Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this;
             return lookup.getDirectMethod(refKind, method.getDeclaringClass(), method, findBoundCallerClass(method));
         }
+        private MethodHandle unreflectForMH(Method m) {
+            // these names require special lookups because they throw UnsupportedOperationException
+            if (MemberName.isMethodHandleInvokeName(m.getName()))
+                return MethodHandleImpl.fakeMethodHandleInvoke(new MemberName(m));
+            return null;
+        }
 
         /**
          * Produces a method handle for a reflected method.
@@ -1004,6 +1046,46 @@
             return unreflectField(f, true);
         }
 
+        /**
+         * Cracks a direct method handle created by this lookup object or a similar one.
+         * Security and access checks are performed to ensure that this lookup object
+         * is capable of reproducing the target method handle.
+         * This means that the cracking may fail if target is a direct method handle
+         * but was created by an unrelated lookup object.
+         * @param target a direct method handle to crack into symbolic reference components
+         * @return a symbolic reference which can be used to reconstruct this method handle from this lookup object
+         * @exception SecurityException if a security manager is present and it
+         *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+         * @throws IllegalArgumentException if the target is not a direct method handle or if access checking fails
+         * @exception NullPointerException if the target is {@code null}
+         * @since 1.8
+         */
+        public MethodHandleInfo revealDirect(MethodHandle target) {
+            MemberName member = target.internalMemberName();
+            if (member == null || (!member.isResolved() && !member.isMethodHandleInvoke()))
+                throw newIllegalArgumentException("not a direct method handle");
+            Class<?> defc = member.getDeclaringClass();
+            byte refKind = member.getReferenceKind();
+            assert(MethodHandleNatives.refKindIsValid(refKind));
+            if (refKind == REF_invokeSpecial && !target.isInvokeSpecial())
+                // Devirtualized method invocation is usually formally virtual.
+                // To avoid creating extra MemberName objects for this common case,
+                // we encode this extra degree of freedom using MH.isInvokeSpecial.
+                refKind = REF_invokeVirtual;
+            if (refKind == REF_invokeVirtual && defc.isInterface())
+                // Symbolic reference is through interface but resolves to Object method (toString, etc.)
+                refKind = REF_invokeInterface;
+            // Check SM permissions and member access before cracking.
+            try {
+                checkSecurityManager(defc, member);
+                checkAccess(refKind, defc, member);
+            } catch (IllegalAccessException ex) {
+                throw new IllegalArgumentException(ex);
+            }
+            // Produce the handle to the results.
+            return new InfoFromMemberName(this, member, refKind);
+        }
+
         /// Helper methods, all package-private.
 
         MemberName resolveOrFail(byte refKind, Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
@@ -1201,12 +1283,12 @@
         private MethodHandle getDirectMethodCommon(byte refKind, Class<?> refc, MemberName method,
                                                    boolean doRestrict, Class<?> callerClass) throws IllegalAccessException {
             checkMethod(refKind, refc, method);
-            if (method.isMethodHandleInvoke())
-                return fakeMethodHandleInvoke(method);
+            assert(!method.isMethodHandleInvoke());
 
             Class<?> refcAsSuper;
             if (refKind == REF_invokeSpecial &&
                 refc != lookupClass() &&
+                !refc.isInterface() &&
                 refc != (refcAsSuper = lookupClass().getSuperclass()) &&
                 refc.isAssignableFrom(lookupClass())) {
                 assert(!method.getName().equals("<init>"));  // not this code path
@@ -1234,9 +1316,6 @@
                 mh = restrictReceiver(method, mh, lookupClass());
             return mh;
         }
-        private MethodHandle fakeMethodHandleInvoke(MemberName method) {
-            return throwException(method.getReturnType(), UnsupportedOperationException.class);
-        }
         private MethodHandle maybeBindCaller(MemberName method, MethodHandle mh,
                                              Class<?> callerClass)
                                              throws IllegalAccessException {
--- a/src/share/classes/java/lang/invoke/SerializedLambda.java	Fri Sep 06 12:04:18 2013 -0400
+++ b/src/share/classes/java/lang/invoke/SerializedLambda.java	Fri Sep 06 12:10:30 2013 -0400
@@ -225,7 +225,7 @@
 
     @Override
     public String toString() {
-        String implKind=MethodHandleInfo.getReferenceKindString(implMethodKind);
+        String implKind=MethodHandleInfo.referenceKindToString(implMethodKind);
         return String.format("SerializedLambda[%s=%s, %s=%s.%s:%s, " +
                              "%s=%s %s.%s:%s, %s=%s, %s=%d]",
                              "capturingClass", capturingClass,
--- a/src/share/classes/java/net/IDN.java	Fri Sep 06 12:04:18 2013 -0400
+++ b/src/share/classes/java/net/IDN.java	Fri Sep 06 12:10:30 2013 -0400
@@ -292,13 +292,17 @@
         if (useSTD3ASCIIRules) {
             for (int i = 0; i < dest.length(); i++) {
                 int c = dest.charAt(i);
-                if (!isLDHChar(c)) {
-                    throw new IllegalArgumentException("Contains non-LDH characters");
+                if (isNonLDHAsciiCodePoint(c)) {
+                    throw new IllegalArgumentException(
+                        "Contains non-LDH ASCII characters");
                 }
             }
 
-            if (dest.charAt(0) == '-' || dest.charAt(dest.length() - 1) == '-') {
-                throw new IllegalArgumentException("Has leading or trailing hyphen");
+            if (dest.charAt(0) == '-' ||
+                dest.charAt(dest.length() - 1) == '-') {
+
+                throw new IllegalArgumentException(
+                        "Has leading or trailing hyphen");
             }
         }
 
@@ -401,26 +405,20 @@
     //
     // LDH stands for "letter/digit/hyphen", with characters restricted to the
     // 26-letter Latin alphabet <A-Z a-z>, the digits <0-9>, and the hyphen
-    // <->
-    // non-LDH = 0..0x2C, 0x2E..0x2F, 0x3A..0x40, 0x56..0x60, 0x7B..0x7F
+    // <->.
+    // Non LDH refers to characters in the ASCII range, but which are not
+    // letters, digits or the hypen.
     //
-    private static boolean isLDHChar(int ch){
-        // high runner case
-        if(ch > 0x007A){
-            return false;
-        }
-        //['-' '0'..'9' 'A'..'Z' 'a'..'z']
-        if((ch == 0x002D) ||
-           (0x0030 <= ch && ch <= 0x0039) ||
-           (0x0041 <= ch && ch <= 0x005A) ||
-           (0x0061 <= ch && ch <= 0x007A)
-          ){
-            return true;
-        }
-        return false;
+    // non-LDH = 0..0x2C, 0x2E..0x2F, 0x3A..0x40, 0x5B..0x60, 0x7B..0x7F
+    //
+    private static boolean isNonLDHAsciiCodePoint(int ch){
+        return (0x0000 <= ch && ch <= 0x002C) ||
+               (0x002E <= ch && ch <= 0x002F) ||
+               (0x003A <= ch && ch <= 0x0040) ||
+               (0x005B <= ch && ch <= 0x0060) ||
+               (0x007B <= ch && ch <= 0x007F);
     }
 
-
     //
     // search dots in a string and return the index of that character;
     // or if there is no dots, return the length of input string
--- a/src/share/classes/java/nio/file/Files.java	Fri Sep 06 12:04:18 2013 -0400
+++ b/src/share/classes/java/nio/file/Files.java	Fri Sep 06 12:10:30 2013 -0400
@@ -25,34 +25,56 @@
 
 package java.nio.file;
 
-import java.nio.file.attribute.*;
-import java.nio.file.spi.FileSystemProvider;
-import java.nio.file.spi.FileTypeDetector;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.Closeable;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.UncheckedIOException;
+import java.io.Writer;
 import java.nio.channels.Channels;
 import java.nio.channels.FileChannel;
 import java.nio.channels.SeekableByteChannel;
-import java.io.Closeable;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.Reader;
-import java.io.Writer;
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.io.IOException;
-import java.io.UncheckedIOException;
-import java.util.*;
-import java.util.function.BiPredicate;
-import java.util.stream.CloseableStream;
-import java.util.stream.DelegatingStream;
-import java.util.stream.Stream;
-import java.util.stream.StreamSupport;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
 import java.nio.charset.Charset;
 import java.nio.charset.CharsetDecoder;
 import java.nio.charset.CharsetEncoder;
+import java.nio.file.attribute.BasicFileAttributeView;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.nio.file.attribute.DosFileAttributes;
+import java.nio.file.attribute.FileAttribute;
+import java.nio.file.attribute.FileAttributeView;
+import java.nio.file.attribute.FileOwnerAttributeView;
+import java.nio.file.attribute.FileStoreAttributeView;
+import java.nio.file.attribute.FileTime;
+import java.nio.file.attribute.PosixFileAttributeView;
+import java.nio.file.attribute.PosixFileAttributes;
+import java.nio.file.attribute.PosixFilePermission;
+import java.nio.file.attribute.UserPrincipal;
+import java.nio.file.spi.FileSystemProvider;
+import java.nio.file.spi.FileTypeDetector;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.ServiceLoader;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.BiPredicate;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
 
 /**
  * This class consists exclusively of static methods that operate on files,
@@ -74,6 +96,21 @@
         return path.getFileSystem().provider();
     }
 
+    /**
+     * Convert a Closeable to a Runnable by converting checked IOException
+     * to UncheckedIOException
+     */
+    private static Runnable asUncheckedRunnable(Closeable c) {
+        return () -> {
+            try {
+                c.close();
+            }
+            catch (IOException e) {
+                throw new UncheckedIOException(e);
+            }
+        };
+    }
+
     // -- File contents --
 
     /**
@@ -3228,29 +3265,7 @@
     // -- Stream APIs --
 
     /**
-     * Implementation of CloseableStream
-     */
-    private static class DelegatingCloseableStream<T> extends DelegatingStream<T>
-        implements CloseableStream<T>
-    {
-        private final Closeable closeable;
-
-        DelegatingCloseableStream(Closeable c, Stream<T> delegate) {
-            super(delegate);
-            this.closeable = c;
-        }
-
-        public void close() {
-            try {
-                closeable.close();
-            } catch (IOException ex) {
-                throw new UncheckedIOException(ex);
-            }
-        }
-    }
-
-    /**
-     * Return a lazily populated {@code CloseableStream}, the elements of
+     * Return a lazily populated {@code Stream}, the elements of
      * which are the entries in the directory.  The listing is not recursive.
      *
      * <p> The elements of the stream are {@link Path} objects that are
@@ -3264,10 +3279,13 @@
      * reflect updates to the directory that occur after returning from this
      * method.
      *
-     * <p> When not using the try-with-resources construct, then the stream's
-     * {@link CloseableStream#close close} method should be invoked after the
-     * operation is completed so as to free any resources held for the open
-     * directory. Operating on a closed stream behaves as if the end of stream
+     * <p> The returned stream encapsulates a {@link DirectoryStream}.
+     * If timely disposal of file system resources is required, the
+     * {@code try}-with-resources construct should be used to ensure that the
+     * stream's {@link Stream#close close} method is invoked after the stream
+     * operations are completed.
+     *
+     * <p> Operating on a closed stream behaves as if the end of stream
      * has been reached. Due to read-ahead, one or more elements may be
      * returned after the stream has been closed.
      *
@@ -3278,7 +3296,7 @@
      *
      * @param   dir  The path to the directory
      *
-     * @return  The {@code CloseableStream} describing the content of the
+     * @return  The {@code Stream} describing the content of the
      *          directory
      *
      * @throws  NotDirectoryException
@@ -3294,43 +3312,54 @@
      * @see     #newDirectoryStream(Path)
      * @since   1.8
      */
-    public static CloseableStream<Path> list(Path dir) throws IOException {
+    public static Stream<Path> list(Path dir) throws IOException {
         DirectoryStream<Path> ds = Files.newDirectoryStream(dir);
-        final Iterator<Path> delegate = ds.iterator();
+        try {
+            final Iterator<Path> delegate = ds.iterator();
 
-        // Re-wrap DirectoryIteratorException to UncheckedIOException
-        Iterator<Path> it = new Iterator<Path>() {
-            public boolean hasNext() {
+            // Re-wrap DirectoryIteratorException to UncheckedIOException
+            Iterator<Path> it = new Iterator<Path>() {
+                @Override
+                public boolean hasNext() {
+                    try {
+                        return delegate.hasNext();
+                    } catch (DirectoryIteratorException e) {
+                        throw new UncheckedIOException(e.getCause());
+                    }
+                }
+                @Override
+                public Path next() {
+                    try {
+                        return delegate.next();
+                    } catch (DirectoryIteratorException e) {
+                        throw new UncheckedIOException(e.getCause());
+                    }
+                }
+            };
+
+            return StreamSupport.stream(Spliterators.spliteratorUnknownSize(it, Spliterator.DISTINCT), false)
+                                .onClose(asUncheckedRunnable(ds));
+        } catch (Error|RuntimeException e) {
+            try {
+                ds.close();
+            } catch (IOException ex) {
                 try {
-                    return delegate.hasNext();
-                } catch (DirectoryIteratorException e) {
-                    throw new UncheckedIOException(e.getCause());
-                }
+                    e.addSuppressed(ex);
+                } catch (Throwable ignore) {}
             }
-            public Path next() {
-                try {
-                    return delegate.next();
-                } catch (DirectoryIteratorException e) {
-                    throw new UncheckedIOException(e.getCause());
-                }
-            }
-        };
-
-        Stream<Path> s = StreamSupport.stream(
-                Spliterators.spliteratorUnknownSize(it, Spliterator.DISTINCT),
-                false);
-        return new DelegatingCloseableStream<>(ds, s);
+            throw e;
+        }
     }
 
     /**
-     * Return a {@code CloseableStream} that is lazily populated with {@code
+     * Return a {@code Stream} that is lazily populated with {@code
      * Path} by walking the file tree rooted at a given starting file.  The
      * file tree is traversed <em>depth-first</em>, the elements in the stream
      * are {@link Path} objects that are obtained as if by {@link
      * Path#resolve(Path) resolving} the relative path against {@code start}.
      *
      * <p> The {@code stream} walks the file tree as elements are consumed.
-     * The {@code CloseableStream} returned is guaranteed to have at least one
+     * The {@code Stream} returned is guaranteed to have at least one
      * element, the starting file itself. For each file visited, the stream
      * attempts to read its {@link BasicFileAttributes}. If the file is a
      * directory and can be opened successfully, entries in the directory, and
@@ -3370,10 +3399,11 @@
      * <p> When a security manager is installed and it denies access to a file
      * (or directory), then it is ignored and not included in the stream.
      *
-     * <p> When not using the try-with-resources construct, then the stream's
-     * {@link CloseableStream#close close} method should be invoked after the
-     * operation is completed so as to free any resources held for the open
-     * directory. Operate the stream after it is closed will throw an
+     * <p> The returned stream encapsulates one or more {@link DirectoryStream}s.
+     * If timely disposal of file system resources is required, the
+     * {@code try}-with-resources construct should be used to ensure that the
+     * stream's {@link Stream#close close} method is invoked after the stream
+     * operations are completed.  Operating on a closed stream will result in an
      * {@link java.lang.IllegalStateException}.
      *
      * <p> If an {@link IOException} is thrown when accessing the directory
@@ -3388,7 +3418,7 @@
      * @param   options
      *          options to configure the traversal
      *
-     * @return  the {@link CloseableStream} of {@link Path}
+     * @return  the {@link Stream} of {@link Path}
      *
      * @throws  IllegalArgumentException
      *          if the {@code maxDepth} parameter is negative
@@ -3401,21 +3431,22 @@
      *          if an I/O error is thrown when accessing the starting file.
      * @since   1.8
      */
-    public static CloseableStream<Path> walk(Path start, int maxDepth,
-                                             FileVisitOption... options)
-        throws IOException
-    {
+    public static Stream<Path> walk(Path start, int maxDepth,
+                                    FileVisitOption... options)
+            throws IOException {
         FileTreeIterator iterator = new FileTreeIterator(start, maxDepth, options);
-
-        Stream<Path> s = StreamSupport.stream(
-                Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT),
-                false).
-                map(entry -> entry.file());
-        return new DelegatingCloseableStream<>(iterator, s);
+        try {
+            return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT), false)
+                                .onClose(iterator::close)
+                                .map(entry -> entry.file());
+        } catch (Error|RuntimeException e) {
+            iterator.close();
+            throw e;
+        }
     }
 
     /**
-     * Return a {@code CloseableStream} that is lazily populated with {@code
+     * Return a {@code Stream} that is lazily populated with {@code
      * Path} by walking the file tree rooted at a given starting file.  The
      * file tree is traversed <em>depth-first</em>, the elements in the stream
      * are {@link Path} objects that are obtained as if by {@link
@@ -3428,12 +3459,19 @@
      * </pre></blockquote>
      * In other words, it visits all levels of the file tree.
      *
+     * <p> The returned stream encapsulates one or more {@link DirectoryStream}s.
+     * If timely disposal of file system resources is required, the
+     * {@code try}-with-resources construct should be used to ensure that the
+     * stream's {@link Stream#close close} method is invoked after the stream
+     * operations are completed.  Operating on a closed stream will result in an
+     * {@link java.lang.IllegalStateException}.
+     *
      * @param   start
      *          the starting file
      * @param   options
      *          options to configure the traversal
      *
-     * @return  the {@link CloseableStream} of {@link Path}
+     * @return  the {@link Stream} of {@link Path}
      *
      * @throws  SecurityException
      *          If the security manager denies access to the starting file.
@@ -3446,15 +3484,14 @@
      * @see     #walk(Path, int, FileVisitOption...)
      * @since   1.8
      */
-    public static CloseableStream<Path> walk(Path start,
-                                             FileVisitOption... options)
-        throws IOException
-    {
+    public static Stream<Path> walk(Path start,
+                                    FileVisitOption... options)
+            throws IOException {
         return walk(start, Integer.MAX_VALUE, options);
     }
 
     /**
-     * Return a {@code CloseableStream} that is lazily populated with {@code
+     * Return a {@code Stream} that is lazily populated with {@code
      * Path} by searching for files in a file tree rooted at a given starting
      * file.
      *
@@ -3463,12 +3500,19 @@
      * {@link BiPredicate} is invoked with its {@link Path} and {@link
      * BasicFileAttributes}. The {@code Path} object is obtained as if by
      * {@link Path#resolve(Path) resolving} the relative path against {@code
-     * start} and is only included in the returned {@link CloseableStream} if
+     * start} and is only included in the returned {@link Stream} if
      * the {@code BiPredicate} returns true. Compare to calling {@link
      * java.util.stream.Stream#filter filter} on the {@code Stream}
      * returned by {@code walk} method, this method may be more efficient by
      * avoiding redundant retrieval of the {@code BasicFileAttributes}.
      *
+     * <p> The returned stream encapsulates one or more {@link DirectoryStream}s.
+     * If timely disposal of file system resources is required, the
+     * {@code try}-with-resources construct should be used to ensure that the
+     * stream's {@link Stream#close close} method is invoked after the stream
+     * operations are completed.  Operating on a closed stream will result in an
+     * {@link java.lang.IllegalStateException}.
+     *
      * <p> If an {@link IOException} is thrown when accessing the directory
      * after returned from this method, it is wrapped in an {@link
      * UncheckedIOException} which will be thrown from the method that caused
@@ -3484,7 +3528,7 @@
      * @param   options
      *          options to configure the traversal
      *
-     * @return  the {@link CloseableStream} of {@link Path}
+     * @return  the {@link Stream} of {@link Path}
      *
      * @throws  IllegalArgumentException
      *          if the {@code maxDepth} parameter is negative
@@ -3499,24 +3543,25 @@
      * @see     #walk(Path, int, FileVisitOption...)
      * @since   1.8
      */
-    public static CloseableStream<Path> find(Path start,
-                                             int maxDepth,
-                                             BiPredicate<Path, BasicFileAttributes> matcher,
-                                             FileVisitOption... options)
-        throws IOException
-    {
+    public static Stream<Path> find(Path start,
+                                    int maxDepth,
+                                    BiPredicate<Path, BasicFileAttributes> matcher,
+                                    FileVisitOption... options)
+            throws IOException {
         FileTreeIterator iterator = new FileTreeIterator(start, maxDepth, options);
-
-        Stream<Path> s = StreamSupport.stream(
-                Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT),
-                false).
-                filter(entry -> matcher.test(entry.file(), entry.attributes())).
-                map(entry -> entry.file());
-        return new DelegatingCloseableStream<>(iterator, s);
+        try {
+            return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT), false)
+                                .onClose(iterator::close)
+                                .filter(entry -> matcher.test(entry.file(), entry.attributes()))
+                                .map(entry -> entry.file());
+        } catch (Error|RuntimeException e) {
+            iterator.close();
+            throw e;
+        }
     }
 
     /**
-     * Read all lines from a file as a {@code CloseableStream}.  Unlike {@link
+     * Read all lines from a file as a {@code Stream}.  Unlike {@link
      * #readAllLines(Path, Charset) readAllLines}, this method does not read
      * all lines into a {@code List}, but instead populates lazily as the stream
      * is consumed.
@@ -3528,22 +3573,24 @@
      * <p> After this method returns, then any subsequent I/O exception that
      * occurs while reading from the file or when a malformed or unmappable byte
      * sequence is read, is wrapped in an {@link UncheckedIOException} that will
-     * be thrown form the
+     * be thrown from the
      * {@link java.util.stream.Stream} method that caused the read to take
      * place. In case an {@code IOException} is thrown when closing the file,
      * it is also wrapped as an {@code UncheckedIOException}.
      *
-     * <p> When not using the try-with-resources construct, then stream's
-     * {@link CloseableStream#close close} method should be invoked after
-     * operation is completed so as to free any resources held for the open
-     * file.
+     * <p> The returned stream encapsulates a {@link Reader}.  If timely
+     * disposal of file system resources is required, the try-with-resources
+     * construct should be used to ensure that the stream's
+     * {@link Stream#close close} method is invoked after the stream operations
+     * are completed.
+     *
      *
      * @param   path
      *          the path to the file
      * @param   cs
      *          the charset to use for decoding
      *
-     * @return  the lines from the file as a {@code CloseableStream}
+     * @return  the lines from the file as a {@code Stream}
      *
      * @throws  IOException
      *          if an I/O error occurs opening the file
@@ -3557,10 +3604,19 @@
      * @see     java.io.BufferedReader#lines()
      * @since   1.8
      */
-    public static CloseableStream<String> lines(Path path, Charset cs)
-        throws IOException
-    {
+    public static Stream<String> lines(Path path, Charset cs) throws IOException {
         BufferedReader br = Files.newBufferedReader(path, cs);
-        return new DelegatingCloseableStream<>(br, br.lines());
+        try {
+            return br.lines().onClose(asUncheckedRunnable(br));
+        } catch (Error|RuntimeException e) {
+            try {
+                br.close();
+            } catch (IOException ex) {
+                try {
+                    e.addSuppressed(ex);
+                } catch (Throwable ignore) {}
+            }
+            throw e;
+        }
     }
 }
--- a/src/share/classes/java/util/HashMap.java	Fri Sep 06 12:04:18 2013 -0400
+++ b/src/share/classes/java/util/HashMap.java	Fri Sep 06 12:10:30 2013 -0400
@@ -25,13 +25,14 @@
 
 package java.util;
 
-import java.io.*;
+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.concurrent.ThreadLocalRandom;
 import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
 import java.util.function.Consumer;
-import java.util.function.BiFunction;
 import java.util.function.Function;
 
 /**
@@ -63,20 +64,25 @@
  * 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>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.
+ * <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
@@ -128,11 +134,100 @@
  * @see     Hashtable
  * @since   1.2
  */
+public class HashMap<K,V> extends AbstractMap<K,V>
+    implements Map<K,V>, Cloneable, Serializable {
 
-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.
@@ -152,14 +247,158 @@
     static final float DEFAULT_LOAD_FACTOR = 0.75f;
 
     /**
-     * An empty table instance to share when the table is not inflated.
+     * 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 Object[] EMPTY_TABLE = {};
+    static final int TREEIFY_THRESHOLD = 8;
 
     /**
-     * The table, resized as necessary. Length MUST Always be a power of two.
+     * 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.
      */
-    transient Object[] table = EMPTY_TABLE;
+    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.
@@ -167,21 +406,6 @@
     transient int size;
 
     /**
-     * The next size value at which to resize (capacity * load factor).
-     * @serial
-     */
-    // If table == EMPTY_TABLE then this is the initial capacity at which the
-    // table will be created when inflated.
-    int threshold;
-
-    /**
-     * The load factor for the hash table.
-     *
-     * @serial
-     */
-    final float loadFactor;
-
-    /**
      * The number of times this HashMap has been structurally modified
      * Structural modifications are those that change the number of mappings in
      * the HashMap or otherwise modify its internal structure (e.g.,
@@ -191,627 +415,24 @@
     transient int modCount;
 
     /**
-     * Holds values which can't be initialized until after VM is booted.
+     * The next size value at which to resize (capacity * load factor).
+     *
+     * @serial
      */
-    private static class Holder {
-        static final sun.misc.Unsafe UNSAFE;
-
-        /**
-         * Offset of "final" hashSeed field we must set in
-         * readObject() method.
-         */
-        static final long HASHSEED_OFFSET;
-
-        static final boolean USE_HASHSEED;
-
-        static {
-            String hashSeedProp = java.security.AccessController.doPrivileged(
-                    new sun.security.action.GetPropertyAction(
-                        "jdk.map.useRandomSeed"));
-            boolean localBool = (null != hashSeedProp)
-                    ? Boolean.parseBoolean(hashSeedProp) : false;
-            USE_HASHSEED = localBool;
-
-            if (USE_HASHSEED) {
-                try {
-                    UNSAFE = sun.misc.Unsafe.getUnsafe();
-                    HASHSEED_OFFSET = UNSAFE.objectFieldOffset(
-                        HashMap.class.getDeclaredField("hashSeed"));
-                } catch (NoSuchFieldException | SecurityException e) {
-                    throw new InternalError("Failed to record hashSeed offset", e);
-                }
-            } else {
-                UNSAFE = null;
-                HASHSEED_OFFSET = 0;
-            }
-        }
-    }
-
-    /*
-     * A randomizing value associated with this instance that is applied to
-     * hash code of keys to make hash collisions harder to find.
-     *
-     * Non-final so it can be set lazily, but be sure not to set more than once.
-     */
-    transient final int hashSeed;
-
-    /*
-     * TreeBin/TreeNode code from CHM doesn't handle the null key.  Store the
-     * null key entry here.
-     */
-    transient Entry<K,V> nullKeyEntry = null;
-
-    /*
-     * In order to improve performance under high hash-collision conditions,
-     * HashMap will switch to storing a bin's entries in a balanced tree
-     * (TreeBin) instead of a linked-list once the number of entries in the bin
-     * passes a certain threshold (TreeBin.TREE_THRESHOLD), if at least one of
-     * the keys in the bin implements Comparable.  This technique is borrowed
-     * from ConcurrentHashMap.
-     */
-
-    /*
-     * Code based on CHMv8
-     *
-     * Node type for TreeBin
-     */
-    final static class TreeNode<K,V> {
-        TreeNode parent;  // red-black tree links
-        TreeNode left;
-        TreeNode right;
-        TreeNode prev;    // needed to unlink next upon deletion
-        boolean red;
-        final HashMap.Entry<K,V> entry;
-
-        TreeNode(HashMap.Entry<K,V> entry, Object next, TreeNode parent) {
-            this.entry = entry;
-            this.entry.next = next;
-            this.parent = parent;
-        }
-    }
+    // (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;
 
     /**
-     * Returns a Class for the given object of the form "class C
-     * implements Comparable<C>", if one exists, else null.  See the TreeBin
-     * docs, below, for explanation.
+     * The load factor for the hash table.
+     *
+     * @serial
      */
-    static Class<?> comparableClassFor(Object x) {
-        Class<?> c, s, cmpc; Type[] ts, as; Type t; ParameterizedType p;
-        if ((c = x.getClass()) == String.class) // bypass checks
-            return c;
-        if ((cmpc = Comparable.class).isAssignableFrom(c)) {
-            while (cmpc.isAssignableFrom(s = c.getSuperclass()))
-                c = s; // find topmost comparable class
-            if ((ts  = c.getGenericInterfaces()) != null) {
-                for (int i = 0; i < ts.length; ++i) {
-                    if (((t = ts[i]) instanceof ParameterizedType) &&
-                        ((p = (ParameterizedType)t).getRawType() == cmpc) &&
-                        (as = p.getActualTypeArguments()) != null &&
-                        as.length == 1 && as[0] == c) // type arg is c
-                        return c;
-                }
-            }
-        }
-        return null;
-    }
+    final float loadFactor;
 
-    /*
-     * Code based on CHMv8
-     *
-     * A specialized form of red-black tree for use in bins
-     * whose size exceeds a threshold.
-     *
-     * 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<T>
-     * 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.)  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).
-     */
-    final class TreeBin {
-        /*
-         * The bin count threshold for using a tree rather than list for a bin. The
-         * value reflects the approximate break-even point for using tree-based
-         * operations.
-         */
-        static final int TREE_THRESHOLD = 16;
-
-        TreeNode<K,V> root;  // root of tree
-        TreeNode<K,V> first; // head of next-pointer list
-
-        /*
-         * Split a TreeBin into lo and hi parts and install in given table.
-         *
-         * Existing Entrys are re-used, which maintains the before/after links for
-         * LinkedHashMap.Entry.
-         *
-         * No check for Comparable, though this is the same as CHM.
-         */
-        final void splitTreeBin(Object[] newTable, int i, TreeBin loTree, TreeBin hiTree) {
-            TreeBin oldTree = this;
-            int bit = newTable.length >>> 1;
-            int loCount = 0, hiCount = 0;
-            TreeNode<K,V> e = oldTree.first;
-            TreeNode<K,V> next;
-
-            // This method is called when the table has just increased capacity,
-            // so indexFor() is now taking one additional bit of hash into
-            // account ("bit").  Entries in this TreeBin now belong in one of
-            // two bins, "i" or "i+bit", depending on if the new top bit of the
-            // hash is set.  The trees for the two bins are loTree and hiTree.
-            // If either tree ends up containing fewer than TREE_THRESHOLD
-            // entries, it is converted back to a linked list.
-            while (e != null) {
-                // Save entry.next - it will get overwritten in putTreeNode()
-                next = (TreeNode<K,V>)e.entry.next;
-
-                int h = e.entry.hash;
-                K k = (K) e.entry.key;
-                V v = e.entry.value;
-                if ((h & bit) == 0) {
-                    ++loCount;
-                    // Re-using e.entry
-                    loTree.putTreeNode(h, k, v, e.entry);
-                } else {
-                    ++hiCount;
-                    hiTree.putTreeNode(h, k, v, e.entry);
-                }
-                // Iterate using the saved 'next'
-                e = next;
-            }
-            if (loCount < TREE_THRESHOLD) { // too small, convert back to list
-                HashMap.Entry loEntry = null;
-                TreeNode<K,V> p = loTree.first;
-                while (p != null) {
-                    @SuppressWarnings("unchecked")
-                    TreeNode<K,V> savedNext = (TreeNode<K,V>) p.entry.next;
-                    p.entry.next = loEntry;
-                    loEntry = p.entry;
-                    p = savedNext;
-                }
-                // assert newTable[i] == null;
-                newTable[i] = loEntry;
-            } else {
-                // assert newTable[i] == null;
-                newTable[i] = loTree;
-            }
-            if (hiCount < TREE_THRESHOLD) { // too small, convert back to list
-                HashMap.Entry hiEntry = null;
-                TreeNode<K,V> p = hiTree.first;
-                while (p != null) {
-                    @SuppressWarnings("unchecked")
-                    TreeNode<K,V> savedNext = (TreeNode<K,V>) p.entry.next;
-                    p.entry.next = hiEntry;
-                    hiEntry = p.entry;
-                    p = savedNext;
-                }
-                // assert newTable[i + bit] == null;
-                newTable[i + bit] = hiEntry;
-            } else {
-                // assert newTable[i + bit] == null;
-                newTable[i + bit] = hiTree;
-            }
-        }
-
-        /*
-         * Popuplate the TreeBin with entries from the linked list e
-         *
-         * Assumes 'this' is a new/empty TreeBin
-         *
-         * Note: no check for Comparable
-         * Note: I believe this changes iteration order
-         */
-        @SuppressWarnings("unchecked")
-        void populate(HashMap.Entry e) {
-            // assert root == null;
-            // assert first == null;
-            HashMap.Entry next;
-            while (e != null) {
-                // Save entry.next - it will get overwritten in putTreeNode()
-                next = (HashMap.Entry)e.next;
-                // Re-using Entry e will maintain before/after in LinkedHM
-                putTreeNode(e.hash, (K)e.key, (V)e.value, e);
-                // Iterate using the saved 'next'
-                e = next;
-            }
-        }
-
-        /**
-         * Copied from CHMv8
-         * From CLR
-         */
-        private void rotateLeft(TreeNode p) {
-            if (p != null) {
-                TreeNode r = p.right, pp, rl;
-                if ((rl = p.right = r.left) != null) {
-                    rl.parent = p;
-                }
-                if ((pp = r.parent = p.parent) == null) {
-                    root = r;
-                } else if (pp.left == p) {
-                    pp.left = r;
-                } else {
-                    pp.right = r;
-                }
-                r.left = p;
-                p.parent = r;
-            }
-        }
-
-        /**
-         * Copied from CHMv8
-         * From CLR
-         */
-        private void rotateRight(TreeNode p) {
-            if (p != null) {
-                TreeNode l = p.left, pp, lr;
-                if ((lr = p.left = l.right) != null) {
-                    lr.parent = p;
-                }
-                if ((pp = l.parent = p.parent) == null) {
-                    root = l;
-                } else if (pp.right == p) {
-                    pp.right = l;
-                } else {
-                    pp.left = l;
-                }
-                l.right = p;
-                p.parent = l;
-            }
-        }
-
-        /**
-         * Returns the TreeNode (or null if not found) for the given
-         * key.  A front-end for recursive version.
-         */
-        final TreeNode getTreeNode(int h, K k) {
-            return getTreeNode(h, k, root, comparableClassFor(k));
-        }
-
-        /**
-         * Returns the TreeNode (or null if not found) for the given key
-         * starting at given root.
-         */
-        @SuppressWarnings("unchecked")
-        final TreeNode getTreeNode (int h, K k, TreeNode p, Class<?> cc) {
-            // assert k != null;
-            while (p != null) {
-                int dir, ph;  Object pk;
-                if ((ph = p.entry.hash) != h)
-                    dir = (h < ph) ? -1 : 1;
-                else if ((pk = p.entry.key) == k || k.equals(pk))
-                    return p;
-                else if (cc == null || comparableClassFor(pk) != cc ||
-                         (dir = ((Comparable<Object>)k).compareTo(pk)) == 0) {
-                    // assert pk != null;
-                    TreeNode r, pl, pr; // check both sides
-                    if ((pr = p.right) != null &&
-                        (r = getTreeNode(h, k, pr, cc)) != null)
-                        return r;
-                    else if ((pl = p.left) != null)
-                        dir = -1;
-                    else // nothing there
-                        break;
-                }
-                p = (dir > 0) ? p.right : p.left;
-            }
-            return null;
-        }
-
-        /*
-         * Finds or adds a node.
-         *
-         * 'entry' should be used to recycle an existing Entry (e.g. in the case
-         * of converting a linked-list bin to a TreeBin).
-         * If entry is null, a new Entry will be created for the new TreeNode
-         *
-         * @return the TreeNode containing the mapping, or null if a new
-         * TreeNode was added
-         */
-        @SuppressWarnings("unchecked")
-        TreeNode putTreeNode(int h, K k, V v, HashMap.Entry<K,V> entry) {
-            // assert k != null;
-            //if (entry != null) {
-                // assert h == entry.hash;
-                // assert k == entry.key;
-                // assert v == entry.value;
-            // }
-            Class<?> cc = comparableClassFor(k);
-            TreeNode pp = root, p = null;
-            int dir = 0;
-            while (pp != null) { // find existing node or leaf to insert at
-                int ph;  Object pk;
-                p = pp;
-                if ((ph = p.entry.hash) != h)
-                    dir = (h < ph) ? -1 : 1;
-                else if ((pk = p.entry.key) == k || k.equals(pk))
-                    return p;
-                else if (cc == null || comparableClassFor(pk) != cc ||
-                         (dir = ((Comparable<Object>)k).compareTo(pk)) == 0) {
-                    TreeNode r, pr;
-                    if ((pr = p.right) != null &&
-                        (r = getTreeNode(h, k, pr, cc)) != null)
-                        return r;
-                    else // continue left
-                        dir = -1;
-                }
-                pp = (dir > 0) ? p.right : p.left;
-            }
-
-            // Didn't find the mapping in the tree, so add it
-            TreeNode f = first;
-            TreeNode x;
-            if (entry != null) {
-                x = new TreeNode(entry, f, p);
-            } else {
-                x = new TreeNode(newEntry(h, k, v, null), f, p);
-            }
-            first = x;
-
-            if (p == null) {
-                root = x;
-            } else { // attach and rebalance; adapted from CLR
-                TreeNode xp, xpp;
-                if (f != null) {
-                    f.prev = x;
-                }
-                if (dir <= 0) {
-                    p.left = x;
-                } else {
-                    p.right = x;
-                }
-                x.red = true;
-                while (x != null && (xp = x.parent) != null && xp.red
-                        && (xpp = xp.parent) != null) {
-                    TreeNode xppl = xpp.left;
-                    if (xp == xppl) {
-                        TreeNode y = xpp.right;
-                        if (y != null && y.red) {
-                            y.red = false;
-                            xp.red = false;
-                            xpp.red = true;
-                            x = xpp;
-                        } else {
-                            if (x == xp.right) {
-                                rotateLeft(x = xp);
-                                xpp = (xp = x.parent) == null ? null : xp.parent;
-                            }
-                            if (xp != null) {
-                                xp.red = false;
-                                if (xpp != null) {
-                                    xpp.red = true;
-                                    rotateRight(xpp);
-                                }
-                            }
-                        }
-                    } else {
-                        TreeNode y = xppl;
-                        if (y != null && y.red) {
-                            y.red = false;
-                            xp.red = false;
-                            xpp.red = true;
-                            x = xpp;
-                        } else {
-                            if (x == xp.left) {
-                                rotateRight(x = xp);
-                                xpp = (xp = x.parent) == null ? null : xp.parent;
-                            }
-                            if (xp != null) {
-                                xp.red = false;
-                                if (xpp != null) {
-                                    xpp.red = true;
-                                    rotateLeft(xpp);
-                                }
-                            }
-                        }
-                    }
-                }
-                TreeNode r = root;
-                if (r != null && r.red) {
-                    r.red = false;
-                }
-            }
-            return null;
-        }
-
-        /*
-         * From CHMv8
-         *
-         * 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.
-         */
-        final void deleteTreeNode(TreeNode p) {
-            TreeNode next = (TreeNode) p.entry.next; // unlink traversal pointers
-            TreeNode pred = p.prev;
-            if (pred == null) {
-                first = next;
-            } else {
-                pred.entry.next = next;
-            }
-            if (next != null) {
-                next.prev = pred;
-            }
-            TreeNode replacement;
-            TreeNode pl = p.left;
-            TreeNode pr = p.right;
-            if (pl != null && pr != null) {
-                TreeNode 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 sr = s.right;
-                TreeNode pp = p.parent;
-                if (s == pr) { // p was s's direct parent
-                    p.parent = s;
-                    s.right = p;
-                } else {
-                    TreeNode 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;
-                }
-                replacement = sr;
-            } else {
-                replacement = (pl != null) ? pl : pr;
-            }
-            TreeNode pp = p.parent;
-            if (replacement == null) {
-                if (pp == null) {
-                    root = null;
-                    return;
-                }
-                replacement = p;
-            } else {
-                replacement.parent = pp;
-                if (pp == null) {
-                    root = replacement;
-                } else if (p == pp.left) {
-                    pp.left = replacement;
-                } else {
-                    pp.right = replacement;
-                }
-                p.left = p.right = p.parent = null;
-            }
-            if (!p.red) { // rebalance, from CLR
-                TreeNode x = replacement;
-                while (x != null) {
-                    TreeNode xp, xpl;
-                    if (x.red || (xp = x.parent) == null) {
-                        x.red = false;
-                        break;
-                    }
-                    if (x == (xpl = xp.left)) {
-                        TreeNode sib = xp.right;
-                        if (sib != null && sib.red) {
-                            sib.red = false;
-                            xp.red = true;
-                            rotateLeft(xp);
-                            sib = (xp = x.parent) == null ? null : xp.right;
-                        }
-                        if (sib == null) {
-                            x = xp;
-                        } else {
-                            TreeNode sl = sib.left, sr = sib.right;
-                            if ((sr == null || !sr.red)
-                                    && (sl == null || !sl.red)) {
-                                sib.red = true;
-                                x = xp;
-                            } else {
-                                if (sr == null || !sr.red) {
-                                    if (sl != null) {
-                                        sl.red = false;
-                                    }
-                                    sib.red = true;
-                                    rotateRight(sib);
-                                    sib = (xp = x.parent) == null ?
-                                        null : xp.right;
-                                }
-                                if (sib != null) {
-                                    sib.red = (xp == null) ? false : xp.red;
-                                    if ((sr = sib.right) != null) {
-                                        sr.red = false;
-                                    }
-                                }
-                                if (xp != null) {
-                                    xp.red = false;
-                                    rotateLeft(xp);
-                                }
-                                x = root;
-                            }
-                        }
-                    } else { // symmetric
-                        TreeNode sib = xpl;
-                        if (sib != null && sib.red) {
-                            sib.red = false;
-                            xp.red = true;
-                            rotateRight(xp);
-                            sib = (xp = x.parent) == null ? null : xp.left;
-                        }
-                        if (sib == null) {
-                            x = xp;
-                        } else {
-                            TreeNode sl = sib.left, sr = sib.right;
-                            if ((sl == null || !sl.red)
-                                    && (sr == null || !sr.red)) {
-                                sib.red = true;
-                                x = xp;
-                            } else {
-                                if (sl == null || !sl.red) {
-                                    if (sr != null) {
-                                        sr.red = false;
-                                    }
-                                    sib.red = true;
-                                    rotateLeft(sib);
-                                    sib = (xp = x.parent) == null ?
-                                        null : xp.left;
-                                }
-                                if (sib != null) {
-                                    sib.red = (xp == null) ? false : xp.red;
-                                    if ((sl = sib.left) != null) {
-                                        sl.red = false;
-                                    }
-                                }
-                                if (xp != null) {
-                                    xp.red = false;
-                                    rotateRight(xp);
-                                }
-                                x = root;
-                            }
-                        }
-                    }
-                }
-            }
-            if (p == replacement && (pp = p.parent) != null) {
-                if (p == pp.left) // detach pointers
-                {
-                    pp.left = null;
-                } else if (p == pp.right) {
-                    pp.right = null;
-                }
-                p.parent = null;
-            }
-        }
-    }
+    /* ---------------- Public operations -------------- */
 
     /**
      * Constructs an empty <tt>HashMap</tt> with the specified initial
@@ -832,9 +453,7 @@
             throw new IllegalArgumentException("Illegal load factor: " +
                                                loadFactor);
         this.loadFactor = loadFactor;
-        threshold = initialCapacity;
-        hashSeed = initHashSeed();
-        init();
+        this.threshold = tableSizeFor(initialCapacity);
     }
 
     /**
@@ -853,7 +472,7 @@
      * (16) and the default load factor (0.75).
      */
     public HashMap() {
-        this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
+        this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
     }
 
     /**
@@ -866,79 +485,35 @@
      * @throws  NullPointerException if the specified map is null
      */
     public HashMap(Map<? extends K, ? extends V> m) {
-        this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
-                DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);
-        inflateTable(threshold);
-
-        putAllForCreate(m);
-        // assert size == m.size();
-    }
-
-    private static int roundUpToPowerOf2(int number) {
-        // assert number >= 0 : "number must be non-negative";
-        return number >= MAXIMUM_CAPACITY
-                ? MAXIMUM_CAPACITY
-                : (number > 1) ? Integer.highestOneBit((number - 1) << 1) : 1;
+        this.loadFactor = DEFAULT_LOAD_FACTOR;
+        putMapEntries(m, false);
     }
 
     /**
-     * Inflates the table.
+     * Implements Map.putAll and Map constructor
+     *
+     * @param m the map
+     * @param evict false when initially constructing this map, else
+     * true (relayed to method afterNodeInsertion).
      */
-    private void inflateTable(int toSize) {
-        // Find a power of 2 >= toSize
-        int capacity = roundUpToPowerOf2(toSize);
-
-        threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);
-        table = new Object[capacity];
-    }
-
-    // internal utilities
-
-    /**
-     * Initialization hook for subclasses. This method is called
-     * in all constructors and pseudo-constructors (clone, readObject)
-     * after HashMap has been initialized but before any entries have
-     * been inserted.  (In the absence of this method, readObject would
-     * require explicit knowledge of subclasses.)
-     */
-    void init() {
-    }
-
-    /**
-     * Return an initial value for the hashSeed, or 0 if the random seed is not
-     * enabled.
-     */
-    final int initHashSeed() {
-        if (sun.misc.VM.isBooted() && Holder.USE_HASHSEED) {
-            int seed = ThreadLocalRandom.current().nextInt();
-            return (seed != 0) ? seed : 1;
+    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);
+            }
         }
-        return 0;
-    }
-
-    /**
-     * 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 = hashSeed ^ 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.
-     */
-    static int indexFor(int h, int length) {
-        // assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2";
-        return h & (length-1);
     }
 
     /**
@@ -976,18 +551,36 @@
      *
      * @see #put(Object, Object)
      */
-    @SuppressWarnings("unchecked")
     public V get(Object key) {
-        Entry<K,V> entry = getEntry(key);
-
-        return null == entry ? null : entry.getValue();
+        Node<K,V> e;
+        return (e = getNode(hash(key), key)) == null ? null : e.value;
     }
 
-    @Override
-    public V getOrDefault(Object key, V defaultValue) {
-        Entry<K,V> entry = getEntry(key);
-
-        return (entry == null) ? defaultValue : entry.getValue();
+    /**
+     * 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;
     }
 
     /**
@@ -999,49 +592,10 @@
      * key.
      */
     public boolean containsKey(Object key) {
-        return getEntry(key) != null;
+        return getNode(hash(key), key) != null;
     }
 
     /**
-     * Returns the entry associated with the specified key in the
-     * HashMap.  Returns null if the HashMap contains no mapping
-     * for the key.
-     */
-    @SuppressWarnings("unchecked")
-    final Entry<K,V> getEntry(Object key) {
-        if (size == 0) {
-            return null;
-        }
-        if (key == null) {
-            return nullKeyEntry;
-        }
-        int hash = hash(key);
-        int bin = indexFor(hash, table.length);
-
-        if (table[bin] instanceof Entry) {
-            Entry<K,V> e = (Entry<K,V>) table[bin];
-            for (; e != null; e = (Entry<K,V>)e.next) {
-                Object k;
-                if (e.hash == hash &&
-                    ((k = e.key) == key || key.equals(k))) {
-                    return e;
-                }
-            }
-        } else if (table[bin] != null) {
-            TreeBin e = (TreeBin)table[bin];
-            TreeNode p = e.getTreeNode(hash, (K)key);
-            if (p != null) {
-                // assert p.entry.hash == hash && p.entry.key.equals(key);
-                return (Entry<K,V>)p.entry;
-            } else {
-                return null;
-            }
-        }
-        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.
@@ -1053,202 +607,169 @@
      *         (A <tt>null</tt> return can also indicate that the map
      *         previously associated <tt>null</tt> with <tt>key</tt>.)
      */
-    @SuppressWarnings("unchecked")
     public V put(K key, V value) {
-        if (table == EMPTY_TABLE) {
-            inflateTable(threshold);
-        }
-       if (key == null)
-            return putForNullKey(value);
-        int hash = hash(key);
-        int i = indexFor(hash, table.length);
-        boolean checkIfNeedTree = false; // Might we convert bin to a TreeBin?
+        return putVal(hash(key), key, value, false, true);
+    }
 
-        if (table[i] instanceof Entry) {
-            // Bin contains ordinary Entries.  Search for key in the linked list
-            // of entries, counting the number of entries.  Only check for
-            // TreeBin conversion if the list size is >= TREE_THRESHOLD.
-            // (The conversion still may not happen if the table gets resized.)
-            int listSize = 0;
-            Entry<K,V> e = (Entry<K,V>) table[i];
-            for (; e != null; e = (Entry<K,V>)e.next) {
-                Object k;
-                if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
-                    V oldValue = e.value;
+    /**
+     * 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 (size > threshold || (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;
-                    e.recordAccess(this);
-                    return oldValue;
-                }
-                listSize++;
-            }
-            // Didn't find, so fall through and call addEntry() to add the
-            // Entry and check for TreeBin conversion.
-            checkIfNeedTree = listSize >= TreeBin.TREE_THRESHOLD;
-        } else if (table[i] != null) {
-            TreeBin e = (TreeBin)table[i];
-            TreeNode p = e.putTreeNode(hash, key, value, null);
-            if (p == null) { // putTreeNode() added a new node
-                modCount++;
-                size++;
-                if (size >= threshold) {
-                    resize(2 * table.length);
-                }
-                return null;
-            } else { // putTreeNode() found an existing node
-                Entry<K,V> pEntry = (Entry<K,V>)p.entry;
-                V oldVal = pEntry.value;
-                pEntry.value = value;
-                pEntry.recordAccess(this);
-                return oldVal;
+                afterNodeAccess(e);
+                return oldValue;
             }
         }
-        modCount++;
-        addEntry(hash, key, value, i, checkIfNeedTree);
+        ++modCount;
+        ++size;
+        afterNodeInsertion(evict);
         return null;
     }
 
     /**
-     * Offloaded version of put for null keys
+     * 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
      */
-    private V putForNullKey(V value) {
-        if (nullKeyEntry != null) {
-            V oldValue = nullKeyEntry.value;
-            nullKeyEntry.value = value;
-            nullKeyEntry.recordAccess(this);
-            return oldValue;
+    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
         }
-        modCount++;
-        size++; // newEntry() skips size++
-        nullKeyEntry = newEntry(0, null, value, null);
-        return null;
-    }
-
-    private void putForCreateNullKey(V value) {
-        // Look for preexisting entry for key.  This will never happen for
-        // clone or deserialize.  It will only happen for construction if the
-        // input Map is a sorted map whose ordering is inconsistent w/ equals.
-        if (nullKeyEntry != null) {
-            nullKeyEntry.value = value;
-        } else {
-            nullKeyEntry = newEntry(0, null, value, null);
-            size++;
+        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);
         }
-    }
-
-
-    /**
-     * This method is used instead of put by constructors and
-     * pseudoconstructors (clone, readObject).  It does not resize the table,
-     * check for comodification, etc, though it will convert bins to TreeBins
-     * as needed.  It calls createEntry rather than addEntry.
-     */
-    @SuppressWarnings("unchecked")
-    private void putForCreate(K key, V value) {
-        if (null == key) {
-            putForCreateNullKey(value);
-            return;
+        if (newThr == 0) {
+            float ft = (float)newCap * loadFactor;
+            newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
+                      (int)ft : Integer.MAX_VALUE);
         }
-        int hash = hash(key);
-        int i = indexFor(hash, table.length);
-        boolean checkIfNeedTree = false; // Might we convert bin to a TreeBin?
-
-        /**
-         * Look for preexisting entry for key.  This will never happen for
-         * clone or deserialize.  It will only happen for construction if the
-         * input Map is a sorted map whose ordering is inconsistent w/ equals.
-         */
-        if (table[i] instanceof Entry) {
-            int listSize = 0;
-            Entry<K,V> e = (Entry<K,V>) table[i];
-            for (; e != null; e = (Entry<K,V>)e.next) {
-                Object k;
-                if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
-                    e.value = value;
-                    return;
+        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;
+                        }
+                    }
                 }
-                listSize++;
             }
-            // Didn't find, fall through to createEntry().
-            // Check for conversion to TreeBin done via createEntry().
-            checkIfNeedTree = listSize >= TreeBin.TREE_THRESHOLD;
-        } else if (table[i] != null) {
-            TreeBin e = (TreeBin)table[i];
-            TreeNode p = e.putTreeNode(hash, key, value, null);
-            if (p != null) {
-                p.entry.setValue(value); // Found an existing node, set value
-            } else {
-                size++; // Added a new TreeNode, so update size
-            }
-            // don't need modCount++/check for resize - just return
-            return;
         }
-
-        createEntry(hash, key, value, i, checkIfNeedTree);
-    }
-
-    private void putAllForCreate(Map<? extends K, ? extends V> m) {
-        for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
-            putForCreate(e.getKey(), e.getValue());
+        return newTab;
     }
 
     /**
-     * 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).
+     * Replaces all linked nodes in bin at index for given hash unless
+     * table is too small, in which case resizes instead.
      */
-    void resize(int newCapacity) {
-        Object[] oldTable = table;
-        int oldCapacity = oldTable.length;
-        if (oldCapacity == MAXIMUM_CAPACITY) {
-            threshold = Integer.MAX_VALUE;
-            return;
+    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);
         }
-
-        Object[] newTable = new Object[newCapacity];
-        transfer(newTable);
-        table = newTable;
-        threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
-    }
-
-    /**
-     * Transfers all entries from current table to newTable.
-     *
-     * Assumes newTable is larger than table
-     */
-    @SuppressWarnings("unchecked")
-    void transfer(Object[] newTable) {
-        Object[] src = table;
-        // assert newTable.length > src.length : "newTable.length(" +
-        //   newTable.length + ") expected to be > src.length("+src.length+")";
-        int newCapacity = newTable.length;
-        for (int j = 0; j < src.length; j++) {
-             if (src[j] instanceof Entry) {
-                // Assume: since wasn't TreeBin before, won't need TreeBin now
-                Entry<K,V> e = (Entry<K,V>) src[j];
-                while (null != e) {
-                    Entry<K,V> next = (Entry<K,V>)e.next;
-                    int i = indexFor(e.hash, newCapacity);
-                    e.next = (Entry<K,V>) newTable[i];
-                    newTable[i] = e;
-                    e = next;
-                }
-            } else if (src[j] != null) {
-                TreeBin e = (TreeBin) src[j];
-                TreeBin loTree = new TreeBin();
-                TreeBin hiTree = new TreeBin();
-                e.splitTreeBin(newTable, j, loTree, hiTree);
-            }
-        }
-        Arrays.fill(table, null);
     }
 
     /**
@@ -1260,30 +781,8 @@
      * @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;
-
-        if (table == EMPTY_TABLE) {
-            inflateTable((int) Math.max(numKeysToBeAdded * loadFactor, threshold));
-        }
-
-        /*
-         * 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 && table.length < MAXIMUM_CAPACITY) {
-            resize(table.length * 2);
-        }
-
-        for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
-            put(e.getKey(), e.getValue());
-        }
+        putMapEntries(m, true);
+    }
 
     /**
      * Removes the mapping for the specified key from this map if present.
@@ -1295,834 +794,74 @@
      *         previously associated <tt>null</tt> with <tt>key</tt>.)
      */
     public V remove(Object key) {
-        Entry<K,V> e = removeEntryForKey(key);
-       return (e == null ? null : e.value);
-   }
+        Node<K,V> e;
+        return (e = removeNode(hash(key), key, null, false, true)) == null ?
+            null : e.value;
+    }
 
-   // optimized implementations of default methods in Map
-
-    @Override
-    public void forEach(BiConsumer<? super K, ? super V> action) {
-        Objects.requireNonNull(action);
-        final int expectedModCount = modCount;
-        if (nullKeyEntry != null) {
-            forEachNullKey(expectedModCount, action);
-        }
-        Object[] tab = this.table;
-        for (int index = 0; index < tab.length; index++) {
-            Object item = tab[index];
-            if (item == null) {
-                continue;
-            }
-            if (item instanceof HashMap.TreeBin) {
-                eachTreeNode(expectedModCount, ((TreeBin)item).first, action);
-                continue;
-            }
-            @SuppressWarnings("unchecked")
-            Entry<K, V> entry = (Entry<K, V>)item;
-            while (entry != null) {
-                action.accept(entry.key, entry.value);
-                entry = (Entry<K, V>)entry.next;
-
-                if (expectedModCount != modCount) {
-                    throw new ConcurrentModificationException();
+    /**
+     * 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);
                 }
             }
-        }
-    }
-
-    private void eachTreeNode(int expectedModCount, TreeNode<K, V> node, BiConsumer<? super K, ? super V> action) {
-        while (node != null) {
-            @SuppressWarnings("unchecked")
-            Entry<K, V> entry = (Entry<K, V>)node.entry;
-            action.accept(entry.key, entry.value);
-            node = (TreeNode<K, V>)entry.next;
-
-            if (expectedModCount != modCount) {
-                throw new ConcurrentModificationException();
-            }
-        }
-    }
-
-    private void forEachNullKey(int expectedModCount, BiConsumer<? super K, ? super V> action) {
-        action.accept(null, nullKeyEntry.value);
-
-        if (expectedModCount != modCount) {
-            throw new ConcurrentModificationException();
-        }
-    }
-
-    @Override
-    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
-        Objects.requireNonNull(function);
-        final int expectedModCount = modCount;
-        if (nullKeyEntry != null) {
-            replaceforNullKey(expectedModCount, function);
-        }
-        Object[] tab = this.table;
-        for (int index = 0; index < tab.length; index++) {
-            Object item = tab[index];
-            if (item == null) {
-                continue;
-            }
-            if (item instanceof HashMap.TreeBin) {
-                replaceEachTreeNode(expectedModCount, ((TreeBin)item).first, function);
-                continue;
-            }
-            @SuppressWarnings("unchecked")
-            Entry<K, V> entry = (Entry<K, V>)item;
-            while (entry != null) {
-                entry.value = function.apply(entry.key, entry.value);
-                entry = (Entry<K, V>)entry.next;
-
-                if (expectedModCount != modCount) {
-                    throw new ConcurrentModificationException();
-                }
-            }
-        }
-    }
-
-    private void replaceEachTreeNode(int expectedModCount, TreeNode<K, V> node, BiFunction<? super K, ? super V, ? extends V> function) {
-        while (node != null) {
-            @SuppressWarnings("unchecked")
-            Entry<K, V> entry = (Entry<K, V>)node.entry;
-            entry.value = function.apply(entry.key, entry.value);
-            node = (TreeNode<K, V>)entry.next;
-
-            if (expectedModCount != modCount) {
-                throw new ConcurrentModificationException();
-            }
-        }
-    }
-
-    private void replaceforNullKey(int expectedModCount, BiFunction<? super K, ? super V, ? extends V> function) {
-        nullKeyEntry.value = function.apply(null, nullKeyEntry.value);
-
-        if (expectedModCount != modCount) {
-            throw new ConcurrentModificationException();
-        }
-    }
-
-    @Override
-    public V putIfAbsent(K key, V value) {
-        if (table == EMPTY_TABLE) {
-            inflateTable(threshold);
-        }
-        if (key == null) {
-            if (nullKeyEntry == null || nullKeyEntry.value == null) {
-                putForNullKey(value);
-                return null;
-            } else {
-                return nullKeyEntry.value;
-            }
-        }
-        int hash = hash(key);
-        int i = indexFor(hash, table.length);
-        boolean checkIfNeedTree = false; // Might we convert bin to a TreeBin?
-
-        if (table[i] instanceof Entry) {
-            int listSize = 0;
-            Entry<K,V> e = (Entry<K,V>) table[i];
-            for (; e != null; e = (Entry<K,V>)e.next) {
-                if (e.hash == hash && Objects.equals(e.key, key)) {
-                    if (e.value != null) {
-                        return e.value;
-                    }
-                    e.value = value;
-                    e.recordAccess(this);
-                    return null;
-                }
-                listSize++;
-            }
-            // Didn't find, so fall through and call addEntry() to add the
-            // Entry and check for TreeBin conversion.
-            checkIfNeedTree = listSize >= TreeBin.TREE_THRESHOLD;
-        } else if (table[i] != null) {
-            TreeBin e = (TreeBin)table[i];
-            TreeNode p = e.putTreeNode(hash, key, value, null);
-            if (p == null) { // not found, putTreeNode() added a new node
-                modCount++;
-                size++;
-                if (size >= threshold) {
-                    resize(2 * table.length);
-                }
-                return null;
-            } else { // putTreeNode() found an existing node
-                Entry<K,V> pEntry = (Entry<K,V>)p.entry;
-                V oldVal = pEntry.value;
-                if (oldVal == null) { // only replace if maps to null
-                    pEntry.value = value;
-                    pEntry.recordAccess(this);
-                }
-                return oldVal;
-            }
-        }
-        modCount++;
-        addEntry(hash, key, value, i, checkIfNeedTree);
-        return null;
-    }
-
-    @Override
-    public boolean remove(Object key, Object value) {
-        if (size == 0) {
-            return false;
-        }
-        if (key == null) {
-            if (nullKeyEntry != null &&
-                 Objects.equals(nullKeyEntry.value, value)) {
-                removeNullKey();
-                return true;
-            }
-            return false;
-        }
-        int hash = hash(key);
-        int i = indexFor(hash, table.length);
-
-        if (table[i] instanceof Entry) {
-            @SuppressWarnings("unchecked")
-            Entry<K,V> prev = (Entry<K,V>) table[i];
-            Entry<K,V> e = prev;
-            while (e != null) {
-                @SuppressWarnings("unchecked")
-                Entry<K,V> next = (Entry<K,V>) e.next;
-                if (e.hash == hash && Objects.equals(e.key, key)) {
-                    if (!Objects.equals(e.value, value)) {
-                        return false;
-                    }
-                    modCount++;
-                    size--;
-                    if (prev == e)
-                        table[i] = next;
-                    else
-                        prev.next = next;
-                    e.recordRemoval(this);
-                    return true;
-                }
-                prev = e;
-                e = next;
-            }
-        } else if (table[i] != null) {
-            TreeBin tb = ((TreeBin) table[i]);
-            TreeNode p = tb.getTreeNode(hash, (K)key);
-            if (p != null) {
-                Entry<K,V> pEntry = (Entry<K,V>)p.entry;
-                // assert pEntry.key.equals(key);
-                if (Objects.equals(pEntry.value, value)) {
-                    modCount++;
-                    size--;
-                    tb.deleteTreeNode(p);
-                    pEntry.recordRemoval(this);
-                    if (tb.root == null || tb.first == null) {
-                        // assert tb.root == null && tb.first == null :
-                        //         "TreeBin.first and root should both be null";
-                        // TreeBin is now empty, we should blank this bin
-                        table[i] = null;
-                    }
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    @Override
-    public boolean replace(K key, V oldValue, V newValue) {
-        if (size == 0) {
-            return false;
-        }
-        if (key == null) {
-            if (nullKeyEntry != null &&
-                 Objects.equals(nullKeyEntry.value, oldValue)) {
-                putForNullKey(newValue);
-                return true;
-            }
-            return false;
-        }
-        int hash = hash(key);
-        int i = indexFor(hash, table.length);
-
-        if (table[i] instanceof Entry) {
-            @SuppressWarnings("unchecked")
-            Entry<K,V> e = (Entry<K,V>) table[i];
-            for (; e != null; e = (Entry<K,V>)e.next) {
-                if (e.hash == hash && Objects.equals(e.key, key) && Objects.equals(e.value, oldValue)) {
-                    e.value = newValue;
-                    e.recordAccess(this);
-                    return true;
-                }
-            }
-            return false;
-        } else if (table[i] != null) {
-            TreeBin tb = ((TreeBin) table[i]);
-            TreeNode p = tb.getTreeNode(hash, key);
-            if (p != null) {
-                Entry<K,V> pEntry = (Entry<K,V>)p.entry;
-                // assert pEntry.key.equals(key);
-                if (Objects.equals(pEntry.value, oldValue)) {
-                    pEntry.value = newValue;
-                    pEntry.recordAccess(this);
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-   @Override
-    public V replace(K key, V value) {
-        if (size == 0) {
-            return null;
-        }
-        if (key == null) {
-            if (nullKeyEntry != null) {
-                return putForNullKey(value);
-            }
-            return null;
-        }
-        int hash = hash(key);
-        int i = indexFor(hash, table.length);
-        if (table[i] instanceof Entry) {
-            @SuppressWarnings("unchecked")
-            Entry<K,V> e = (Entry<K,V>)table[i];
-            for (; e != null; e = (Entry<K,V>)e.next) {
-                if (e.hash == hash && Objects.equals(e.key, key)) {
-                    V oldValue = e.value;
-                    e.value = value;
-                    e.recordAccess(this);
-                    return oldValue;
-                }
-            }
-
-            return null;
-        } else if (table[i] != null) {
-            TreeBin tb = ((TreeBin) table[i]);
-            TreeNode p = tb.getTreeNode(hash, key);
-            if (p != null) {
-                Entry<K,V> pEntry = (Entry<K,V>)p.entry;
-                // assert pEntry.key.equals(key);
-                V oldValue = pEntry.value;
-                pEntry.value = value;
-                pEntry.recordAccess(this);
-                return oldValue;
+            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;
     }
 
-    @Override
-    public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
-        if (table == EMPTY_TABLE) {
-            inflateTable(threshold);
-        }
-        if (key == null) {
-            if (nullKeyEntry == null || nullKeyEntry.value == null) {
-                V newValue = mappingFunction.apply(key);
-                if (newValue != null) {
-                    putForNullKey(newValue);
-                }
-                return newValue;
-            }
-            return nullKeyEntry.value;
-        }
-        int hash = hash(key);
-        int i = indexFor(hash, table.length);
-        boolean checkIfNeedTree = false; // Might we convert bin to a TreeBin?
-
-        if (table[i] instanceof Entry) {
-            int listSize = 0;
-            @SuppressWarnings("unchecked")
-            Entry<K,V> e = (Entry<K,V>)table[i];
-            for (; e != null; e = (Entry<K,V>)e.next) {
-                if (e.hash == hash && Objects.equals(e.key, key)) {
-                    V oldValue = e.value;
-                    if (oldValue == null) {
-                        V newValue = mappingFunction.apply(key);
-                        if (newValue != null) {
-                            e.value = newValue;
-                            e.recordAccess(this);
-                        }
-                        return newValue;
-                    }
-                    return oldValue;
-                }
-                listSize++;
-            }
-            // Didn't find, fall through to call the mapping function
-            checkIfNeedTree = listSize >= TreeBin.TREE_THRESHOLD;
-        } else if (table[i] != null) {
-            TreeBin e = (TreeBin)table[i];
-            V value = mappingFunction.apply(key);
-            if (value == null) { // Return the existing value, if any
-                TreeNode p = e.getTreeNode(hash, key);
-                if (p != null) {
-                    return (V) p.entry.value;
-                }
-                return null;
-            } else { // Put the new value into the Tree, if absent
-                TreeNode p = e.putTreeNode(hash, key, value, null);
-                if (p == null) { // not found, new node was added
-                    modCount++;
-                    size++;
-                    if (size >= threshold) {
-                        resize(2 * table.length);
-                    }
-                    return value;
-                } else { // putTreeNode() found an existing node
-                    Entry<K,V> pEntry = (Entry<K,V>)p.entry;
-                    V oldVal = pEntry.value;
-                    if (oldVal == null) { // only replace if maps to null
-                        pEntry.value = value;
-                        pEntry.recordAccess(this);
-                        return value;
-                    }
-                    return oldVal;
-                }
-            }
-        }
-        V newValue = mappingFunction.apply(key);
-        if (newValue != null) { // add Entry and check for TreeBin conversion
-            modCount++;
-            addEntry(hash, key, newValue, i, checkIfNeedTree);
-        }
-
-        return newValue;
-    }
-
-    @Override
-    public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
-        if (size == 0) {
-            return null;
-        }
-        if (key == null) {
-            V oldValue;
-            if (nullKeyEntry != null && (oldValue = nullKeyEntry.value) != null) {
-                V newValue = remappingFunction.apply(key, oldValue);
-                if (newValue != null ) {
-                    putForNullKey(newValue);
-                    return newValue;
-                } else {
-                    removeNullKey();
-                }
-            }
-            return null;
-        }
-        int hash = hash(key);
-        int i = indexFor(hash, table.length);
-        if (table[i] instanceof Entry) {
-            @SuppressWarnings("unchecked")
-            Entry<K,V> prev = (Entry<K,V>)table[i];
-            Entry<K,V> e = prev;
-            while (e != null) {
-                Entry<K,V> next = (Entry<K,V>)e.next;
-                if (e.hash == hash && Objects.equals(e.key, key)) {
-                    V oldValue = e.value;
-                    if (oldValue == null)
-                        break;
-                    V newValue = remappingFunction.apply(key, oldValue);
-                    if (newValue == null) {
-                        modCount++;
-                        size--;
-                        if (prev == e)
-                            table[i] = next;
-                        else
-                            prev.next = next;
-                        e.recordRemoval(this);
-                    } else {
-                        e.value = newValue;
-                        e.recordAccess(this);
-                    }
-                    return newValue;
-                }
-                prev = e;
-                e = next;
-            }
-        } else if (table[i] != null) {
-            TreeBin tb = (TreeBin)table[i];
-            TreeNode p = tb.getTreeNode(hash, key);
-            if (p != null) {
-                Entry<K,V> pEntry = (Entry<K,V>)p.entry;
-                // assert pEntry.key.equals(key);
-                V oldValue = pEntry.value;
-                if (oldValue != null) {
-                    V newValue = remappingFunction.apply(key, oldValue);
-                if (newValue == null) { // remove mapping
-                    modCount++;
-                    size--;
-                    tb.deleteTreeNode(p);
-                    pEntry.recordRemoval(this);
-                    if (tb.root == null || tb.first == null) {
-                        // assert tb.root == null && tb.first == null :
-                        //     "TreeBin.first and root should both be null";
-                        // TreeBin is now empty, we should blank this bin
-                        table[i] = null;
-                    }
-                } else {
-                    pEntry.value = newValue;
-                    pEntry.recordAccess(this);
-                }
-                return newValue;
-            }
-        }
-        }
-        return null;
-    }
-
-    @Override
-    public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
-        if (table == EMPTY_TABLE) {
-            inflateTable(threshold);
-        }
-        if (key == null) {
-            V oldValue = nullKeyEntry == null ? null : nullKeyEntry.value;
-            V newValue = remappingFunction.apply(key, oldValue);
-            if (newValue != oldValue || (oldValue == null && nullKeyEntry != null)) {
-                if (newValue == null) {
-                    removeNullKey();
-                } else {
-                    putForNullKey(newValue);
-                }
-            }
-            return newValue;
-        }
-        int hash = hash(key);
-        int i = indexFor(hash, table.length);
-        boolean checkIfNeedTree = false; // Might we convert bin to a TreeBin?
-
-        if (table[i] instanceof Entry) {
-            int listSize = 0;
-            @SuppressWarnings("unchecked")
-            Entry<K,V> prev = (Entry<K,V>)table[i];
-            Entry<K,V> e = prev;
-
-            while (e != null) {
-                Entry<K,V> next = (Entry<K,V>)e.next;
-                if (e.hash == hash && Objects.equals(e.key, key)) {
-                    V oldValue = e.value;
-                    V newValue = remappingFunction.apply(key, oldValue);
-                    if (newValue != oldValue || oldValue == null) {
-                        if (newValue == null) {
-                            modCount++;
-                            size--;
-                            if (prev == e)
-                                table[i] = next;
-                            else
-                                prev.next = next;
-                            e.recordRemoval(this);
-                        } else {
-                            e.value = newValue;
-                            e.recordAccess(this);
-                        }
-                    }
-                    return newValue;
-                }
-                prev = e;
-                e = next;
-                listSize++;
-            }
-            checkIfNeedTree = listSize >= TreeBin.TREE_THRESHOLD;
-        } else if (table[i] != null) {
-            TreeBin tb = (TreeBin)table[i];
-            TreeNode p = tb.getTreeNode(hash, key);
-            V oldValue = p == null ? null : (V)p.entry.value;
-            V newValue = remappingFunction.apply(key, oldValue);
-            if (newValue != oldValue || (oldValue == null && p != null)) {
-                if (newValue == null) {
-                    Entry<K,V> pEntry = (Entry<K,V>)p.entry;
-                    modCount++;
-                    size--;
-                    tb.deleteTreeNode(p);
-                    pEntry.recordRemoval(this);
-                    if (tb.root == null || tb.first == null) {
-                        // assert tb.root == null && tb.first == null :
-                        //         "TreeBin.first and root should both be null";
-                        // TreeBin is now empty, we should blank this bin
-                        table[i] = null;
-                    }
-                } else {
-                    if (p != null) { // just update the value
-                        Entry<K,V> pEntry = (Entry<K,V>)p.entry;
-                        pEntry.value = newValue;
-                        pEntry.recordAccess(this);
-                    } else { // need to put new node
-                        p = tb.putTreeNode(hash, key, newValue, null);
-                        // assert p == null; // should have added a new node
-                        modCount++;
-                        size++;
-                        if (size >= threshold) {
-                            resize(2 * table.length);
-                        }
-                    }
-                }
-            }
-            return newValue;
-        }
-
-        V newValue = remappingFunction.apply(key, null);
-        if (newValue != null) {
-            modCount++;
-            addEntry(hash, key, newValue, i, checkIfNeedTree);
-        }
-
-        return newValue;
-    }
-
-    @Override
-    public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
-        if (table == EMPTY_TABLE) {
-            inflateTable(threshold);
-        }
-        if (key == null) {
-            V oldValue = nullKeyEntry == null ? null : nullKeyEntry.value;
-            V newValue = oldValue == null ? value : remappingFunction.apply(oldValue, value);
-            if (newValue != null) {
-                putForNullKey(newValue);
-            } else if (nullKeyEntry != null) {
-                removeNullKey();
-            }
-            return newValue;
-        }
-        int hash = hash(key);
-        int i = indexFor(hash, table.length);
-        boolean checkIfNeedTree = false; // Might we convert bin to a TreeBin?
-
-        if (table[i] instanceof Entry) {
-            int listSize = 0;
-            @SuppressWarnings("unchecked")
-            Entry<K,V> prev = (Entry<K,V>)table[i];
-            Entry<K,V> e = prev;
-
-            while (e != null) {
-                Entry<K,V> next = (Entry<K,V>)e.next;
-                if (e.hash == hash && Objects.equals(e.key, key)) {
-                    V oldValue = e.value;
-                    V newValue = (oldValue == null) ? value :
-                                 remappingFunction.apply(oldValue, value);
-                    if (newValue == null) {
-                        modCount++;
-                        size--;
-                        if (prev == e)
-                            table[i] = next;
-                        else
-                            prev.next = next;
-                        e.recordRemoval(this);
-                    } else {
-                        e.value = newValue;
-                        e.recordAccess(this);
-                    }
-                    return newValue;
-                }
-                prev = e;
-                e = next;
-                listSize++;
-            }
-            // Didn't find, so fall through and (maybe) call addEntry() to add
-            // the Entry and check for TreeBin conversion.
-            checkIfNeedTree = listSize >= TreeBin.TREE_THRESHOLD;
-        } else if (table[i] != null) {
-            TreeBin tb = (TreeBin)table[i];
-            TreeNode p = tb.getTreeNode(hash, key);
-            V oldValue = p == null ? null : (V)p.entry.value;
-            V newValue = (oldValue == null) ? value :
-                         remappingFunction.apply(oldValue, value);
-            if (newValue == null) {
-                if (p != null) {
-                    Entry<K,V> pEntry = (Entry<K,V>)p.entry;
-                    modCount++;
-                    size--;
-                    tb.deleteTreeNode(p);
-                    pEntry.recordRemoval(this);
-
-                    if (tb.root == null || tb.first == null) {
-                        // assert tb.root == null && tb.first == null :
-                        //         "TreeBin.first and root should both be null";
-                        // TreeBin is now empty, we should blank this bin
-                        table[i] = null;
-                    }
-                }
-                return null;
-            } else if (newValue != oldValue) {
-                if (p != null) { // just update the value
-                    Entry<K,V> pEntry = (Entry<K,V>)p.entry;
-                    pEntry.value = newValue;
-                    pEntry.recordAccess(this);
-                } else { // need to put new node
-                    p = tb.putTreeNode(hash, key, newValue, null);
-                    // assert p == null; // should have added a new node
-                    modCount++;
-                    size++;
-                    if (size >= threshold) {
-                        resize(2 * table.length);
-                    }
-                }
-            }
-            return newValue;
-        }
-        if (value != null) {
-            modCount++;
-            addEntry(hash, key, value, i, checkIfNeedTree);
-        }
-        return value;
-    }
-
-    // end of optimized implementations of default methods in Map
-
-    /**
-     * Removes and returns the entry associated with the specified key
-     * in the HashMap.  Returns null if the HashMap contains no mapping
-     * for this key.
-     *
-     * We don't bother converting TreeBins back to Entry lists if the bin falls
-     * back below TREE_THRESHOLD, but we do clear bins when removing the last
-     * TreeNode in a TreeBin.
-     */
-    final Entry<K,V> removeEntryForKey(Object key) {
-        if (size == 0) {
-            return null;
-        }
-        if (key == null) {
-            if (nullKeyEntry != null) {
-                return removeNullKey();
-            }
-            return null;
-        }
-        int hash = hash(key);
-        int i = indexFor(hash, table.length);
-
-        if (table[i] instanceof Entry) {
-            @SuppressWarnings("unchecked")
-            Entry<K,V> prev = (Entry<K,V>)table[i];
-            Entry<K,V> e = prev;
-
-            while (e != null) {
-                @SuppressWarnings("unchecked")
-                Entry<K,V> next = (Entry<K,V>) e.next;
-                if (e.hash == hash && Objects.equals(e.key, key)) {
-                    modCount++;
-                    size--;
-                    if (prev == e)
-                        table[i] = next;
-                    else
-                        prev.next = next;
-                    e.recordRemoval(this);
-                    return e;
-                }
-                prev = e;
-                e = next;
-            }
-        } else if (table[i] != null) {
-            TreeBin tb = ((TreeBin) table[i]);
-            TreeNode p = tb.getTreeNode(hash, (K)key);
-            if (p != null) {
-                Entry<K,V> pEntry = (Entry<K,V>)p.entry;
-                // assert pEntry.key.equals(key);
-                modCount++;
-                size--;
-                tb.deleteTreeNode(p);
-                pEntry.recordRemoval(this);
-                if (tb.root == null || tb.first == null) {
-                    // assert tb.root == null && tb.first == null :
-                    //             "TreeBin.first and root should both be null";
-                    // TreeBin is now empty, we should blank this bin
-                    table[i] = null;
-                }
-                return pEntry;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Special version of remove for EntrySet using {@code Map.Entry.equals()}
-     * for matching.
-     */
-    final Entry<K,V> removeMapping(Object o) {
-        if (size == 0 || !(o instanceof Map.Entry))
-            return null;
-
-        Map.Entry<?,?> entry = (Map.Entry<?,?>) o;
-        Object key = entry.getKey();
-
-        if (key == null) {
-            if (entry.equals(nullKeyEntry)) {
-                return removeNullKey();
-            }
-            return null;
-        }
-
-        int hash = hash(key);
-        int i = indexFor(hash, table.length);
-
-        if (table[i] instanceof Entry) {
-            @SuppressWarnings("unchecked")
-                Entry<K,V> prev = (Entry<K,V>)table[i];
-            Entry<K,V> e = prev;
-
-            while (e != null) {
-                @SuppressWarnings("unchecked")
-                Entry<K,V> next = (Entry<K,V>)e.next;
-                if (e.hash == hash && e.equals(entry)) {
-                    modCount++;
-                    size--;
-                    if (prev == e)
-                        table[i] = next;
-                    else
-                        prev.next = next;
-                    e.recordRemoval(this);
-                    return e;
-                }
-                prev = e;
-                e = next;
-            }
-        } else if (table[i] != null) {
-            TreeBin tb = ((TreeBin) table[i]);
-            TreeNode p = tb.getTreeNode(hash, (K)key);
-            if (p != null && p.entry.equals(entry)) {
-                @SuppressWarnings("unchecked")
-                Entry<K,V> pEntry = (Entry<K,V>)p.entry;
-                // assert pEntry.key.equals(key);
-                modCount++;
-                size--;
-                tb.deleteTreeNode(p);
-                pEntry.recordRemoval(this);
-                if (tb.root == null || tb.first == null) {
-                    // assert tb.root == null && tb.first == null :
-                    //             "TreeBin.first and root should both be null";
-                    // TreeBin is now empty, we should blank this bin
-                    table[i] = null;
-                }
-                return pEntry;
-            }
-        }
-        return null;
-    }
-
-    /*
-     * Remove the mapping for the null key, and update internal accounting
-     * (size, modcount, recordRemoval, etc).
-     *
-     * Assumes nullKeyEntry is non-null.
-     */
-    private Entry<K,V> removeNullKey() {
-        // assert nullKeyEntry != null;
-        Entry<K,V> retVal = nullKeyEntry;
-        modCount++;
-        size--;
-        retVal.recordRemoval(this);
-        nullKeyEntry = null;
-        return retVal;
-    }
-
     /**
      * 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 (nullKeyEntry != null) {
-            nullKeyEntry = null;
+        if ((tab = table) != null && size > 0) {
+            size = 0;
+            for (int i = 0; i < tab.length; ++i)
+                tab[i] = null;
         }
-        Arrays.fill(table, null);
-        size = 0;
     }
 
     /**
@@ -2134,352 +873,20 @@
      *         specified value
      */
     public boolean containsValue(Object value) {
-        if (value == null) {
-            return containsNullValue();
-        }
-        Object[] tab = table;
-        for (int i = 0; i < tab.length; i++) {
-            if (tab[i] instanceof Entry) {
-                Entry<?,?> e = (Entry<?,?>)tab[i];
-                for (; e != null; e = (Entry<?,?>)e.next) {
-                    if (value.equals(e.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;
-                    }
-                }
-            } else if (tab[i] != null) {
-                TreeBin e = (TreeBin)tab[i];
-                TreeNode p = e.first;
-                for (; p != null; p = (TreeNode) p.entry.next) {
-                    if (value == p.entry.value || value.equals(p.entry.value)) {
-                        return true;
-                    }
                 }
             }
         }
-        // Didn't find value in table - could be in nullKeyEntry
-        return (nullKeyEntry != null && (value == nullKeyEntry.value ||
-                                         value.equals(nullKeyEntry.value)));
+        return false;
     }
 
     /**
-     * Special-case code for containsValue with null argument
-     */
-    private boolean containsNullValue() {
-        Object[] tab = table;
-        for (int i = 0; i < tab.length; i++) {
-            if (tab[i] instanceof Entry) {
-                Entry<K,V> e = (Entry<K,V>)tab[i];
-                for (; e != null; e = (Entry<K,V>)e.next) {
-                    if (e.value == null) {
-                        return true;
-                    }
-                }
-            } else if (tab[i] != null) {
-                TreeBin e = (TreeBin)tab[i];
-                TreeNode p = e.first;
-                for (; p != null; p = (TreeNode) p.entry.next) {
-                    if (p.entry.value == null) {
-                        return true;
-                    }
-                }
-            }
-        }
-        // Didn't find value in table - could be in nullKeyEntry
-        return (nullKeyEntry != null && nullKeyEntry.value == null);
-    }
-
-    /**
-     * 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")
-    public Object clone() {
-        HashMap<K,V> result = null;
-        try {
-            result = (HashMap<K,V>)super.clone();
-        } catch (CloneNotSupportedException e) {
-            // assert false;
-        }
-        if (result.table != EMPTY_TABLE) {
-            result.inflateTable(Math.min(
-                (int) Math.min(
-                    size * Math.min(1 / loadFactor, 4.0f),
-                    // we have limits...
-                    HashMap.MAXIMUM_CAPACITY),
-                table.length));
-        }
-        result.entrySet = null;
-        result.modCount = 0;
-        result.size = 0;
-        result.nullKeyEntry = null;
-        result.init();
-        result.putAllForCreate(this);
-
-        return result;
-    }
-
-    static class Entry<K,V> implements Map.Entry<K,V> {
-        final K key;
-        V value;
-        Object next; // an Entry, or a TreeNode
-        final int hash;
-
-        /**
-         * Creates new entry.
-         */
-        Entry(int h, K k, V v, Object n) {
-            value = v;
-            next = n;
-            key = k;
-            hash = h;
-        }
-
-        public final K getKey() {
-            return key;
-        }
-
-        public final V getValue() {
-            return value;
-        }
-
-        public final V setValue(V newValue) {
-            V oldValue = value;
-            value = newValue;
-            return oldValue;
-        }
-
-        public final boolean equals(Object o) {
-            if (!(o instanceof Map.Entry))
-                return false;
-            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
-            Object k1 = getKey();
-            Object k2 = e.getKey();
-            if (k1 == k2 || (k1 != null && k1.equals(k2))) {
-                Object v1 = getValue();
-                Object v2 = e.getValue();
-                if (v1 == v2 || (v1 != null && v1.equals(v2)))
-                    return true;
-                }
-            return false;
-        }
-
-        public final int hashCode() {
-            return Objects.hashCode(getKey()) ^ Objects.hashCode(getValue());
-        }
-
-        public final String toString() {
-            return getKey() + "=" + getValue();
-        }
-
-        /**
-         * This method is invoked whenever the value in an entry is
-         * overwritten for a key that's already in the HashMap.
-         */
-        void recordAccess(HashMap<K,V> m) {
-        }
-
-        /**
-         * This method is invoked whenever the entry is
-         * removed from the table.
-         */
-        void recordRemoval(HashMap<K,V> m) {
-        }
-    }
-
-    void addEntry(int hash, K key, V value, int bucketIndex) {
-        addEntry(hash, key, value, bucketIndex, true);
-    }
-
-    /**
-     * Adds a new entry with the specified key, value and hash code to
-     * the specified bucket.  It is the responsibility of this
-     * method to resize the table if appropriate.  The new entry is then
-     * created by calling createEntry().
-     *
-     * Subclass overrides this to alter the behavior of put method.
-     *
-     * If checkIfNeedTree is false, it is known that this bucket will not need
-     * to be converted to a TreeBin, so don't bothering checking.
-     *
-     * Assumes key is not null.
-     */
-    void addEntry(int hash, K key, V value, int bucketIndex, boolean checkIfNeedTree) {
-        // assert key != null;
-        if ((size >= threshold) && (null != table[bucketIndex])) {
-            resize(2 * table.length);
-            hash = hash(key);
-            bucketIndex = indexFor(hash, table.length);
-        }
-        createEntry(hash, key, value, bucketIndex, checkIfNeedTree);
-    }
-
-    /**
-     * Called by addEntry(), and also used when creating entries
-     * as part of Map construction or "pseudo-construction" (cloning,
-     * deserialization).  This version does not check for resizing of the table.
-     *
-     * This method is responsible for converting a bucket to a TreeBin once
-     * TREE_THRESHOLD is reached. However if checkIfNeedTree is false, it is known
-     * that this bucket will not need to be converted to a TreeBin, so don't
-     * bother checking.  The new entry is constructed by calling newEntry().
-     *
-     * Assumes key is not null.
-     *
-     * Note: buckets already converted to a TreeBin don't call this method, but
-     * instead call TreeBin.putTreeNode() to create new entries.
-     */
-    void createEntry(int hash, K key, V value, int bucketIndex, boolean checkIfNeedTree) {
-        // assert key != null;
-        @SuppressWarnings("unchecked")
-            Entry<K,V> e = (Entry<K,V>)table[bucketIndex];
-        table[bucketIndex] = newEntry(hash, key, value, e);
-        size++;
-
-        if (checkIfNeedTree) {
-            int listSize = 0;
-            for (e = (Entry<K,V>) table[bucketIndex]; e != null; e = (Entry<K,V>)e.next) {
-                listSize++;
-                if (listSize >= TreeBin.TREE_THRESHOLD) { // Convert to TreeBin
-                    if (comparableClassFor(key) != null) {
-                        TreeBin t = new TreeBin();
-                        t.populate((Entry)table[bucketIndex]);
-                        table[bucketIndex] = t;
-                    }
-                    break;
-                }
-            }
-        }
-    }
-
-    /*
-     * Factory method to create a new Entry object.
-     */
-    Entry<K,V> newEntry(int hash, K key, V value, Object next) {
-        return new HashMap.Entry<>(hash, key, value, next);
-    }
-
-
-    private abstract class HashIterator<E> implements Iterator<E> {
-        Object next;            // next entry to return, an Entry or a TreeNode
-        int expectedModCount;   // For fast-fail
-        int index;              // current slot
-        Object current;         // current entry, an Entry or a TreeNode
-
-        HashIterator() {
-            expectedModCount = modCount;
-            if (size > 0) { // advance to first entry
-                if (nullKeyEntry != null) {
-                    // assert nullKeyEntry.next == null;
-                    // This works with nextEntry(): nullKeyEntry isa Entry, and
-                    // e.next will be null, so we'll hit the findNextBin() call.
-                    next = nullKeyEntry;
-                } else {
-                    findNextBin();
-                }
-            }
-        }
-
-        public final boolean hasNext() {
-            return next != null;
-        }
-
-        @SuppressWarnings("unchecked")
-        final Entry<K,V> nextEntry() {
-            if (modCount != expectedModCount) {
-                throw new ConcurrentModificationException();
-            }
-            Object e = next;
-            Entry<K,V> retVal;
-
-            if (e == null)
-                throw new NoSuchElementException();
-
-            if (e instanceof TreeNode) { // TreeBin
-                retVal = (Entry<K,V>)((TreeNode)e).entry;
-                next = retVal.next;
-            } else {
-                retVal = (Entry<K,V>)e;
-                next = ((Entry<K,V>)e).next;
-            }
-
-            if (next == null) { // Move to next bin
-                findNextBin();
-            }
-            current = e;
-            return retVal;
-        }
-
-        public void remove() {
-            if (current == null)
-                throw new IllegalStateException();
-            if (modCount != expectedModCount)
-                throw new ConcurrentModificationException();
-            K k;
-
-            if (current instanceof Entry) {
-                k = ((Entry<K,V>)current).key;
-            } else {
-                k = ((Entry<K,V>)((TreeNode)current).entry).key;
-
-            }
-            current = null;
-            HashMap.this.removeEntryForKey(k);
-            expectedModCount = modCount;
-        }
-
-        /*
-         * Set 'next' to the first entry of the next non-empty bin in the table
-         */
-        private void findNextBin() {
-            // assert next == null;
-            Object[] t = table;
-
-            while (index < t.length && (next = t[index++]) == null)
-                ;
-            if (next instanceof HashMap.TreeBin) { // Point to the first TreeNode
-                next = ((TreeBin) next).first;
-                // assert next != null; // There should be no empty TreeBins
-            }
-        }
-    }
-
-    private final class ValueIterator extends HashIterator<V> {
-        public V next() {
-            return nextEntry().value;
-        }
-    }
-
-    private final class KeyIterator extends HashIterator<K> {
-        public K next() {
-            return nextEntry().getKey();
-        }
-    }
-
-    private final class EntryIterator extends HashIterator<Map.Entry<K,V>> {
-        public Map.Entry<K,V> next() {
-            return nextEntry();
-        }
-    }
-
-    // Subclass overrides these to alter behavior of views' iterator() method
-    Iterator<K> newKeyIterator()   {
-        return new KeyIterator();
-    }
-    Iterator<V> newValueIterator()   {
-        return new ValueIterator();
-    }
-    Iterator<Map.Entry<K,V>> newEntryIterator()   {
-        return new EntryIterator();
-    }
-
-
-    // Views
-
-    private transient Set<Map.Entry<K,V>> entrySet = null;
-
-    /**
      * 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
@@ -2491,35 +898,38 @@
      * <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;
-        return (ks != null ? ks : (keySet = new KeySet()));
+        Set<K> ks;
+        return (ks = keySet) == null ? (keySet = new KeySet()) : ks;
     }
 
-    private final class KeySet extends AbstractSet<K> {
-        public Iterator<K> iterator() {
-            return newKeyIterator();
+    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 int size() {
-            return size;
+        public final Spliterator<K> spliterator() {
+            return new KeySpliterator<K,V>(HashMap.this, 0, -1, 0, 0);
         }
-        public boolean contains(Object o) {
-            return containsKey(o);
-        }
-        public boolean remove(Object o) {
-            return HashMap.this.removeEntryForKey(o) != null;
-        }
-        public void clear() {
-            HashMap.this.clear();
-        }
-
-        public Spliterator<K> spliterator() {
-            if (HashMap.this.getClass() == HashMap.class)
-                return new KeySpliterator<K,V>(HashMap.this, 0, -1, 0, 0);
-            else
-                return Spliterators.spliterator
-                        (this, Spliterator.SIZED | Spliterator.DISTINCT);
+        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;
+                for (int i = 0; i < tab.length; ++i) {
+                    for (Node<K,V> e = tab[i]; e != null; e = e.next)
+                        action.accept(e.key);
+                }
+                if (modCount != mc)
+                    throw new ConcurrentModificationException();
+            }
         }
     }
 
@@ -2535,32 +945,35 @@
      * <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;
-        return (vs != null ? vs : (values = new Values()));
+        Collection<V> vs;
+        return (vs = values) == null ? (values = new Values()) : vs;
     }
 
-    private final class Values extends AbstractCollection<V> {
-        public Iterator<V> iterator() {
-            return newValueIterator();
+    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<K,V>(HashMap.this, 0, -1, 0, 0);
         }
-        public int size() {
-            return size;
-        }
-        public boolean contains(Object o) {
-            return containsValue(o);
-        }
-        public void clear() {
-            HashMap.this.clear();
-        }
-
-        public Spliterator<V> spliterator() {
-            if (HashMap.this.getClass() == HashMap.class)
-                return new ValueSpliterator<K,V>(HashMap.this, 0, -1, 0, 0);
-            else
-                return Spliterators.spliterator
-                        (this, Spliterator.SIZED);
+        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;
+                for (int i = 0; i < tab.length; ++i) {
+                    for (Node<K,V> e = tab[i]; e != null; e = e.next)
+                        action.accept(e.value);
+                }
+                if (modCount != mc)
+                    throw new ConcurrentModificationException();
+            }
         }
     }
 
@@ -2581,42 +994,324 @@
      * @return a set view of the mappings contained in this map
      */
     public Set<Map.Entry<K,V>> entrySet() {
-        return entrySet0();
+        Set<Map.Entry<K,V>> es;
+        return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;
     }
 
-    private Set<Map.Entry<K,V>> entrySet0() {
-        Set<Map.Entry<K,V>> es = entrySet;
-        return es != null ? es : (entrySet = new EntrySet());
-    }
-
-    private final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
-        public Iterator<Map.Entry<K,V>> iterator() {
-            return newEntryIterator();
+    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 boolean contains(Object o) {
+        public final boolean contains(Object o) {
             if (!(o instanceof Map.Entry))
                 return false;
             Map.Entry<?,?> e = (Map.Entry<?,?>) o;
-            Entry<K,V> candidate = getEntry(e.getKey());
+            Object key = e.getKey();
+            Node<K,V> candidate = getNode(hash(key), key);
             return candidate != null && candidate.equals(e);
         }
-        public boolean remove(Object o) {
-            return removeMapping(o) != null;
+        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 int size() {
-            return size;
+        public final Spliterator<Map.Entry<K,V>> spliterator() {
+            return new EntrySpliterator<K,V>(HashMap.this, 0, -1, 0, 0);
         }
-        public void clear() {
-            HashMap.this.clear();
+        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;
+                for (int i = 0; i < tab.length; ++i) {
+                    for (Node<K,V> e = tab[i]; e != null; e = e.next)
+                        action.accept(e);
+                }
+                if (modCount != mc)
+                    throw new ConcurrentModificationException();
+            }
         }
+    }
 
-        public Spliterator<Map.Entry<K,V>> spliterator() {
-            if (HashMap.this.getClass() == HashMap.class)
-                return new EntrySpliterator<K,V>(HashMap.this, 0, -1, 0, 0);
+    // Overrides of JDK8 Map extension methods
+
+    public V getOrDefault(Object key, V defaultValue) {
+        Node<K,V> e;
+        return (e = getNode(hash(key), key)) == null ? defaultValue : e.value;
+    }
+
+    public V putIfAbsent(K key, V value) {
+        return putVal(hash(key), key, value, true, true);
+    }
+
+    public boolean remove(Object key, Object value) {
+        return removeNode(hash(key), key, value, true, true) != null;
+    }
+
+    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;
+    }
+
+    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;
+    }
+
+    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 (old != null) {
+            old.value = v;
+            afterNodeAccess(old);
+            return v;
+        }
+        else if (v == null)
+            return null;
+        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) {
+        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
-                return Spliterators.spliterator
-                        (this, Spliterator.SIZED | Spliterator.DISTINCT);
+                removeNode(hash, key, null, false, true);
         }
+        return null;
+    }
+
+    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;
+    }
+
+    public V merge(K key, V value,
+                   BiFunction<? super V, ? 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);
+            }
+        }
+        if (old != null) {
+            V v = remappingFunction.apply(old.value, 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;
+    }
+
+    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;
+            for (int i = 0; i < tab.length; ++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();
+        }
+    }
+
+    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")
+    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;
     }
 
     /**
@@ -2631,118 +1326,143 @@
      *             emitted in no particular order.
      */
     private void writeObject(java.io.ObjectOutputStream s)
-        throws IOException
-    {
+        throws IOException {
+        int buckets = capacity();
         // Write out the threshold, loadfactor, and any hidden stuff
         s.defaultWriteObject();
-
-        // Write out number of buckets
-        if (table==EMPTY_TABLE) {
-            s.writeInt(roundUpToPowerOf2(threshold));
-        } else {
-            s.writeInt(table.length);
-        }
-
-        // Write out size (number of Mappings)
+        s.writeInt(buckets);
         s.writeInt(size);
-
-        // Write out keys and values (alternating)
-        if (size > 0) {
-            for(Map.Entry<K,V> e : entrySet0()) {
-                s.writeObject(e.getKey());
-                s.writeObject(e.getValue());
-            }
-        }
+        internalWriteEntries(s);
     }
 
-    private static final long serialVersionUID = 362498820763181265L;
-
     /**
      * Reconstitute the {@code HashMap} instance from a stream (i.e.,
      * deserialize it).
      */
     private void readObject(java.io.ObjectInputStream s)
-         throws IOException, ClassNotFoundException
-    {
+        throws IOException, ClassNotFoundException {
         // Read in the threshold (ignored), loadfactor, and any hidden stuff
         s.defaultReadObject();
-        if (loadFactor <= 0 || Float.isNaN(loadFactor)) {
+        reinitialize();
+        if (loadFactor <= 0 || Float.isNaN(loadFactor))
             throw new InvalidObjectException("Illegal load factor: " +
-                                               loadFactor);
-        }
-
-        // set other fields that need values
-        if (Holder.USE_HASHSEED) {
-            int seed = ThreadLocalRandom.current().nextInt();
-            Holder.UNSAFE.putIntVolatile(this, Holder.HASHSEED_OFFSET,
-                                         (seed != 0) ? seed : 1);
-        }
-        table = EMPTY_TABLE;
-
-        // Read in number of buckets
-        s.readInt(); // ignored.
-
-        // Read number of mappings
-        int mappings = s.readInt();
+                                             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);
+                                             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;
 
-        // capacity chosen by number of mappings and desired load (if >= 0.25)
-        int capacity = (int) Math.min(
-                mappings * Math.min(1 / loadFactor, 4.0f),
-                // we have limits...
-                HashMap.MAXIMUM_CAPACITY);
-
-        // allocate the bucket array;
-        if (mappings > 0) {
-            inflateTable(capacity);
-        } else {
-            threshold = capacity;
-        }
-
-        init();  // Give subclass a chance to do its thing.
-
-        // 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();
-            putForCreate(key, value);
+            // 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);
+            }
         }
     }
 
-    // These methods are used when serializing HashSets
-    int   capacity()     { return table.length; }
-    float loadFactor()   { return loadFactor;   }
+    /* ------------------------------------------------------------ */
+    // iterators
 
-    /**
-     * Standin until HM overhaul; based loosely on Weak and Identity HM.
-     */
+    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;
-        Object current;             // current node, can be Entry or TreeNode
+        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
-        boolean acceptedNull;       // Have we accepted the null key?
-                                    // Without this, we can't distinguish
-                                    // between being at the very beginning (and
-                                    // needing to accept null), or being at the
-                                    // end of the list in bin 0.  In both cases,
-                                    // current == null && index == 0.
 
         HashMapSpliterator(HashMap<K,V> m, int origin,
-                               int fence, int est,
-                               int expectedModCount) {
+                           int fence, int est,
+                           int expectedModCount) {
             this.map = m;
             this.index = origin;
             this.fence = fence;
             this.est = est;
             this.expectedModCount = expectedModCount;
-            this.acceptedNull = false;
         }
 
         final int getFence() { // initialize fence and size on first use
@@ -2751,7 +1471,8 @@
                 HashMap<K,V> m = map;
                 est = m.size;
                 expectedModCount = m.modCount;
-                hi = fence = m.table.length;
+                Node<K,V>[] tab = m.table;
+                hi = fence = (tab == null) ? 0 : tab.length;
             }
             return hi;
         }
@@ -2772,56 +1493,33 @@
 
         public KeySpliterator<K,V> trySplit() {
             int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
-            if (lo >= mid || current != null) {
-                return null;
-            } else {
-                KeySpliterator<K,V> retVal = new KeySpliterator<K,V>(map, lo,
-                                     index = mid, est >>>= 1, expectedModCount);
-                // Only 'this' Spliterator chould check for null.
-                retVal.acceptedNull = true;
-                return retVal;
-            }
+            return (lo >= mid || current != null) ? null :
+                new KeySpliterator<K,V>(map, lo, index = mid, est >>>= 1,
+                                        expectedModCount);
         }
 
-        @SuppressWarnings("unchecked")
         public void forEachRemaining(Consumer<? super K> action) {
             int i, hi, mc;
             if (action == null)
                 throw new NullPointerException();
             HashMap<K,V> m = map;
-            Object[] tab = m.table;
+            Node<K,V>[] tab = m.table;
             if ((hi = fence) < 0) {
                 mc = expectedModCount = m.modCount;
-                hi = fence = tab.length;
+                hi = fence = (tab == null) ? 0 : tab.length;
             }
             else
                 mc = expectedModCount;
-
-            if (!acceptedNull) {
-                acceptedNull = true;
-                if (m.nullKeyEntry != null) {
-                    action.accept(m.nullKeyEntry.key);
-                }
-            }
-            if (tab.length >= hi && (i = index) >= 0 &&
-                (i < (index = hi) || current != null)) {
-                Object p = current;
+            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) {
+                    if (p == null)
                         p = tab[i++];
-                        if (p instanceof HashMap.TreeBin) {
-                            p = ((HashMap.TreeBin)p).first;
-                        }
-                    } else {
-                        HashMap.Entry<K,V> entry;
-                        if (p instanceof HashMap.Entry) {
-                            entry = (HashMap.Entry<K,V>)p;
-                        } else {
-                            entry = (HashMap.Entry<K,V>)((TreeNode)p).entry;
-                        }
-                        action.accept(entry.key);
-                        p = entry.next;
+                    else {
+                        action.accept(p.key);
+                        p = p.next;
                     }
                 } while (p != null || i < hi);
                 if (m.modCount != mc)
@@ -2829,39 +1527,18 @@
             }
         }
 
-        @SuppressWarnings("unchecked")
         public boolean tryAdvance(Consumer<? super K> action) {
             int hi;
             if (action == null)
                 throw new NullPointerException();
-            Object[] tab = map.table;
-            hi = getFence();
-
-            if (!acceptedNull) {
-                acceptedNull = true;
-                if (map.nullKeyEntry != null) {
-                    action.accept(map.nullKeyEntry.key);
-                    if (map.modCount != expectedModCount)
-                        throw new ConcurrentModificationException();
-                    return true;
-                }
-            }
-            if (tab.length >= hi && index >= 0) {
+            Node<K,V>[] tab = map.table;
+            if (tab != null && tab.length >= (hi = getFence()) && index >= 0) {
                 while (current != null || index < hi) {
-                    if (current == null) {
+                    if (current == null)
                         current = tab[index++];
-                        if (current instanceof HashMap.TreeBin) {
-                            current = ((HashMap.TreeBin)current).first;
-                        }
-                    } else {
-                        HashMap.Entry<K,V> entry;
-                        if (current instanceof HashMap.Entry) {
-                            entry = (HashMap.Entry<K,V>)current;
-                        } else {
-                            entry = (HashMap.Entry<K,V>)((TreeNode)current).entry;
-                        }
-                        K k = entry.key;
-                        current = entry.next;
+                    else {
+                        K k = current.key;
+                        current = current.next;
                         action.accept(k);
                         if (map.modCount != expectedModCount)
                             throw new ConcurrentModificationException();
@@ -2888,56 +1565,33 @@
 
         public ValueSpliterator<K,V> trySplit() {
             int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
-            if (lo >= mid || current != null) {
-                return null;
-            } else {
-                ValueSpliterator<K,V> retVal = new ValueSpliterator<K,V>(map,
-                                 lo, index = mid, est >>>= 1, expectedModCount);
-                // Only 'this' Spliterator chould check for null.
-                retVal.acceptedNull = true;
-                return retVal;
-            }
+            return (lo >= mid || current != null) ? null :
+                new ValueSpliterator<K,V>(map, lo, index = mid, est >>>= 1,
+                                          expectedModCount);
         }
 
-        @SuppressWarnings("unchecked")
         public void forEachRemaining(Consumer<? super V> action) {
             int i, hi, mc;
             if (action == null)
                 throw new NullPointerException();
             HashMap<K,V> m = map;
-            Object[] tab = m.table;
+            Node<K,V>[] tab = m.table;
             if ((hi = fence) < 0) {
                 mc = expectedModCount = m.modCount;
-                hi = fence = tab.length;
+                hi = fence = (tab == null) ? 0 : tab.length;
             }
             else
                 mc = expectedModCount;
-
-            if (!acceptedNull) {
-                acceptedNull = true;
-                if (m.nullKeyEntry != null) {
-                    action.accept(m.nullKeyEntry.value);
-                }
-            }
-            if (tab.length >= hi && (i = index) >= 0 &&
-                (i < (index = hi) || current != null)) {
-                Object p = current;
+            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) {
+                    if (p == null)
                         p = tab[i++];
-                        if (p instanceof HashMap.TreeBin) {
-                            p = ((HashMap.TreeBin)p).first;
-                        }
-                    } else {
-                        HashMap.Entry<K,V> entry;
-                        if (p instanceof HashMap.Entry) {
-                            entry = (HashMap.Entry<K,V>)p;
-                        } else {
-                            entry = (HashMap.Entry<K,V>)((TreeNode)p).entry;
-                        }
-                        action.accept(entry.value);
-                        p = entry.next;
+                    else {
+                        action.accept(p.value);
+                        p = p.next;
                     }
                 } while (p != null || i < hi);
                 if (m.modCount != mc)
@@ -2945,39 +1599,18 @@
             }
         }
 
-        @SuppressWarnings("unchecked")
         public boolean tryAdvance(Consumer<? super V> action) {
             int hi;
             if (action == null)
                 throw new NullPointerException();
-            Object[] tab = map.table;
-            hi = getFence();
-
-            if (!acceptedNull) {
-                acceptedNull = true;
-                if (map.nullKeyEntry != null) {
-                    action.accept(map.nullKeyEntry.value);
-                    if (map.modCount != expectedModCount)
-                        throw new ConcurrentModificationException();
-                    return true;
-                }
-            }
-            if (tab.length >= hi && index >= 0) {
+            Node<K,V>[] tab = map.table;
+            if (tab != null && tab.length >= (hi = getFence()) && index >= 0) {
                 while (current != null || index < hi) {
-                    if (current == null) {
+                    if (current == null)
                         current = tab[index++];
-                        if (current instanceof HashMap.TreeBin) {
-                            current = ((HashMap.TreeBin)current).first;
-                        }
-                    } else {
-                        HashMap.Entry<K,V> entry;
-                        if (current instanceof HashMap.Entry) {
-                            entry = (Entry<K,V>)current;
-                        } else {
-                            entry = (Entry<K,V>)((TreeNode)current).entry;
-                        }
-                        V v = entry.value;
-                        current = entry.next;
+                    else {
+                        V v = current.value;
+                        current = current.next;
                         action.accept(v);
                         if (map.modCount != expectedModCount)
                             throw new ConcurrentModificationException();
@@ -3003,57 +1636,33 @@
 
         public EntrySpliterator<K,V> trySplit() {
             int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
-            if (lo >= mid || current != null) {
-                return null;
-            } else {
-                EntrySpliterator<K,V> retVal = new EntrySpliterator<K,V>(map,
-                                 lo, index = mid, est >>>= 1, expectedModCount);
-                // Only 'this' Spliterator chould check for null.
-                retVal.acceptedNull = true;
-                return retVal;
-            }
+            return (lo >= mid || current != null) ? null :
+                new EntrySpliterator<K,V>(map, lo, index = mid, est >>>= 1,
+                                          expectedModCount);
         }
 
-        @SuppressWarnings("unchecked")
         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;
-            Object[] tab = m.table;
+            Node<K,V>[] tab = m.table;
             if ((hi = fence) < 0) {
                 mc = expectedModCount = m.modCount;
-                hi = fence = tab.length;
+                hi = fence = (tab == null) ? 0 : tab.length;
             }
             else
                 mc = expectedModCount;
-
-            if (!acceptedNull) {
-                acceptedNull = true;
-                if (m.nullKeyEntry != null) {
-                    action.accept(m.nullKeyEntry);
-                }
-            }
-            if (tab.length >= hi && (i = index) >= 0 &&
-                (i < (index = hi) || current != null)) {
-                Object p = current;
+            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) {
+                    if (p == null)
                         p = tab[i++];
-                        if (p instanceof HashMap.TreeBin) {
-                            p = ((HashMap.TreeBin)p).first;
-                        }
-                    } else {
-                        HashMap.Entry<K,V> entry;
-                        if (p instanceof HashMap.Entry) {
-                            entry = (HashMap.Entry<K,V>)p;
-                        } else {
-                            entry = (HashMap.Entry<K,V>)((TreeNode)p).entry;
-                        }
-                        action.accept(entry);
-                        p = entry.next;
-
+                    else {
+                        action.accept(p);
+                        p = p.next;
                     }
                 } while (p != null || i < hi);
                 if (m.modCount != mc)
@@ -3061,38 +1670,18 @@
             }
         }
 
-        @SuppressWarnings("unchecked")
         public boolean tryAdvance(Consumer<? super Map.Entry<K,V>> action) {
             int hi;
             if (action == null)
                 throw new NullPointerException();
-            Object[] tab = map.table;
-            hi = getFence();
-
-            if (!acceptedNull) {
-                acceptedNull = true;
-                if (map.nullKeyEntry != null) {
-                    action.accept(map.nullKeyEntry);
-                    if (map.modCount != expectedModCount)
-                        throw new ConcurrentModificationException();
-                    return true;
-                }
-            }
-            if (tab.length >= hi && index >= 0) {
+            Node<K,V>[] tab = map.table;
+            if (tab != null && tab.length >= (hi = getFence()) && index >= 0) {
                 while (current != null || index < hi) {
-                    if (current == null) {
+                    if (current == null)
                         current = tab[index++];
-                        if (current instanceof HashMap.TreeBin) {
-                            current = ((HashMap.TreeBin)current).first;
-                        }
-                    } else {
-                        HashMap.Entry<K,V> e;
-                        if (current instanceof HashMap.Entry) {
-                            e = (Entry<K,V>)current;
-                        } else {
-                            e = (Entry<K,V>)((TreeNode)current).entry;
-                        }
-                        current = e.next;
+                    else {
+                        Node<K,V> e = current;
+                        current = current.next;
                         action.accept(e);
                         if (map.modCount != expectedModCount)
                             throw new ConcurrentModificationException();
@@ -3108,4 +1697,664 @@
                 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<K,V>(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<K,V>(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<K,V>(hash, key, value, next);
+    }
+
+    // For treeifyBin
+    TreeNode<K,V> replacementTreeNode(Node<K,V> p, Node<K,V> next) {
+        return new TreeNode<K,V>(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.Entry<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 || (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.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;
+        }
+    }
+
 }
--- a/src/share/classes/java/util/LinkedHashMap.java	Fri Sep 06 12:04:18 2013 -0400
+++ b/src/share/classes/java/util/LinkedHashMap.java	Fri Sep 06 12:10:30 2013 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -24,9 +24,12 @@
  */
 
 package java.util;
-import java.io.*;
+
+import java.util.function.Consumer;
 import java.util.function.BiConsumer;
 import java.util.function.BiFunction;
+import java.io.Serializable;
+import java.io.IOException;
 
 /**
  * <p>Hash table and linked list implementation of the <tt>Map</tt> interface,
@@ -57,9 +60,9 @@
  * order they were presented.)
  *
  * <p>A special {@link #LinkedHashMap(int,float,boolean) constructor} is
- * provided to create a <tt>LinkedHashMap</tt> 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
+ * 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 <tt>put</tt> or <tt>get</tt> method
  * results in an access to the corresponding entry (assuming it exists after
  * the invocation completes).  The <tt>putAll</tt> method generates one entry
@@ -155,18 +158,53 @@
  * @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. The name of this
+     * class, LinkedHashMap.Entry, is confusing in several ways in its
+     * current context, but cannot be changed.  Otherwise, even though
+     * it is not exported outside this package, some existing source
+     * code is known to have relied on a symbol resolution corner case
+     * rule in calls to removeEldestEntry that suppressed compilation
+     * errors due to ambiguous usages. So, we keep the name to
+     * preserve unmodified compilability.
+     *
+     * 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 Entry<K,V> extends HashMap.Node<K,V> {
+        Entry<K,V> before, after;
+        Entry(int hash, K key, V value, Node<K,V> next) {
+            super(hash, key, value, next);
+        }
+    }
+
     private static final long serialVersionUID = 3801124242820219131L;
 
     /**
-     * The head of the doubly linked list.
+     * The head (eldest) of the doubly linked list.
      */
-    private transient Entry<K,V> header;
+    transient LinkedHashMap.Entry<K,V> head;
+
+    /**
+     * The tail (youngest) of the doubly linked list.
+     */
+    transient LinkedHashMap.Entry<K,V> tail;
 
     /**
      * The iteration ordering method for this linked hash map: <tt>true</tt>
@@ -174,7 +212,125 @@
      *
      * @serial
      */
-    private final boolean accessOrder;
+    final boolean accessOrder;
+
+    // internal utilities
+
+    // link at the end of list
+    private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
+        LinkedHashMap.Entry<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(LinkedHashMap.Entry<K,V> src,
+                               LinkedHashMap.Entry<K,V> dst) {
+        LinkedHashMap.Entry<K,V> b = dst.before = src.before;
+        LinkedHashMap.Entry<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) {
+        LinkedHashMap.Entry<K,V> p =
+            new LinkedHashMap.Entry<K,V>(hash, key, value, e);
+        linkNodeLast(p);
+        return p;
+    }
+
+    Node<K,V> replacementNode(Node<K,V> p, Node<K,V> next) {
+        LinkedHashMap.Entry<K,V> q = (LinkedHashMap.Entry<K,V>)p;
+        LinkedHashMap.Entry<K,V> t =
+            new LinkedHashMap.Entry<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) {
+        LinkedHashMap.Entry<K,V> q = (LinkedHashMap.Entry<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
+        LinkedHashMap.Entry<K,V> p =
+            (LinkedHashMap.Entry<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
+        LinkedHashMap.Entry<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
+        LinkedHashMap.Entry<K,V> last;
+        if (accessOrder && (last = tail) != e) {
+            LinkedHashMap.Entry<K,V> p =
+                (LinkedHashMap.Entry<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 (LinkedHashMap.Entry<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
@@ -221,8 +377,9 @@
      * @throws NullPointerException if the specified map is null
      */
     public LinkedHashMap(Map<? extends K, ? extends V> m) {
-        super(m);
+        super();
         accessOrder = false;
+        putMapEntries(m, false);
     }
 
     /**
@@ -243,16 +400,6 @@
         this.accessOrder = accessOrder;
     }
 
-    /**
-     * Called by superclass constructors and pseudoconstructors (clone,
-     * readObject) before any entries are inserted into the map.  Initializes
-     * the chain.
-     */
-    @Override
-    void init() {
-        header = new Entry<>(-1, null, null, null);
-        header.before = header.after = header;
-    }
 
     /**
      * Returns <tt>true</tt> if this map maps one or more keys to the
@@ -263,15 +410,10 @@
      *         specified value
      */
     public boolean containsValue(Object value) {
-        // Overridden to take advantage of faster iterator
-        if (value==null) {
-            for (Entry<?,?> e = header.after; e != header; e = e.after)
-                if (e.value==null)
-                    return true;
-        } else {
-            for (Entry<?,?> e = header.after; e != header; e = e.after)
-                if (value.equals(e.value))
-                    return true;
+        for (LinkedHashMap.Entry<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;
     }
@@ -292,10 +434,11 @@
      * distinguish these two cases.
      */
     public V get(Object key) {
-        Entry<K,V> e = (Entry<K,V>)getEntry(key);
-        if (e == null)
+        Node<K,V> e;
+        if ((e = getNode(hash(key), key)) == null)
             return null;
-        e.recordAccess(this);
+        if (accessOrder)
+            afterNodeAccess(e);
         return e.value;
     }
 
@@ -305,163 +448,7 @@
      */
     public void clear() {
         super.clear();
-        header.before = header.after = header;
-    }
-
-    @Override
-    public void forEach(BiConsumer<? super K, ? super V> action) {
-        Objects.requireNonNull(action);
-        int expectedModCount = modCount;
-        for (Entry<K, V> entry = header.after; entry != header; entry = entry.after) {
-            action.accept(entry.key, entry.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 (Entry<K, V> entry = header.after; entry != header; entry = entry.after) {
-            entry.value = function.apply(entry.key, entry.value);
-
-            if (expectedModCount != modCount) {
-                throw new ConcurrentModificationException();
-            }
-        }
-    }
-
-    /**
-     * LinkedHashMap entry.
-     */
-    private static class Entry<K,V> extends HashMap.Entry<K,V> {
-        // These fields comprise the doubly linked list used for iteration.
-        Entry<K,V> before, after;
-
-        Entry(int hash, K key, V value, Object next) {
-            super(hash, key, value, next);
-        }
-
-        /**
-         * Removes this entry from the linked list.
-         */
-        private void remove() {
-            before.after = after;
-            after.before = before;
-        }
-
-        /**
-         * Inserts this entry before the specified existing entry in the list.
-         */
-        private void addBefore(Entry<K,V> existingEntry) {
-            after  = existingEntry;
-            before = existingEntry.before;
-            before.after = this;
-            after.before = this;
-        }
-
-        /**
-         * This method is invoked by the superclass whenever the value
-         * of a pre-existing entry is read by Map.get or modified by Map.put.
-         * If the enclosing Map is access-ordered, it moves the entry
-         * to the end of the list; otherwise, it does nothing.
-         */
-        void recordAccess(HashMap<K,V> m) {
-            LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;
-            if (lm.accessOrder) {
-                lm.modCount++;
-                remove();
-                addBefore(lm.header);
-            }
-        }
-
-        void recordRemoval(HashMap<K,V> m) {
-            remove();
-        }
-    }
-
-    private abstract class LinkedHashIterator<T> implements Iterator<T> {
-        Entry<K,V> nextEntry    = header.after;
-        Entry<K,V> lastReturned = null;
-
-        /**
-         * 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 nextEntry != header;
-        }
-
-        public void remove() {
-            if (lastReturned == null)
-                throw new IllegalStateException();
-            if (modCount != expectedModCount)
-                throw new ConcurrentModificationException();
-
-            LinkedHashMap.this.remove(lastReturned.key);
-            lastReturned = null;
-            expectedModCount = modCount;
-        }
-
-        Entry<K,V> nextEntry() {
-            if (modCount != expectedModCount)
-                throw new ConcurrentModificationException();
-            if (nextEntry == header)
-                throw new NoSuchElementException();
-
-            Entry<K,V> e = lastReturned = nextEntry;
-            nextEntry = e.after;
-            return e;
-        }
-    }
-
-    private class KeyIterator extends LinkedHashIterator<K> {
-        public K next() { return nextEntry().getKey(); }
-    }
-
-    private class ValueIterator extends LinkedHashIterator<V> {
-        public V next() { return nextEntry().value; }
-    }
-
-    private class EntryIterator extends LinkedHashIterator<Map.Entry<K,V>> {
-        public Map.Entry<K,V> next() { return nextEntry(); }
-    }
-
-    // These Overrides alter the behavior of superclass view iterator() methods
-    Iterator<K> newKeyIterator()   { return new KeyIterator();   }
-    Iterator<V> newValueIterator() { return new ValueIterator(); }
-    Iterator<Map.Entry<K,V>> newEntryIterator() { return new EntryIterator(); }
-
-    /**
-     * This override alters behavior of superclass put method. It causes newly
-     * allocated entry to get inserted at the end of the linked list and
-     * removes the eldest entry if appropriate.
-     */
-    @Override
-    void addEntry(int hash, K key, V value, int bucketIndex, boolean checkIfNeedTree) {
-        super.addEntry(hash, key, value, bucketIndex, checkIfNeedTree);
-
-        // Remove eldest entry if instructed
-        Entry<K,V> eldest = header.after;
-        if (removeEldestEntry(eldest)) {
-            removeEntryForKey(eldest.key);
-        }
-    }
-
-    /*
-     * Create a new LinkedHashMap.Entry and setup the before/after pointers
-     */
-    @Override
-    HashMap.Entry<K,V> newEntry(int hash, K key, V value, Object next) {
-        Entry<K,V> newEntry = new Entry<>(hash, key, value, next);
-        newEntry.addBefore(header);
-        return newEntry;
+        head = tail = null;
     }
 
     /**
@@ -475,13 +462,13 @@
      * <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>{@code
+     * <pre>
      *     private static final int MAX_ENTRIES = 100;
      *
      *     protected boolean removeEldestEntry(Map.Entry eldest) {
-     *        return size() > MAX_ENTRIES;
+     *        return size() &gt; MAX_ENTRIES;
      *     }
-     * }</pre>
+     * </pre>
      *
      * <p>This method typically does not modify the map in any way,
      * instead allowing the map to modify itself as directed by its
@@ -508,4 +495,241 @@
     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;
+        return (ks = keySet) == null ? (keySet = new LinkedKeySet()) : 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;
+            for (LinkedHashMap.Entry<K,V> e = head; e != null; 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;
+        return (vs = values) == null ? (values = new LinkedValues()) : 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;
+            for (LinkedHashMap.Entry<K,V> e = head; e != null; 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;
+            for (LinkedHashMap.Entry<K,V> e = head; e != null; 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;
+        for (LinkedHashMap.Entry<K,V> e = head; 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;
+        for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
+            e.value = function.apply(e.key, e.value);
+        if (modCount != mc)
+            throw new ConcurrentModificationException();
+    }
+
+    // Iterators
+
+    abstract class LinkedHashIterator {
+        LinkedHashMap.Entry<K,V> next;
+        LinkedHashMap.Entry<K,V> current;
+        int expectedModCount;
+
+        LinkedHashIterator() {
+            next = head;
+            expectedModCount = modCount;
+            current = null;
+        }
+
+        public final boolean hasNext() {
+            return next != null;
+        }
+
+        final LinkedHashMap.Entry<K,V> nextNode() {
+            LinkedHashMap.Entry<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(); }
+    }
+
+
 }
--- a/src/share/classes/java/util/Random.java	Fri Sep 06 12:04:18 2013 -0400
+++ b/src/share/classes/java/util/Random.java	Fri Sep 06 12:10:30 2013 -0400
@@ -26,9 +26,13 @@
 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;
 
@@ -85,6 +89,13 @@
     private static final long addend = 0xBL;
     private static final long mask = (1L << 48) - 1;
 
+    private static final double DOUBLE_UNIT = 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
@@ -222,6 +233,82 @@
     }
 
     /**
+     * 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
@@ -247,23 +334,23 @@
      * 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 n} possible
+     * is pseudorandomly generated and returned.  All {@code bound} possible
      * {@code int} values are produced with (approximately) equal
-     * probability.  The method {@code nextInt(int n)} is implemented by
+     * probability.  The method {@code nextInt(int bound)} is implemented by
      * class {@code Random} as if by:
      *  <pre> {@code
-     * public int nextInt(int n) {
-     *   if (n <= 0)
-     *     throw new IllegalArgumentException("n must be positive");
+     * public int nextInt(int bound) {
+     *   if (bound <= 0)
+     *     throw new IllegalArgumentException("bound must be positive");
      *
-     *   if ((n & -n) == n)  // i.e., n is a power of 2
-     *     return (int)((n * (long)next(31)) >> 31);
+     *   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 % n;
-     *   } while (bits - val + (n-1) < 0);
+     *       val = bits % bound;
+     *   } while (bits - val + (bound-1) < 0);
      *   return val;
      * }}</pre>
      *
@@ -289,28 +376,28 @@
      * 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 n the bound on the random number to be returned.  Must be
-     *        positive.
+     * @param bound the upper bound (exclusive).  Must be positive.
      * @return the next pseudorandom, uniformly distributed {@code int}
-     *         value between {@code 0} (inclusive) and {@code n} (exclusive)
+     *         value between zero (inclusive) and {@code bound} (exclusive)
      *         from this random number generator's sequence
-     * @throws IllegalArgumentException if n is not positive
+     * @throws IllegalArgumentException if bound is not positive
      * @since 1.2
      */
+    public int nextInt(int bound) {
+        if (bound <= 0)
+            throw new IllegalArgumentException(BadBound);
 
-    public int nextInt(int n) {
-        if (n <= 0)
-            throw new IllegalArgumentException("n must be positive");
-
-        if ((n & -n) == n)  // i.e., n is a power of 2
-            return (int)((n * (long)next(31)) >> 31);
-
-        int bits, val;
-        do {
-            bits = next(31);
-            val = bits % n;
-        } while (bits - val + (n-1) < 0);
-        return val;
+        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;
     }
 
     /**
@@ -442,8 +529,7 @@
      * @see Math#random
      */
     public double nextDouble() {
-        return (((long)(next(26)) << 27) + next(27))
-            / (double)(1L << 53);
+        return (((long)(next(26)) << 27) + next(27)) * DOUBLE_UNIT;
     }
 
     private double nextNextGaussian;
@@ -513,57 +599,563 @@
         }
     }
 
+    // stream methods, coded in a way intended to better isolate for
+    // maintenance purposes the small differences across forms.
+
     /**
-     * Returns a stream of pseudorandom, uniformly distributed
-     * {@code integer} values from this random number generator's
-     * sequence. Values are obtained as needed by calling
-     * {@link #nextInt()}.
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code int} values.
      *
-     * @return an infinite stream of {@code integer} 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 IntStream.generate(this::nextInt);
+        return StreamSupport.intStream
+                (new RandomIntsSpliterator
+                         (this, 0L, Long.MAX_VALUE, Integer.MAX_VALUE, 0),
+                 false);
     }
 
     /**
-     * Returns a stream of pseudorandom, uniformly distributed
-     * {@code long} values from this random number generator's
-     * sequence. Values are obtained as needed by calling
-     * {@link #nextLong()}.
+     * Returns a stream producing the given {@code streamSize} number
+     * of pseudorandom {@code int} values, each conforming to the given
+     * origin (inclusive) and bound (exclusive).
      *
-     * @return an infinite stream of {@code long} values
+     * <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 LongStream.generate(this::nextLong);
+        return StreamSupport.longStream
+                (new RandomLongsSpliterator
+                         (this, 0L, Long.MAX_VALUE, Long.MAX_VALUE, 0L),
+                 false);
     }
 
     /**
-     * Returns a stream of pseudorandom, uniformly distributed
-     * {@code double} values between {@code 0.0} and {@code 1.0}
-     * from this random number generator's sequence. Values are
-     * obtained as needed by calling {@link #nextDouble()}.
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code long}, each conforming to the given origin
+     * (inclusive) and bound (exclusive).
      *
-     * @return an infinite stream of {@code double} values
+     * <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 DoubleStream.generate(this::nextDouble);
+        return StreamSupport.doubleStream
+                (new RandomDoublesSpliterator
+                         (this, 0L, Long.MAX_VALUE, Double.MAX_VALUE, 0.0),
+                 false);
     }
 
     /**
-     * Returns a stream of pseudorandom, Gaussian ("normally")
-     * distributed {@code double} values with mean {@code 0.0}
-     * and standard deviation {@code 1.0} from this random number
-     * generator's sequence. Values are obtained as needed by
-     * calling {@link #nextGaussian()}.
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code double} values, each conforming to the given origin
+     * (inclusive) and bound (exclusive).
      *
-     * @return an infinite stream of {@code double} values
+     * <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 gaussians() {
-        return DoubleStream.generate(this::nextGaussian);
+    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);
+            }
+        }
     }
 
     /**
--- a/src/share/classes/java/util/concurrent/ThreadLocalRandom.java	Fri Sep 06 12:04:18 2013 -0400
+++ b/src/share/classes/java/util/concurrent/ThreadLocalRandom.java	Fri Sep 06 12:10:30 2013 -0400
@@ -37,11 +37,16 @@
 
 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
@@ -64,6 +69,10 @@
  * <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.
+ *
  * @since 1.7
  * @author Doug Lea
  */
@@ -85,28 +94,26 @@
      * 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.
-     * The base functionality of Random methods is conveniently
-     * isolated in method next(bits), that just reads and writes the
-     * Thread field rather than its own field.  However, 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.
+     * 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.
      *
-     * Per-thread initialization is similar to that in the no-arg
-     * Random constructor, but we avoid correlation among not only
-     * initial seeds of those created in different threads, but also
-     * those created using class Random itself; while at the same time
-     * not changing any statistical properties.  So we use the same
-     * underlying multiplicative sequence, but start the sequence far
-     * away from the base version, and then merge (xor) current time
-     * and per-thread probe bits to generate initial values.
+     * 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
@@ -115,24 +122,51 @@
      * but we provide identical statistical properties.
      */
 
-    // same constants as Random, but must be redeclared because private
-    private static final long multiplier = 0x5DEECE66DL;
-    private static final long addend = 0xBL;
-    private static final long mask = (1L << 48) - 1;
-    private static final int PROBE_INCREMENT = 0x61c88647;
-
-    /** Generates the basis for per-thread initial seed values */
-    private static final AtomicLong seedGenerator =
-        new AtomicLong(1269533684904616924L);
-
     /** Generates per-thread initialization/probe field */
     private static final AtomicInteger probeGenerator =
-        new AtomicInteger(0xe80f8647);
+        new AtomicInteger();
+
+    /**
+     * The next seed for default constructors.
+     */
+    private static final AtomicLong seeder =
+        new AtomicLong(mix64(System.currentTimeMillis()) ^
+                       mix64(System.nanoTime()));
+
+    /**
+     * 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 = 1.0 / (1L << 53);
+    private static final float  FLOAT_UNIT  = 1.0f / (1 << 24);
 
     /** Rarely-used holder for the second of a pair of Gaussians */
     private static final ThreadLocal<Double> nextLocalGaussian =
         new ThreadLocal<Double>();
 
+    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.
@@ -155,16 +189,11 @@
      * rely on (static) atomic generators to initialize the values.
      */
     static final void localInit() {
-        int p = probeGenerator.getAndAdd(PROBE_INCREMENT);
+        int p = probeGenerator.addAndGet(PROBE_INCREMENT);
         int probe = (p == 0) ? 1 : p; // skip 0
-        long current, next;
-        do { // same sequence as j.u.Random but different initial value
-            current = seedGenerator.get();
-            next = current * 181783497276652981L;
-        } while (!seedGenerator.compareAndSet(current, next));
-        long r = next ^ ((long)probe << 32) ^ System.nanoTime();
+        long seed = mix64(seeder.getAndAdd(SEEDER_INCREMENT));
         Thread t = Thread.currentThread();
-        UNSAFE.putLong(t, SEED, r);
+        UNSAFE.putLong(t, SEED, seed);
         UNSAFE.putInt(t, PROBE, probe);
     }
 
@@ -191,124 +220,264 @@
             throw new UnsupportedOperationException();
     }
 
+    final long nextSeed() {
+        Thread t; long r; // read and update per-thread seed
+        UNSAFE.putLong(t = Thread.currentThread(), SEED,
+                       r = UNSAFE.getLong(t, SEED) + GAMMA);
+        return r;
+    }
+
+    // We must define this, but never use it.
     protected int next(int bits) {
-        Thread t; long r; // read and update per-thread seed
-        UNSAFE.putLong
-            (t = Thread.currentThread(), SEED,
-             r = (UNSAFE.getLong(t, SEED) * multiplier + addend) & mask);
-        return (int) (r >>> (48-bits));
+        return (int)(mix64(nextSeed()) >>> (64 - bits));
+    }
+
+    // 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";
+
+    /**
+     * 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;
     }
 
     /**
-     * Returns a pseudorandom, uniformly distributed value between the
-     * given least value (inclusive) and bound (exclusive).
+     * The form of nextInt used by IntStream Spliterators.
+     * Exactly the same as long version, except for types.
      *
-     * @param least the least value returned
-     * @param bound the upper bound (exclusive)
-     * @throws IllegalArgumentException if least greater than or equal
-     * to bound
-     * @return the next value
+     * @param origin the least value, unless greater than bound
+     * @param bound the upper bound (exclusive), must not equal origin
+     * @return a pseudorandom value
      */
-    public int nextInt(int least, int bound) {
-        if (least >= bound)
-            throw new IllegalArgumentException();
-        return nextInt(bound - least) + least;
+    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;
     }
 
     /**
-     * Returns a pseudorandom, uniformly distributed value
-     * between 0 (inclusive) and the specified value (exclusive).
+     * The form of nextDouble used by DoubleStream Spliterators.
      *
-     * @param n the bound on the random number to be returned.  Must be
-     *        positive.
-     * @return the next value
-     * @throws IllegalArgumentException if n is not positive
+     * @param origin the least value, unless greater than bound
+     * @param bound the upper bound (exclusive), must not equal origin
+     * @return a pseudorandom value
      */
-    public long nextLong(long n) {
-        if (n <= 0)
-            throw new IllegalArgumentException("n must be positive");
-        // Divide n by two until small enough for nextInt. On each
-        // iteration (at most 31 of them but usually much less),
-        // randomly choose both whether to include high bit in result
-        // (offset) and whether to continue with the lower vs upper
-        // half (which makes a difference only if odd).
-        long offset = 0;
-        while (n >= Integer.MAX_VALUE) {
-            int bits = next(2);
-            long half = n >>> 1;
-            long nextn = ((bits & 2) == 0) ? half : n - half;
-            if ((bits & 1) == 0)
-                offset += n - nextn;
-            n = nextn;
+    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 offset + nextInt((int) n);
-    }
-
-    @Override
-    public IntStream ints() {
-        return IntStream.generate(() -> current().nextInt());
-    }
-
-    @Override
-    public LongStream longs() {
-        return LongStream.generate(() -> current().nextLong());
-    }
-
-    @Override
-    public DoubleStream doubles() {
-        return DoubleStream.generate(() -> current().nextDouble());
-    }
-
-    @Override
-    public DoubleStream gaussians() {
-        return DoubleStream.generate(() -> current().nextGaussian());
+        return r;
     }
 
     /**
-     * Returns a pseudorandom, uniformly distributed value between the
-     * given least value (inclusive) and bound (exclusive).
+     * Returns a pseudorandom {@code int} value.
      *
-     * @param least the least value returned
-     * @param bound the upper bound (exclusive)
-     * @return the next value
-     * @throws IllegalArgumentException if least greater than or equal
-     * to bound
+     * @return a pseudorandom {@code int} value
      */
-    public long nextLong(long least, long bound) {
-        if (least >= bound)
-            throw new IllegalArgumentException();
-        return nextLong(bound - least) + least;
+    public int nextInt() {
+        return mix32(nextSeed());
     }
 
     /**
-     * Returns a pseudorandom, uniformly distributed {@code double} value
-     * between 0 (inclusive) and the specified value (exclusive).
+     * Returns a pseudorandom {@code int} value between zero (inclusive)
+     * and the specified bound (exclusive).
      *
-     * @param n the bound on the random number to be returned.  Must be
-     *        positive.
-     * @return the next value
-     * @throws IllegalArgumentException if n is not positive
+     * @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 double nextDouble(double n) {
-        if (n <= 0)
-            throw new IllegalArgumentException("n must be positive");
-        return nextDouble() * n;
+    public int nextInt(int bound) {
+        if (bound <= 0)
+            throw new IllegalArgumentException(BadBound);
+        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, uniformly distributed value between the
-     * given least value (inclusive) and bound (exclusive).
+     * Returns a pseudorandom {@code int} value between the specified
+     * origin (inclusive) and the specified bound (exclusive).
      *
-     * @param least the least value returned
+     * @param origin the least value returned
      * @param bound the upper bound (exclusive)
-     * @return the next value
-     * @throws IllegalArgumentException if least greater than or equal
-     * to bound
+     * @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 double nextDouble(double least, double bound) {
-        if (least >= bound)
-            throw new IllegalArgumentException();
-        return nextDouble() * (bound - least) + least;
+    public int nextInt(int origin, int bound) {
+        if (origin >= bound)
+            throw new IllegalArgumentException(BadRange);
+        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(BadBound);
+        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(BadRange);
+        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(BadBound);
+        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(BadRange);
+        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() {
@@ -329,6 +498,445 @@
         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(BadSize);
+        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(BadSize);
+        if (randomNumberOrigin >= randomNumberBound)
+            throw new IllegalArgumentException(BadRange);
+        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(BadRange);
+        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(BadSize);
+        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(BadSize);
+        if (randomNumberOrigin >= randomNumberBound)
+            throw new IllegalArgumentException(BadRange);
+        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(BadRange);
+        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(BadSize);
+        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(BadSize);
+        if (!(randomNumberOrigin < randomNumberBound))
+            throw new IllegalArgumentException(BadRange);
+        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(BadRange);
+        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.
+     */
+    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.
+     */
+    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.
+     */
+    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
 
     /*
@@ -401,23 +1009,26 @@
      */
     private static final ObjectStreamField[] serialPersistentFields = {
             new ObjectStreamField("rnd", long.class),
-            new ObjectStreamField("initialized", boolean.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 out)
+    private void writeObject(java.io.ObjectOutputStream s)
         throws java.io.IOException {
 
-        java.io.ObjectOutputStream.PutField fields = out.putFields();
+        java.io.ObjectOutputStream.PutField fields = s.putFields();
         fields.put("rnd", UNSAFE.getLong(Thread.currentThread(), SEED));
         fields.put("initialized", true);
-        out.writeFields();
+        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();
--- a/src/share/classes/java/util/concurrent/atomic/AtomicLongArray.java	Fri Sep 06 12:04:18 2013 -0400
+++ b/src/share/classes/java/util/concurrent/atomic/AtomicLongArray.java	Fri Sep 06 12:10:30 2013 -0400
@@ -303,7 +303,7 @@
      * @return the previous value
      * @since 1.8
      */
-    public final long getAndAccumulate(int i, int x,
+    public final long getAndAccumulate(int i, long x,
                                       LongBinaryOperator accumulatorFunction) {
         long offset = checkedByteOffset(i);
         long prev, next;
@@ -329,7 +329,7 @@
      * @return the updated value
      * @since 1.8
      */
-    public final long accumulateAndGet(int i, int x,
+    public final long accumulateAndGet(int i, long x,
                                       LongBinaryOperator accumulatorFunction) {
         long offset = checkedByteOffset(i);
         long prev, next;
--- a/src/share/classes/java/util/logging/ConsoleHandler.java	Fri Sep 06 12:04:18 2013 -0400
+++ b/src/share/classes/java/util/logging/ConsoleHandler.java	Fri Sep 06 12:10:30 2013 -0400
@@ -26,9 +26,6 @@
 
 package java.util.logging;
 
-import java.io.*;
-import java.net.*;
-
 /**
  * This <tt>Handler</tt> publishes log records to <tt>System.err</tt>.
  * By default the <tt>SimpleFormatter</tt> is used to generate brief summaries.
@@ -114,6 +111,7 @@
      * @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();
@@ -124,6 +122,7 @@
      * to close the output stream.  That is, we do <b>not</b>
      * close <tt>System.err</tt>.
      */
+    @Override
     public void close() {
         flush();
     }
--- a/src/share/classes/java/util/logging/FileHandler.java	Fri Sep 06 12:04:18 2013 -0400
+++ b/src/share/classes/java/util/logging