Merge
authorduke
Wed, 05 Jul 2017 18:34:47 +0200
changeset 14967 a3f11e8a60ae
parent 14966 3849a5b1c05c (current diff)
parent 14946 0cb9ff04c620 (diff)
child 14968 a41ada2ed4ef
Merge
jdk/make/jdk/asm/Makefile
--- a/.hgtags-top-repo	Fri Dec 28 18:39:09 2012 -0800
+++ b/.hgtags-top-repo	Wed Jul 05 18:34:47 2017 +0200
@@ -191,3 +191,4 @@
 9a6ec97ec45c1a62d5233cefa91e8390e380e13a jdk8-b67
 cdb401a60cea6ad5ef3f498725ed1decf8dda1ea jdk8-b68
 6ee8080a6efe0639fcd00627a5e0f839bf010481 jdk8-b69
+105a25ffa4a4f0af70188d4371b4a0385009b7ce jdk8-b70
--- a/common/makefiles/javadoc/NON_CORE_PKGS.gmk	Fri Dec 28 18:39:09 2012 -0800
+++ b/common/makefiles/javadoc/NON_CORE_PKGS.gmk	Wed Jul 05 18:34:47 2017 +0200
@@ -78,7 +78,8 @@
 
 JCONSOLE_PKGS    = com.sun.tools.jconsole
 
-TREEAPI_PKGS 	 = com.sun.source.tree \
+TREEAPI_PKGS 	 = com.sun.source.doctree \
+		   com.sun.source.tree \
 		   com.sun.source.util
 
 SMARTCARDIO_PKGS = javax.smartcardio
--- a/corba/.hgtags	Fri Dec 28 18:39:09 2012 -0800
+++ b/corba/.hgtags	Wed Jul 05 18:34:47 2017 +0200
@@ -191,3 +191,4 @@
 394515ad2a55d4d54df990b36065505d3e7a3cbb jdk8-b67
 82000531feaa7baef76b6406099e5cd88943d635 jdk8-b68
 22ddcac208a8dea894a16887d04f3ca4d3c5d267 jdk8-b69
+603cceb495c8133d47b26a7502d51c7d8a67d76b jdk8-b70
--- a/hotspot/.hgtags	Fri Dec 28 18:39:09 2012 -0800
+++ b/hotspot/.hgtags	Wed Jul 05 18:34:47 2017 +0200
@@ -303,3 +303,4 @@
 b6c9c0109a608eedbb6b868d260952990e3c91fe hs25-b13
 cb8a4e04bc8c104de8a2f67463c7e31232bf8d68 jdk8-b69
 990bbd393c239d95310ccc38094e57923bbf1d4a hs25-b14
+e94068d4ff52849c8aa0786a53a59b63d1312a39 jdk8-b70
--- a/jaxp/.hgtags	Fri Dec 28 18:39:09 2012 -0800
+++ b/jaxp/.hgtags	Wed Jul 05 18:34:47 2017 +0200
@@ -191,3 +191,4 @@
 83df3493ca3cf0be077f1d0dd90119456f266f54 jdk8-b67
 b854e70084214e9dcf1b37373f6e4b1a68760e03 jdk8-b68
 789a855de959f7e9600e57759c6c3dbb0b24d78b jdk8-b69
+6ec9edffc286c9c9ac96c9cd2050b01cb5d514a8 jdk8-b70
--- a/jaxp/src/com/sun/org/apache/xalan/internal/xslt/EnvironmentCheck.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jaxp/src/com/sun/org/apache/xalan/internal/xslt/EnvironmentCheck.java	Wed Jul 05 18:34:47 2017 +0200
@@ -1005,7 +1005,7 @@
     {
       Class clazz = ObjectFactory.findProviderClass(DOM_CLASS, true);
 
-      Method method = clazz.getMethod(DOM_LEVEL3_METHOD, null);
+      Method method = clazz.getMethod(DOM_LEVEL3_METHOD, (Class<?>[])null);
 
       // If we succeeded, we have loaded interfaces from a
       //  level 3 DOM somewhere
--- a/jaxp/src/com/sun/org/apache/xerces/internal/impl/Version.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jaxp/src/com/sun/org/apache/xerces/internal/impl/Version.java	Wed Jul 05 18:34:47 2017 +0200
@@ -74,7 +74,7 @@
 
     /** Version string.
      * @deprecated  getVersion() should be used instead.  */
-    public static String fVersion = "Xerces-J 2.7.1";
+    public static final String fVersion = getVersion();
 
     private static final String fImmutableVersion = "Xerces-J 2.7.1";
 
--- a/jaxp/src/com/sun/org/apache/xerces/internal/impl/XMLDocumentFragmentScannerImpl.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jaxp/src/com/sun/org/apache/xerces/internal/impl/XMLDocumentFragmentScannerImpl.java	Wed Jul 05 18:34:47 2017 +0200
@@ -193,9 +193,12 @@
                 null,
     };
 
-    protected static final char [] cdata = {'[','C','D','A','T','A','['};
-    protected static final char [] xmlDecl = {'<','?','x','m','l'};
-    protected static final char [] endTag = {'<','/'};
+    private static final char [] cdata = {'[','C','D','A','T','A','['};
+    private static final char [] endTag = {'<','/'};
+
+    //this variable is also used by XMLDocumentScannerImpl in the same package
+    static final char [] xmlDecl = {'<','?','x','m','l'};
+
     // debugging
 
     /** Debug scanner state. */
--- a/jaxp/src/com/sun/org/apache/xerces/internal/impl/XMLEntityScanner.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jaxp/src/com/sun/org/apache/xerces/internal/impl/XMLEntityScanner.java	Wed Jul 05 18:34:47 2017 +0200
@@ -71,7 +71,7 @@
     /** Listeners which should know when load is being called */
     private Vector listeners = new Vector();
 
-    public static final boolean [] VALID_NAMES = new boolean[127];
+    private static final boolean [] VALID_NAMES = new boolean[127];
 
     /**
      * Debug printing of buffer. This debugging flag works best when you
--- a/jaxp/src/javax/xml/transform/FactoryFinder.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jaxp/src/javax/xml/transform/FactoryFinder.java	Wed Jul 05 18:34:47 2017 +0200
@@ -210,7 +210,7 @@
                 providerClass.getDeclaredMethod(
                     "newTransformerFactoryNoServiceLoader"
                 );
-                return creationMethod.invoke(null, null);
+                return creationMethod.invoke(null, (Object[])null);
             } catch (NoSuchMethodException exc) {
                 return null;
             } catch (Exception exc) {
--- a/jaxp/src/javax/xml/validation/SchemaFactoryFinder.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jaxp/src/javax/xml/validation/SchemaFactoryFinder.java	Wed Jul 05 18:34:47 2017 +0200
@@ -357,7 +357,7 @@
                 providerClass.getDeclaredMethod(
                     "newXMLSchemaFactoryNoServiceLoader"
                 );
-                return creationMethod.invoke(null, null);
+                return creationMethod.invoke(null, (Object[])null);
             } catch (NoSuchMethodException exc) {
                 return null;
             } catch (Exception exc) {
--- a/jaxp/src/javax/xml/xpath/XPathFactoryFinder.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jaxp/src/javax/xml/xpath/XPathFactoryFinder.java	Wed Jul 05 18:34:47 2017 +0200
@@ -333,7 +333,7 @@
                 providerClass.getDeclaredMethod(
                     "newXPathFactoryNoServiceLoader"
                 );
-                return creationMethod.invoke(null, null);
+                return creationMethod.invoke(null, (Object[])null);
             } catch (NoSuchMethodException exc) {
                 return null;
             } catch (Exception exc) {
--- a/jaxws/.hgtags	Fri Dec 28 18:39:09 2012 -0800
+++ b/jaxws/.hgtags	Wed Jul 05 18:34:47 2017 +0200
@@ -191,3 +191,4 @@
 eb06aa51dfc225614dba2d89ae7ca6cedddff982 jdk8-b67
 d3fe408f3a9ad250bc9a4e9365bdfc3f28c1d3f4 jdk8-b68
 756323c990115a9c0341d67b10f2d52c6370e35d jdk8-b69
+3b1c2733d47ee9f8c530925df4041c59f9ee5a31 jdk8-b70
--- a/jdk/.hgtags	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/.hgtags	Wed Jul 05 18:34:47 2017 +0200
@@ -191,3 +191,4 @@
 ce9b02a3a17edd1983201002cfa0f364e4ab7524 jdk8-b67
 53fb43e4d614c92310e1fb00ec41d1960fd9facf jdk8-b68
 a8012d8d7e9c5035de0bdd4887dc9f7c54008f21 jdk8-b69
+a996b57e554198f4592a5f3c30f2f9f4075e545d jdk8-b70
--- a/jdk/make/common/Release.gmk	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/make/common/Release.gmk	Wed Jul 05 18:34:47 2017 +0200
@@ -366,6 +366,7 @@
 	com/sun/source          \
 	com/sun/tools/classfile \
 	com/sun/tools/doclets   \
+	com/sun/tools/doclint   \
 	com/sun/tools/example/debug/expr \
 	com/sun/tools/example/debug/tty  \
 	com/sun/tools/extcheck  \
--- a/jdk/make/common/internal/Defs-langtools.gmk	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/make/common/internal/Defs-langtools.gmk	Wed Jul 05 18:34:47 2017 +0200
@@ -35,6 +35,7 @@
       com/sun/source                \
       com/sun/tools/classfile       \
       com/sun/tools/doclets         \
+      com/sun/tools/doclint         \
       com/sun/tools/javac           \
       com/sun/tools/javadoc         \
       com/sun/tools/javah           \
--- a/jdk/make/docs/NON_CORE_PKGS.gmk	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/make/docs/NON_CORE_PKGS.gmk	Wed Jul 05 18:34:47 2017 +0200
@@ -76,7 +76,8 @@
 
 JCONSOLE_PKGS    = com.sun.tools.jconsole
 
-TREEAPI_PKGS 	 = com.sun.source.tree \
+TREEAPI_PKGS 	 = com.sunsource.doctree \
+		   com.sun.source.tree \
 		   com.sun.source.util
 
 SMARTCARDIO_PKGS = javax.smartcardio
--- a/jdk/make/java/java/FILES_java.gmk	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/make/java/java/FILES_java.gmk	Wed Jul 05 18:34:47 2017 +0200
@@ -294,6 +294,7 @@
 	java/util/IdentityHashMap.java \
 	java/util/EnumMap.java \
     java/util/Arrays.java \
+    java/util/ArraysParallelSortHelpers.java \
     java/util/DualPivotQuicksort.java \
     java/util/TimSort.java \
     java/util/ComparableTimSort.java \
@@ -322,6 +323,7 @@
     java/util/concurrent/CopyOnWriteArrayList.java \
     java/util/concurrent/CopyOnWriteArraySet.java \
     java/util/concurrent/CountDownLatch.java \
+    java/util/concurrent/CountedCompleter.java \
     java/util/concurrent/CyclicBarrier.java \
     java/util/concurrent/DelayQueue.java \
     java/util/concurrent/Delayed.java \
--- a/jdk/make/jdk/Makefile	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/make/jdk/Makefile	Wed Jul 05 18:34:47 2017 +0200
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -23,16 +23,18 @@
 # questions.
 #
 
-#
-# Makefile for building all of java
-#
-
 BUILDDIR = ..
+PACKAGE = jdk
 PRODUCT = jdk
+JAVAC_LINT_OPTIONS=-Xlint:all
 include $(BUILDDIR)/common/Defs.gmk
 
-SUBDIRS = asm
-include $(BUILDDIR)/common/Subdirs.gmk
+#
+# Files to compile
+#
+AUTO_FILES_JAVA_DIRS = jdk
 
-all build clean clobber::
-	$(SUBDIRS-loop)
+#
+# Rules
+#
+include $(BUILDDIR)/common/Classes.gmk
--- a/jdk/make/jdk/asm/Makefile	Fri Dec 28 18:39:09 2012 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-#
-# Copyright (c) 1995, 2012, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.  Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-BUILDDIR = ../..
-PACKAGE = jdk.internal.org.objectweb.asm
-PRODUCT = jdk
-JAVAC_LINT_OPTIONS=-Xlint:all
-include $(BUILDDIR)/common/Defs.gmk
-
-#
-# Files to compile
-#
-AUTO_FILES_JAVA_DIRS = jdk/internal/org/objectweb/asm
-
-#
-# Rules
-#
-include $(BUILDDIR)/common/Classes.gmk
--- a/jdk/make/netbeans/jmx/build.properties	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/make/netbeans/jmx/build.properties	Wed Jul 05 18:34:47 2017 +0200
@@ -38,6 +38,7 @@
     com/sun/jmx/snmp/
 
 jtreg.tests=\
+    com/sun/jmx/ \
     com/sun/management/ \
     java/lang/management/ \
     javax/management/
--- a/jdk/makefiles/CreateJars.gmk	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/makefiles/CreateJars.gmk	Wed Jul 05 18:34:47 2017 +0200
@@ -729,6 +729,7 @@
 	com/sun/source          \
 	com/sun/tools/classfile \
 	com/sun/tools/doclets   \
+	com/sun/tools/doclint   \
 	com/sun/tools/example/debug/expr \
 	com/sun/tools/example/debug/tty  \
 	com/sun/tools/extcheck  \
--- a/jdk/src/macosx/classes/sun/lwawt/macosx/CEmbeddedFrame.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CEmbeddedFrame.java	Wed Jul 05 18:34:47 2017 +0200
@@ -119,7 +119,9 @@
 
     public void handleWindowFocusEvent(boolean parentWindowActive) {
         this.parentWindowActive = parentWindowActive;
-        if (focused) {
+        // ignore focus "lost" native request as it may mistakenly
+        // deactivate active window (see 8001161)
+        if (focused && parentWindowActive) {
             responder.handleWindowFocusEvent(parentWindowActive, null);
         }
     }
--- a/jdk/src/share/classes/com/sun/jmx/remote/internal/ClientCommunicatorAdmin.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/com/sun/jmx/remote/internal/ClientCommunicatorAdmin.java	Wed Jul 05 18:34:47 2017 +0200
@@ -115,6 +115,7 @@
                     // restarted is failed by another thread
                     throw ioe;
                 }
+                return;
             } else {
                 state = RE_CONNECTING;
                 lock.notifyAll();
@@ -195,7 +196,7 @@
                     if (e instanceof IOException &&
                         !(e instanceof InterruptedIOException)) {
                         try {
-                            restart((IOException)e);
+                            gotIOException((IOException)e);
                         } catch (Exception ee) {
                             logger.warning("Checker-run",
                                            "Failed to check connection: "+ e);
--- a/jdk/src/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java	Wed Jul 05 18:34:47 2017 +0200
@@ -51,6 +51,7 @@
 
 import com.sun.jmx.remote.util.ClassLogger;
 import com.sun.jmx.remote.util.EnvHelp;
+import java.rmi.UnmarshalException;
 
 
 public abstract class ClientNotifForwarder {
@@ -594,10 +595,7 @@
                 }
 
                 return nr;
-            } catch (ClassNotFoundException e) {
-                logger.trace("NotifFetcher.fetchNotifs", e);
-                return fetchOneNotif();
-            } catch (NotSerializableException e) {
+            } catch (ClassNotFoundException | NotSerializableException | UnmarshalException e) {
                 logger.trace("NotifFetcher.fetchNotifs", e);
                 return fetchOneNotif();
             } catch (IOException ioe) {
@@ -619,17 +617,18 @@
            timeout.  This allows us to skip sequence numbers for
            notifications that don't match our filters.  Then we ask
            for one notification.  If that produces a
-           ClassNotFoundException or a NotSerializableException, we
-           increase our sequence number and ask again.  Eventually we
-           will either get a successful notification, or a return with
-           0 notifications.  In either case we can return a
+           ClassNotFoundException, NotSerializableException or
+           UnmarshalException, we increase our sequence number and ask again.
+           Eventually we will either get a successful notification, or a
+           return with 0 notifications.  In either case we can return a
            NotificationResult.  This algorithm works (albeit less
            well) even if the server implementation doesn't optimize a
            request for 0 notifications to skip sequence numbers for
            notifications that don't match our filters.
 
-           If we had at least one ClassNotFoundException, then we
-           must emit a JMXConnectionNotification.LOST_NOTIFS.
+           If we had at least one
+           ClassNotFoundException/NotSerializableException/UnmarshalException,
+           then we must emit a JMXConnectionNotification.LOST_NOTIFS.
         */
         private NotificationResult fetchOneNotif() {
             ClientNotifForwarder cnf = ClientNotifForwarder.this;
@@ -668,23 +667,20 @@
                 try {
                     // 1 notif to skip possible missing class
                     result = cnf.fetchNotifs(startSequenceNumber, 1, 0L);
+                } catch (ClassNotFoundException | NotSerializableException | UnmarshalException e) {
+                    logger.warning("NotifFetcher.fetchOneNotif",
+                                   "Failed to deserialize a notification: "+e.toString());
+                    if (logger.traceOn()) {
+                        logger.trace("NotifFetcher.fetchOneNotif",
+                                     "Failed to deserialize a notification.", e);
+                    }
+
+                    notFoundCount++;
+                    startSequenceNumber++;
                 } catch (Exception e) {
-                    if (e instanceof ClassNotFoundException
-                        || e instanceof NotSerializableException) {
-                        logger.warning("NotifFetcher.fetchOneNotif",
-                                     "Failed to deserialize a notification: "+e.toString());
-                        if (logger.traceOn()) {
-                            logger.trace("NotifFetcher.fetchOneNotif",
-                                         "Failed to deserialize a notification.", e);
-                        }
-
-                        notFoundCount++;
-                        startSequenceNumber++;
-                    } else {
-                        if (!shouldStop())
-                            logger.trace("NotifFetcher.fetchOneNotif", e);
-                        return null;
-                    }
+                    if (!shouldStop())
+                        logger.trace("NotifFetcher.fetchOneNotif", e);
+                    return null;
                 }
             }
 
@@ -692,7 +688,7 @@
                 final String msg =
                     "Dropped " + notFoundCount + " notification" +
                     (notFoundCount == 1 ? "" : "s") +
-                    " because classes were missing locally";
+                    " because classes were missing locally or incompatible";
                 lostNotifs(msg, notFoundCount);
                 // Even if result.getEarliestSequenceNumber() is now greater than
                 // it was initially, meaning some notifs have been dropped
--- a/jdk/src/share/classes/com/sun/jmx/remote/internal/IIOPHelper.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/com/sun/jmx/remote/internal/IIOPHelper.java	Wed Jul 05 18:34:47 2017 +0200
@@ -26,13 +26,8 @@
 package com.sun.jmx.remote.internal;
 
 import java.util.Properties;
+import java.io.IOException;
 import java.rmi.Remote;
-import java.rmi.RemoteException;
-import java.rmi.NoSuchObjectException;
-
-import java.util.Properties;
-import java.rmi.Remote;
-import java.rmi.RemoteException;
 import java.rmi.NoSuchObjectException;
 
 import java.security.AccessController;
@@ -115,9 +110,10 @@
      * Connects the Stub to the given ORB.
      */
     public static void connect(Object stub, Object orb)
-        throws RemoteException
+        throws IOException
     {
-        ensureAvailable();
+        if (proxy == null)
+            throw new IOException("Connection to ORB failed, RMI/IIOP not available");
         proxy.connect(stub, orb);
     }
 
@@ -125,15 +121,17 @@
      * Returns true if the given object is an ORB.
      */
     public static boolean isOrb(Object obj) {
-        ensureAvailable();
-        return proxy.isOrb(obj);
+        return (proxy == null) ? false : proxy.isOrb(obj);
     }
 
     /**
      * Creates, and returns, a new ORB instance.
      */
-    public static Object createOrb(String[] args, Properties props) {
-        ensureAvailable();
+    public static Object createOrb(String[] args, Properties props)
+        throws IOException
+    {
+        if (proxy == null)
+            throw new IOException("ORB initialization failed, RMI/IIOP not available");
         return proxy.createOrb(args, props);
     }
 
@@ -166,24 +164,27 @@
     /**
      * Makes a server object ready to receive remote calls
      */
-    public static void exportObject(Remote obj) throws RemoteException {
-        ensureAvailable();
+    public static void exportObject(Remote obj) throws IOException {
+        if (proxy == null)
+            throw new IOException("RMI object cannot be exported, RMI/IIOP not available");
         proxy.exportObject(obj);
     }
 
     /**
      * Deregisters a server object from the runtime.
      */
-    public static void unexportObject(Remote obj) throws NoSuchObjectException {
-        ensureAvailable();
+    public static void unexportObject(Remote obj) throws IOException {
+        if (proxy == null)
+            throw new NoSuchObjectException("Object not exported");
         proxy.unexportObject(obj);
     }
 
     /**
      * Returns a stub for the given server object.
      */
-    public static Remote toStub(Remote obj) throws NoSuchObjectException {
-        ensureAvailable();
+    public static Remote toStub(Remote obj) throws IOException {
+        if (proxy == null)
+            throw new NoSuchObjectException("Object not exported");
         return proxy.toStub(obj);
     }
 }
--- a/jdk/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java	Wed Jul 05 18:34:47 2017 +0200
@@ -25,16 +25,15 @@
 
 package com.sun.jmx.remote.internal;
 
-import com.sun.jmx.mbeanserver.Util;
 import com.sun.jmx.remote.security.NotificationAccessController;
 import com.sun.jmx.remote.util.ClassLogger;
 import com.sun.jmx.remote.util.EnvHelp;
 import java.io.IOException;
 import java.security.AccessControlContext;
 import java.security.AccessController;
-import java.security.PrivilegedAction;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -291,13 +290,18 @@
     // so that we can know too, and remove the corresponding entry from the listenerMap.
     // See 6957378.
     private void snoopOnUnregister(NotificationResult nr) {
-        Set<IdAndFilter> delegateSet = listenerMap.get(MBeanServerDelegate.DELEGATE_NAME);
-        if (delegateSet == null || delegateSet.isEmpty()) {
-            return;
+        List<IdAndFilter> copy = null;
+        synchronized (listenerMap) {
+            Set<IdAndFilter> delegateSet = listenerMap.get(MBeanServerDelegate.DELEGATE_NAME);
+            if (delegateSet == null || delegateSet.isEmpty()) {
+                return;
+            }
+            copy = new ArrayList<>(delegateSet);
         }
+
         for (TargetedNotification tn : nr.getTargetedNotifications()) {
             Integer id = tn.getListenerID();
-            for (IdAndFilter idaf : delegateSet) {
+            for (IdAndFilter idaf : copy) {
                 if (idaf.id == id) {
                     // This is a notification from the MBeanServerDelegate.
                     Notification n = tn.getNotification();
--- a/jdk/src/share/classes/com/sun/security/auth/login/ConfigFile.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/com/sun/security/auth/login/ConfigFile.java	Wed Jul 05 18:34:47 2017 +0200
@@ -25,41 +25,39 @@
 
 package com.sun.security.auth.login;
 
-import javax.security.auth.AuthPermission;
 import javax.security.auth.login.AppConfigurationEntry;
-import java.io.*;
-import java.util.*;
+import javax.security.auth.login.Configuration;
 import java.net.URI;
-import java.net.URL;
-import java.net.MalformedURLException;
-import java.text.MessageFormat;
-import sun.security.util.Debug;
-import sun.security.util.ResourcesMgr;
-import sun.security.util.PropertyExpander;
+
+// NOTE: As of JDK 8, this class instantiates
+// sun.security.provider.ConfigSpiFile and forwards all methods to that
+// implementation. All implementation fixes and enhancements should be made to
+// sun.security.provider.ConfigSpiFile and not this class.
+// See JDK-8005117 for more information.
 
 /**
  * This class represents a default implementation for
- * <code>javax.security.auth.login.Configuration</code>.
+ * {@code javax.security.auth.login.Configuration}.
  *
  * <p> This object stores the runtime login configuration representation,
  * and is the amalgamation of multiple static login
  * configurations that resides in files.
  * The algorithm for locating the login configuration file(s) and reading their
- * information into this <code>Configuration</code> object is:
+ * information into this {@code Configuration} object is:
  *
  * <ol>
  * <li>
  *   Loop through the security properties,
  *   <i>login.config.url.1</i>, <i>login.config.url.2</i>, ...,
  *   <i>login.config.url.X</i>.
- *   Each property value specifies a <code>URL</code> pointing to a
+ *   Each property value specifies a {@code URL} pointing to a
  *   login configuration file to be loaded.  Read in and load
  *   each configuration.
  *
  * <li>
- *   The <code>java.lang.System</code> property
+ *   The {@code java.lang.System} property
  *   <i>java.security.auth.login.config</i>
- *   may also be set to a <code>URL</code> pointing to another
+ *   may also be set to a {@code URL} pointing to another
  *   login configuration file
  *   (which is the case when a user uses the -D switch at runtime).
  *   If this property is defined, and its use is allowed by the
@@ -80,593 +78,63 @@
  *
  * <p> The configuration syntax supported by this implementation
  * is exactly that syntax specified in the
- * <code>javax.security.auth.login.Configuration</code> class.
+ * {@code javax.security.auth.login.Configuration} class.
  *
  * @see javax.security.auth.login.LoginContext
  * @see java.security.Security security properties
  */
-public class ConfigFile extends javax.security.auth.login.Configuration {
+public class ConfigFile extends Configuration {
 
-    private StreamTokenizer st;
-    private int lookahead;
-    private int linenum;
-    private HashMap<String, LinkedList<AppConfigurationEntry>> configuration;
-    private boolean expandProp = true;
-    private URL url;
-
-    private static Debug debugConfig = Debug.getInstance("configfile");
-    private static Debug debugParser = Debug.getInstance("configparser");
+    private sun.security.provider.ConfigSpiFile configFile;
 
     /**
-     * Create a new <code>Configuration</code> object.
+     * Create a new {@code Configuration} object.
+     *
+     * @throws SecurityException if the {@code Configuration} can not be
+     *                           initialized
      */
     public ConfigFile() {
-        try {
-            init(url);
-        } catch (IOException ioe) {
-            throw (SecurityException)
-                new SecurityException(ioe.getMessage()).initCause(ioe);
-        }
-    }
-
-    /**
-     * Create a new <code>Configuration</code> object from the specified URI.
-     *
-     * @param uri Create a new Configuration object from this URI.
-     */
-    public ConfigFile(URI uri) {
-        // only load config from the specified URI
-        try {
-            url = uri.toURL();
-            init(url);
-        } catch (MalformedURLException mue) {
-            throw (SecurityException)
-                new SecurityException(mue.getMessage()).initCause(mue);
-        } catch (IOException ioe) {
-            throw (SecurityException)
-                new SecurityException(ioe.getMessage()).initCause(ioe);
-        }
+        configFile = new sun.security.provider.ConfigSpiFile();
     }
 
     /**
-     * Read and initialize the entire login Configuration.
-     *
-     * <p>
+     * Create a new {@code Configuration} object from the specified {@code URI}.
      *
-     * @exception IOException if the Configuration can not be initialized. <p>
-     * @exception SecurityException if the caller does not have permission
-     *                          to initialize the Configuration.
+     * @param uri the {@code URI}
+     * @throws SecurityException if the {@code Configuration} can not be
+     *                           initialized
+     * @throws NullPointerException if {@code uri} is null
      */
-    private void init(URL url) throws IOException {
-
-        boolean initialized = false;
-        FileReader fr = null;
-        String sep = File.separator;
-
-        if ("false".equals(System.getProperty("policy.expandProperties"))) {
-            expandProp = false;
-        }
-
-        // new configuration
-        HashMap<String, LinkedList<AppConfigurationEntry>> newConfig =
-                new HashMap<>();
-
-        if (url != null) {
-
-            /**
-             * If the caller specified a URI via Configuration.getInstance,
-             * we only read from that URI
-             */
-            if (debugConfig != null) {
-                debugConfig.println("reading " + url);
-            }
-            init(url, newConfig);
-            configuration = newConfig;
-            return;
-        }
-
-        /**
-         * Caller did not specify URI via Configuration.getInstance.
-         * Read from URLs listed in the java.security properties file.
-         */
-
-        String allowSys = java.security.Security.getProperty
-                                                ("policy.allowSystemProperty");
-
-        if ("true".equalsIgnoreCase(allowSys)) {
-            String extra_config = System.getProperty
-                                        ("java.security.auth.login.config");
-            if (extra_config != null) {
-                boolean overrideAll = false;
-                if (extra_config.startsWith("=")) {
-                    overrideAll = true;
-                    extra_config = extra_config.substring(1);
-                }
-                try {
-                    extra_config = PropertyExpander.expand(extra_config);
-                } catch (PropertyExpander.ExpandException peee) {
-                    MessageFormat form = new MessageFormat
-                        (ResourcesMgr.getString
-                                ("Unable.to.properly.expand.config",
-                                "sun.security.util.AuthResources"));
-                    Object[] source = {extra_config};
-                    throw new IOException(form.format(source));
-                }
-
-                URL configURL = null;
-                try {
-                    configURL = new URL(extra_config);
-                } catch (java.net.MalformedURLException mue) {
-                    File configFile = new File(extra_config);
-                    if (configFile.exists()) {
-                        configURL = configFile.toURI().toURL();
-                    } else {
-                        MessageFormat form = new MessageFormat
-                            (ResourcesMgr.getString
-                                ("extra.config.No.such.file.or.directory.",
-                                "sun.security.util.AuthResources"));
-                        Object[] source = {extra_config};
-                        throw new IOException(form.format(source));
-                    }
-                }
-
-                if (debugConfig != null) {
-                    debugConfig.println("reading "+configURL);
-                }
-                init(configURL, newConfig);
-                initialized = true;
-                if (overrideAll) {
-                    if (debugConfig != null) {
-                        debugConfig.println("overriding other policies!");
-                    }
-                    configuration = newConfig;
-                    return;
-                }
-            }
-        }
-
-        int n = 1;
-        String config_url;
-        while ((config_url = java.security.Security.getProperty
-                                        ("login.config.url."+n)) != null) {
-            try {
-                config_url = PropertyExpander.expand
-                        (config_url).replace(File.separatorChar, '/');
-                if (debugConfig != null) {
-                    debugConfig.println("\tReading config: " + config_url);
-                }
-                init(new URL(config_url), newConfig);
-                initialized = true;
-            } catch (PropertyExpander.ExpandException peee) {
-                MessageFormat form = new MessageFormat
-                        (ResourcesMgr.getString
-                                ("Unable.to.properly.expand.config",
-                                "sun.security.util.AuthResources"));
-                Object[] source = {config_url};
-                throw new IOException(form.format(source));
-            }
-            n++;
-        }
-
-        if (initialized == false && n == 1 && config_url == null) {
-
-            // get the config from the user's home directory
-            if (debugConfig != null) {
-                debugConfig.println("\tReading Policy " +
-                                "from ~/.java.login.config");
-            }
-            config_url = System.getProperty("user.home");
-            String userConfigFile = config_url +
-                      File.separatorChar + ".java.login.config";
-
-            // No longer throws an exception when there's no config file
-            // at all. Returns an empty Configuration instead.
-            if (new File(userConfigFile).exists()) {
-                init(new File(userConfigFile).toURI().toURL(),
-                    newConfig);
-            }
-        }
-
-        configuration = newConfig;
-    }
-
-    private void init(URL config,
-        HashMap<String, LinkedList<AppConfigurationEntry>> newConfig)
-        throws IOException {
-
-        InputStreamReader isr = null;
-        try {
-            isr = new InputStreamReader(getInputStream(config), "UTF-8");
-            readConfig(isr, newConfig);
-        } catch (FileNotFoundException fnfe) {
-            if (debugConfig != null) {
-                debugConfig.println(fnfe.toString());
-            }
-            throw new IOException(ResourcesMgr.getString
-                    ("Configuration.Error.No.such.file.or.directory",
-                    "sun.security.util.AuthResources"));
-        } finally {
-            if (isr != null) {
-                isr.close();
-            }
-        }
-    }
-
-    /**
-     * Retrieve an entry from the Configuration using an application name
-     * as an index.
-     *
-     * <p>
-     *
-     * @param applicationName the name used to index the Configuration.
-     * @return an array of AppConfigurationEntries which correspond to
-     *          the stacked configuration of LoginModules for this
-     *          application, or null if this application has no configured
-     *          LoginModules.
-     */
-    public AppConfigurationEntry[] getAppConfigurationEntry
-    (String applicationName) {
-
-        LinkedList<AppConfigurationEntry> list = null;
-        synchronized (configuration) {
-            list = configuration.get(applicationName);
-        }
-
-        if (list == null || list.size() == 0)
-            return null;
-
-        AppConfigurationEntry[] entries =
-                                new AppConfigurationEntry[list.size()];
-        Iterator<AppConfigurationEntry> iterator = list.iterator();
-        for (int i = 0; iterator.hasNext(); i++) {
-            AppConfigurationEntry e = iterator.next();
-            entries[i] = new AppConfigurationEntry(e.getLoginModuleName(),
-                                                e.getControlFlag(),
-                                                e.getOptions());
-        }
-        return entries;
+    public ConfigFile(URI uri) {
+        configFile = new sun.security.provider.ConfigSpiFile(uri);
     }
 
     /**
-     * Refresh and reload the Configuration by re-reading all of the
-     * login configurations.
+     * Retrieve an entry from the {@code Configuration} using an application
+     * name as an index.
      *
-     * <p>
-     *
-     * @exception SecurityException if the caller does not have permission
-     *                          to refresh the Configuration.
+     * @param applicationName the name used to index the {@code Configuration}
+     * @return an array of {@code AppConfigurationEntry} which correspond to
+     *         the stacked configuration of {@code LoginModule}s for this
+     *         application, or null if this application has no configured
+     *         {@code LoginModule}s.
      */
-    public synchronized void refresh() {
-
-        java.lang.SecurityManager sm = System.getSecurityManager();
-        if (sm != null)
-            sm.checkPermission(new AuthPermission("refreshLoginConfiguration"));
-
-        java.security.AccessController.doPrivileged
-            (new java.security.PrivilegedAction<Void>() {
-            public Void run() {
-                try {
-                    init(url);
-                } catch (java.io.IOException ioe) {
-                    throw (SecurityException) new SecurityException
-                                (ioe.getLocalizedMessage()).initCause(ioe);
-                }
-                return null;
-            }
-        });
-    }
-
-    private void readConfig(Reader reader,
-        HashMap<String, LinkedList<AppConfigurationEntry>> newConfig)
-        throws IOException {
-
-        int linenum = 1;
-
-        if (!(reader instanceof BufferedReader))
-            reader = new BufferedReader(reader);
-
-        st = new StreamTokenizer(reader);
-        st.quoteChar('"');
-        st.wordChars('$', '$');
-        st.wordChars('_', '_');
-        st.wordChars('-', '-');
-        st.lowerCaseMode(false);
-        st.slashSlashComments(true);
-        st.slashStarComments(true);
-        st.eolIsSignificant(true);
-
-        lookahead = nextToken();
-        while (lookahead != StreamTokenizer.TT_EOF) {
-            parseLoginEntry(newConfig);
-        }
-    }
-
-    private void parseLoginEntry(
-        HashMap<String, LinkedList<AppConfigurationEntry>> newConfig)
-        throws IOException {
-
-        String appName;
-        String moduleClass;
-        String sflag;
-        AppConfigurationEntry.LoginModuleControlFlag controlFlag;
-        LinkedList<AppConfigurationEntry> configEntries = new LinkedList<>();
-
-        // application name
-        appName = st.sval;
-        lookahead = nextToken();
-
-        if (debugParser != null) {
-            debugParser.println("\tReading next config entry: " + appName);
-        }
-
-        match("{");
+    @Override
+    public AppConfigurationEntry[] getAppConfigurationEntry
+        (String applicationName) {
 
-        // get the modules
-        while (peek("}") == false) {
-            // get the module class name
-            moduleClass = match("module class name");
-
-            // controlFlag (required, optional, etc)
-            sflag = match("controlFlag");
-            if (sflag.equalsIgnoreCase("REQUIRED"))
-                controlFlag =
-                        AppConfigurationEntry.LoginModuleControlFlag.REQUIRED;
-            else if (sflag.equalsIgnoreCase("REQUISITE"))
-                controlFlag =
-                        AppConfigurationEntry.LoginModuleControlFlag.REQUISITE;
-            else if (sflag.equalsIgnoreCase("SUFFICIENT"))
-                controlFlag =
-                        AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT;
-            else if (sflag.equalsIgnoreCase("OPTIONAL"))
-                controlFlag =
-                        AppConfigurationEntry.LoginModuleControlFlag.OPTIONAL;
-            else {
-                MessageFormat form = new MessageFormat(ResourcesMgr.getString
-                        ("Configuration.Error.Invalid.control.flag.flag",
-                        "sun.security.util.AuthResources"));
-                Object[] source = {sflag};
-                throw new IOException(form.format(source));
-            }
-
-            // get the args
-            HashMap<String, String> options = new HashMap<>();
-            String key;
-            String value;
-            while (peek(";") == false) {
-                key = match("option key");
-                match("=");
-                try {
-                    value = expand(match("option value"));
-                } catch (PropertyExpander.ExpandException peee) {
-                    throw new IOException(peee.getLocalizedMessage());
-                }
-                options.put(key, value);
-            }
-
-            lookahead = nextToken();
-
-            // create the new element
-            if (debugParser != null) {
-                debugParser.println("\t\t" + moduleClass + ", " + sflag);
-                java.util.Iterator<String> i = options.keySet().iterator();
-                while (i.hasNext()) {
-                    key = i.next();
-                    debugParser.println("\t\t\t" +
-                                        key +
-                                        "=" +
-                                        options.get(key));
-                }
-            }
-            AppConfigurationEntry entry = new AppConfigurationEntry
-                                                        (moduleClass,
-                                                        controlFlag,
-                                                        options);
-            configEntries.add(entry);
-        }
-
-        match("}");
-        match(";");
-
-        // add this configuration entry
-        if (newConfig.containsKey(appName)) {
-            MessageFormat form = new MessageFormat(ResourcesMgr.getString
-                ("Configuration.Error.Can.not.specify.multiple.entries.for.appName",
-                "sun.security.util.AuthResources"));
-            Object[] source = {appName};
-            throw new IOException(form.format(source));
-        }
-        newConfig.put(appName, configEntries);
+        return configFile.engineGetAppConfigurationEntry(applicationName);
     }
 
-    private String match(String expect) throws IOException {
-
-        String value = null;
-
-        switch(lookahead) {
-        case StreamTokenizer.TT_EOF:
-
-            MessageFormat form1 = new MessageFormat(ResourcesMgr.getString
-                ("Configuration.Error.expected.expect.read.end.of.file.",
-                "sun.security.util.AuthResources"));
-            Object[] source1 = {expect};
-            throw new IOException(form1.format(source1));
-
-        case '"':
-        case StreamTokenizer.TT_WORD:
-
-            if (expect.equalsIgnoreCase("module class name") ||
-                expect.equalsIgnoreCase("controlFlag") ||
-                expect.equalsIgnoreCase("option key") ||
-                expect.equalsIgnoreCase("option value")) {
-                value = st.sval;
-                lookahead = nextToken();
-            } else {
-                MessageFormat form = new MessageFormat(ResourcesMgr.getString
-                        ("Configuration.Error.Line.line.expected.expect.found.value.",
-                        "sun.security.util.AuthResources"));
-                Object[] source = {new Integer(linenum), expect, st.sval};
-                throw new IOException(form.format(source));
-            }
-            break;
-
-        case '{':
-
-            if (expect.equalsIgnoreCase("{")) {
-                lookahead = nextToken();
-            } else {
-                MessageFormat form = new MessageFormat(ResourcesMgr.getString
-                        ("Configuration.Error.Line.line.expected.expect.",
-                        "sun.security.util.AuthResources"));
-                Object[] source = {new Integer(linenum), expect, st.sval};
-                throw new IOException(form.format(source));
-            }
-            break;
-
-        case ';':
-
-            if (expect.equalsIgnoreCase(";")) {
-                lookahead = nextToken();
-            } else {
-                MessageFormat form = new MessageFormat(ResourcesMgr.getString
-                        ("Configuration.Error.Line.line.expected.expect.",
-                        "sun.security.util.AuthResources"));
-                Object[] source = {new Integer(linenum), expect, st.sval};
-                throw new IOException(form.format(source));
-            }
-            break;
-
-        case '}':
-
-            if (expect.equalsIgnoreCase("}")) {
-                lookahead = nextToken();
-            } else {
-                MessageFormat form = new MessageFormat(ResourcesMgr.getString
-                        ("Configuration.Error.Line.line.expected.expect.",
-                        "sun.security.util.AuthResources"));
-                Object[] source = {new Integer(linenum), expect, st.sval};
-                throw new IOException(form.format(source));
-            }
-            break;
-
-        case '=':
-
-            if (expect.equalsIgnoreCase("=")) {
-                lookahead = nextToken();
-            } else {
-                MessageFormat form = new MessageFormat(ResourcesMgr.getString
-                        ("Configuration.Error.Line.line.expected.expect.",
-                        "sun.security.util.AuthResources"));
-                Object[] source = {new Integer(linenum), expect, st.sval};
-                throw new IOException(form.format(source));
-            }
-            break;
-
-        default:
-            MessageFormat form = new MessageFormat(ResourcesMgr.getString
-                        ("Configuration.Error.Line.line.expected.expect.found.value.",
-                        "sun.security.util.AuthResources"));
-            Object[] source = {new Integer(linenum), expect, st.sval};
-            throw new IOException(form.format(source));
-        }
-        return value;
-    }
-
-    private boolean peek(String expect) {
-        boolean found = false;
-
-        switch (lookahead) {
-        case ',':
-            if (expect.equalsIgnoreCase(","))
-                found = true;
-            break;
-        case ';':
-            if (expect.equalsIgnoreCase(";"))
-                found = true;
-            break;
-        case '{':
-            if (expect.equalsIgnoreCase("{"))
-                found = true;
-            break;
-        case '}':
-            if (expect.equalsIgnoreCase("}"))
-                found = true;
-            break;
-        default:
-        }
-        return found;
-    }
-
-    private int nextToken() throws IOException {
-        int tok;
-        while ((tok = st.nextToken()) == StreamTokenizer.TT_EOL) {
-            linenum++;
-        }
-        return tok;
-    }
-
-    /*
-     * Fast path reading from file urls in order to avoid calling
-     * FileURLConnection.connect() which can be quite slow the first time
-     * it is called. We really should clean up FileURLConnection so that
-     * this is not a problem but in the meantime this fix helps reduce
-     * start up time noticeably for the new launcher. -- DAC
+    /**
+     * Refresh and reload the {@code Configuration} by re-reading all of the
+     * login configurations.
+     *
+     * @throws SecurityException if the caller does not have permission
+     *                           to refresh the {@code Configuration}
      */
-    private InputStream getInputStream(URL url) throws IOException {
-        if ("file".equalsIgnoreCase(url.getProtocol())) {
-            // Compatibility notes:
-            //
-            // Code changed from
-            //   String path = url.getFile().replace('/', File.separatorChar);
-            //   return new FileInputStream(path);
-            //
-            // The original implementation would search for "/tmp/a%20b"
-            // when url is "file:///tmp/a%20b". This is incorrect. The
-            // current codes fix this bug and searches for "/tmp/a b".
-            // For compatibility reasons, when the file "/tmp/a b" does
-            // not exist, the file named "/tmp/a%20b" will be tried.
-            //
-            // This also means that if both file exists, the behavior of
-            // this method is changed, and the current codes choose the
-            // correct one.
-            try {
-                return url.openStream();
-            } catch (Exception e) {
-                String file = url.getPath();
-                if (url.getHost().length() > 0) {  // For Windows UNC
-                    file = "//" + url.getHost() + file;
-                }
-                if (debugConfig != null) {
-                    debugConfig.println("cannot read " + url +
-                            ", try " + file);
-                }
-                return new FileInputStream(file);
-            }
-        } else {
-            return url.openStream();
-        }
-    }
-
-    private String expand(String value)
-        throws PropertyExpander.ExpandException, IOException {
-
-        if ("".equals(value)) {
-            return value;
-        }
-
-        if (expandProp) {
-
-            String s = PropertyExpander.expand(value);
-
-            if (s == null || s.length() == 0) {
-                MessageFormat form = new MessageFormat(ResourcesMgr.getString
-                        ("Configuration.Error.Line.line.system.property.value.expanded.to.empty.value",
-                        "sun.security.util.AuthResources"));
-                Object[] source = {new Integer(linenum), value};
-                throw new IOException(form.format(source));
-            }
-            return s;
-        } else {
-            return value;
-        }
+    @Override
+    public synchronized void refresh() {
+        configFile.engineRefresh();
     }
 }
--- a/jdk/src/share/classes/java/beans/DefaultPersistenceDelegate.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/java/beans/DefaultPersistenceDelegate.java	Wed Jul 05 18:34:47 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -58,7 +58,8 @@
  */
 
 public class DefaultPersistenceDelegate extends PersistenceDelegate {
-    private String[] constructor;
+    private static final String[] EMPTY = {};
+    private final String[] constructor;
     private Boolean definesEquals;
 
     /**
@@ -67,7 +68,7 @@
      * @see #DefaultPersistenceDelegate(java.lang.String[])
      */
     public DefaultPersistenceDelegate() {
-        this(new String[0]);
+        this.constructor = EMPTY;
     }
 
     /**
@@ -92,7 +93,7 @@
      * @see #instantiate
      */
     public DefaultPersistenceDelegate(String[] constructorPropertyNames) {
-        this.constructor = constructorPropertyNames;
+        this.constructor = (constructorPropertyNames == null) ? EMPTY : constructorPropertyNames.clone();
     }
 
     private static boolean definesEquals(Class<?> type) {
--- a/jdk/src/share/classes/java/beans/EventSetDescriptor.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/java/beans/EventSetDescriptor.java	Wed Jul 05 18:34:47 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -277,7 +277,9 @@
                 Method removeListenerMethod)
                 throws IntrospectionException {
         setName(eventSetName);
-        this.listenerMethodDescriptors = listenerMethodDescriptors;
+        this.listenerMethodDescriptors = (listenerMethodDescriptors != null)
+                ? listenerMethodDescriptors.clone()
+                : null;
         setAddListenerMethod(addListenerMethod);
         setRemoveListenerMethod(removeListenerMethod);
         setListenerType(listenerType);
@@ -347,7 +349,9 @@
      * events are fired.
      */
     public synchronized MethodDescriptor[] getListenerMethodDescriptors() {
-        return listenerMethodDescriptors;
+        return (this.listenerMethodDescriptors != null)
+                ? this.listenerMethodDescriptors.clone()
+                : null;
     }
 
     /**
--- a/jdk/src/share/classes/java/beans/MethodDescriptor.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/java/beans/MethodDescriptor.java	Wed Jul 05 18:34:47 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -70,7 +70,9 @@
                 ParameterDescriptor parameterDescriptors[]) {
         setName(method.getName());
         setMethod(method);
-        this.parameterDescriptors = parameterDescriptors;
+        this.parameterDescriptors = (parameterDescriptors != null)
+                ? parameterDescriptors.clone()
+                : null;
     }
 
     /**
@@ -161,7 +163,9 @@
      *          a null array if the parameter names aren't known.
      */
     public ParameterDescriptor[] getParameterDescriptors() {
-        return parameterDescriptors;
+        return (this.parameterDescriptors != null)
+                ? this.parameterDescriptors.clone()
+                : null;
     }
 
     /*
--- a/jdk/src/share/classes/java/beans/Statement.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/java/beans/Statement.java	Wed Jul 05 18:34:47 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -92,7 +92,7 @@
     public Statement(Object target, String methodName, Object[] arguments) {
         this.target = target;
         this.methodName = methodName;
-        this.arguments = (arguments == null) ? emptyArray : arguments;
+        this.arguments = (arguments == null) ? emptyArray : arguments.clone();
     }
 
     /**
@@ -128,7 +128,7 @@
      * @return the array of arguments
      */
     public Object[] getArguments() {
-        return arguments;
+        return this.arguments.clone();
     }
 
     /**
--- a/jdk/src/share/classes/java/lang/Class.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/java/lang/Class.java	Wed Jul 05 18:34:47 2017 +0200
@@ -506,6 +506,7 @@
      * returns {@code false} otherwise.
      * @return {@code true} if and only if this class is a synthetic class as
      *         defined by the Java Language Specification.
+     * @jls 13.1 The Form of a Binary
      * @since 1.5
      */
     public boolean isSynthetic() {
--- a/jdk/src/share/classes/java/lang/reflect/Constructor.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/java/lang/reflect/Constructor.java	Wed Jul 05 18:34:47 2017 +0200
@@ -66,6 +66,8 @@
     private transient ConstructorRepository genericInfo;
     private byte[]              annotations;
     private byte[]              parameterAnnotations;
+    // This is set by the vm at Constructor creation
+    private byte[]              typeAnnotations;
 
     // Generics infrastructure
     // Accessor for factory
@@ -138,6 +140,8 @@
         res.root = this;
         // Might as well eagerly propagate this if already present
         res.constructorAccessor = constructorAccessor;
+
+        res.typeAnnotations = typeAnnotations;
         return res;
     }
 
@@ -407,6 +411,7 @@
 
     /**
      * {@inheritDoc}
+     * @jls 13.1 The Form of a Binary
      * @since 1.5
      */
     @Override
--- a/jdk/src/share/classes/java/lang/reflect/Executable.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/java/lang/reflect/Executable.java	Wed Jul 05 18:34:47 2017 +0200
@@ -324,6 +324,7 @@
      * @return true if and only if this executable is a synthetic
      * construct as defined by
      * <cite>The Java&trade; Language Specification</cite>.
+     * @jls 13.1 The Form of a Binary
      */
     public boolean isSynthetic() {
         return Modifier.isSynthetic(getModifiers());
--- a/jdk/src/share/classes/java/lang/reflect/Field.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/java/lang/reflect/Field.java	Wed Jul 05 18:34:47 2017 +0200
@@ -80,6 +80,8 @@
     // currently only two levels deep (i.e., one root Field and
     // potentially many Field objects pointing to it.)
     private Field               root;
+    // This is set by the vm at Field creation
+    private byte[]              typeAnnotations;
 
     // Generics infrastructure
 
@@ -144,6 +146,8 @@
         // Might as well eagerly propagate this if already present
         res.fieldAccessor = fieldAccessor;
         res.overrideFieldAccessor = overrideFieldAccessor;
+
+        res.typeAnnotations = typeAnnotations;
         return res;
     }
 
--- a/jdk/src/share/classes/java/lang/reflect/Member.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/java/lang/reflect/Member.java	Wed Jul 05 18:34:47 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -87,6 +87,7 @@
      *
      * @return true if and only if this member was introduced by
      * the compiler.
+     * @jls 13.1 The Form of a Binary
      * @since 1.5
      */
     public boolean isSynthetic();
--- a/jdk/src/share/classes/java/lang/reflect/Method.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/java/lang/reflect/Method.java	Wed Jul 05 18:34:47 2017 +0200
@@ -79,7 +79,8 @@
     // currently only two levels deep (i.e., one root Method and
     // potentially many Method objects pointing to it.)
     private Method              root;
-
+    // This is set by the vm at Method creation
+    private byte[]              typeAnnotations;
 
     // Generics infrastructure
     private String getGenericSignature() {return signature;}
@@ -150,6 +151,8 @@
         res.root = this;
         // Might as well eagerly propagate this if already present
         res.methodAccessor = methodAccessor;
+
+        res.typeAnnotations = typeAnnotations;
         return res;
     }
 
@@ -497,6 +500,7 @@
 
     /**
      * {@inheritDoc}
+     * @jls 13.1 The Form of a Binary
      * @since 1.5
      */
     @Override
@@ -504,6 +508,22 @@
         return super.isSynthetic();
     }
 
+    /**
+     * Returns {@code true} if this method is a default
+     * method; returns {@code false} otherwise.
+     *
+     * A default method is a non-abstract method, that is, a method
+     * with a body, declared in an interface type.
+     *
+     * @return true if and only if this method is a default
+     * method as defined by the Java Language Specification.
+     * @since 1.8
+     */
+    public boolean isDefault() {
+        return (getModifiers() & Modifier.ABSTRACT) == 0 &&
+            getDeclaringClass().isInterface();
+    }
+
     // NOTE that there is no synchronization used here. It is correct
     // (though not efficient) to generate more than one MethodAccessor
     // for a given Method. However, avoiding synchronization will
--- a/jdk/src/share/classes/java/net/URLConnection.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/java/net/URLConnection.java	Wed Jul 05 18:34:47 2017 +0200
@@ -129,15 +129,6 @@
  * <a href="http://www.ietf.org/rfc/rfc2616.txt">http://www.ietf.org/rfc/rfc2616.txt</a>
  * </pre></blockquote>
  *
- * Note about <code>fileNameMap</code>: In versions prior to JDK 1.1.6,
- * field <code>fileNameMap</code> of <code>URLConnection</code> was public.
- * In JDK 1.1.6 and later, <code>fileNameMap</code> is private; accessor
- * and mutator methods {@link #getFileNameMap() getFileNameMap} and
- * {@link #setFileNameMap(java.net.FileNameMap) setFileNameMap} are added
- * to access it.  This change is also described on the <a href=
- * "http://java.sun.com/products/jdk/1.2/compatibility.html">
- * Compatibility</a> page.
- *
  * Invoking the <tt>close()</tt> methods on the <tt>InputStream</tt> or <tt>OutputStream</tt> of an
  * <tt>URLConnection</tt> after a request may free network resources associated with this
  * instance, unless particular protocol specifications specify different behaviours
@@ -305,8 +296,7 @@
      * Loads filename map (a mimetable) from a data file. It will
      * first try to load the user-specific table, defined
      * by &quot;content.types.user.table&quot; property. If that fails,
-     * it tries to load the default built-in table at
-     * lib/content-types.properties under java home.
+     * it tries to load the default built-in table.
      *
      * @return the FileNameMap
      * @since 1.2
--- a/jdk/src/share/classes/java/util/Arrays.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/java/util/Arrays.java	Wed Jul 05 18:34:47 2017 +0200
@@ -26,6 +26,7 @@
 package java.util;
 
 import java.lang.reflect.*;
+import static java.util.ArraysParallelSortHelpers.*;
 
 /**
  * This class contains various methods for manipulating arrays (such as
@@ -54,6 +55,13 @@
  */
 public class Arrays {
 
+    /**
+     * The minimum array length below which the sorting algorithm will not
+     * further partition the sorting task.
+     */
+    // reasonable default so that we don't overcreate tasks
+    private static final int MIN_ARRAY_SORT_GRAN = 256;
+
     // Suppresses default constructor, ensuring non-instantiability.
     private Arrays() {}
 
@@ -787,6 +795,613 @@
         }
     }
 
+    /*
+     * Parallel sorting of primitive type arrays.
+     */
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
+     * that breaks the array into sub-arrays that are themselves sorted and then
+     * merged. When the sub-array length reaches a minimum granularity, the
+     * sub-array is sorted using the appropriate {@link Arrays#sort(byte[])
+     * Arrays.sort} method. The algorithm requires a working space equal to the
+     * size of the original array. The {@link
+     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(byte[] a) {
+        parallelSort(a, 0, a.length);
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending order. The range
+     * to be sorted extends from the index {@code fromIndex}, inclusive, to
+     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
+     * the range to be sorted is empty.
+     *
+     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
+     * that breaks the array into sub-arrays that are themselves sorted and then
+     * merged. When the sub-array length reaches a minimum granularity, the
+     * sub-array is sorted using the appropriate {@link Arrays#sort(byte[])
+     * Arrays.sort} method. The algorithm requires a working space equal to the
+     * size of the original array. The {@link
+     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(byte[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        int nelements = toIndex - fromIndex;
+        int gran = getSplitThreshold(nelements);
+        FJByte.Sorter task = new FJByte.Sorter(a, new byte[a.length], fromIndex,
+                                               nelements, gran);
+        task.invoke();
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
+     * that breaks the array into sub-arrays that are themselves sorted and then
+     * merged. When the sub-array length reaches a minimum granularity, the
+     * sub-array is sorted using the appropriate {@link Arrays#sort(char[])
+     * Arrays.sort} method. The algorithm requires a working space equal to the
+     * size of the original array. The {@link
+     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(char[] a) {
+        parallelSort(a, 0, a.length);
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending order. The range
+     * to be sorted extends from the index {@code fromIndex}, inclusive, to
+     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
+     * the range to be sorted is empty.
+     *
+     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
+     * that breaks the array into sub-arrays that are themselves sorted and then
+     * merged. When the sub-array length reaches a minimum granularity, the
+     * sub-array is sorted using the appropriate {@link Arrays#sort(char[])
+     * Arrays.sort} method. The algorithm requires a working space equal to the
+     * size of the original array. The {@link
+     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(char[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        int nelements = toIndex - fromIndex;
+        int gran = getSplitThreshold(nelements);
+        FJChar.Sorter task = new FJChar.Sorter(a, new char[a.length], fromIndex,
+                                               nelements, gran);
+        task.invoke();
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
+     * that breaks the array into sub-arrays that are themselves sorted and then
+     * merged. When the sub-array length reaches a minimum granularity, the
+     * sub-array is sorted using the appropriate {@link Arrays#sort(short[])
+     * Arrays.sort} method. The algorithm requires a working space equal to the
+     * size of the original array. The {@link
+     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(short[] a) {
+        parallelSort(a, 0, a.length);
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending order. The range
+     * to be sorted extends from the index {@code fromIndex}, inclusive, to
+     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
+     * the range to be sorted is empty.
+     *
+     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
+     * that breaks the array into sub-arrays that are themselves sorted and then
+     * merged. When the sub-array length reaches a minimum granularity, the
+     * sub-array is sorted using the appropriate {@link Arrays#sort(short[])
+     * Arrays.sort} method. The algorithm requires a working space equal to the
+     * size of the original array. The {@link
+     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(short[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        int nelements = toIndex - fromIndex;
+        int gran = getSplitThreshold(nelements);
+        FJShort.Sorter task = new FJShort.Sorter(a, new short[a.length], fromIndex,
+                                                 nelements, gran);
+        task.invoke();
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
+     * that breaks the array into sub-arrays that are themselves sorted and then
+     * merged. When the sub-array length reaches a minimum granularity, the
+     * sub-array is sorted using the appropriate {@link Arrays#sort(int[])
+     * Arrays.sort} method. The algorithm requires a working space equal to the
+     * size of the original array. The {@link
+     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(int[] a) {
+        parallelSort(a, 0, a.length);
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending order. The range
+     * to be sorted extends from the index {@code fromIndex}, inclusive, to
+     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
+     * the range to be sorted is empty.
+     *
+     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
+     * that breaks the array into sub-arrays that are themselves sorted and then
+     * merged. When the sub-array length reaches a minimum granularity, the
+     * sub-array is sorted using the appropriate {@link Arrays#sort(int[])
+     * Arrays.sort} method. The algorithm requires a working space equal to the
+     * size of the original array. The {@link
+     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(int[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        int nelements = toIndex - fromIndex;
+        int gran = getSplitThreshold(nelements);
+        FJInt.Sorter task = new FJInt.Sorter(a, new int[a.length], fromIndex,
+                                             nelements, gran);
+        task.invoke();
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
+     * that breaks the array into sub-arrays that are themselves sorted and then
+     * merged. When the sub-array length reaches a minimum granularity, the
+     * sub-array is sorted using the appropriate {@link Arrays#sort(long[])
+     * Arrays.sort} method. The algorithm requires a working space equal to the
+     * size of the original array. The {@link
+     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(long[] a) {
+        parallelSort(a, 0, a.length);
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending order. The range
+     * to be sorted extends from the index {@code fromIndex}, inclusive, to
+     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
+     * the range to be sorted is empty.
+     *
+     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
+     * that breaks the array into sub-arrays that are themselves sorted and then
+     * merged. When the sub-array length reaches a minimum granularity, the
+     * sub-array is sorted using the appropriate {@link Arrays#sort(long[])
+     * Arrays.sort} method. The algorithm requires a working space equal to the
+     * size of the original array. The {@link
+     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(long[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        int nelements = toIndex - fromIndex;
+        int gran = getSplitThreshold(nelements);
+        FJLong.Sorter task = new FJLong.Sorter(a, new long[a.length], fromIndex,
+                                               nelements, gran);
+        task.invoke();
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * <p>The {@code <} relation does not provide a total order on all float
+     * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN}
+     * value compares neither less than, greater than, nor equal to any value,
+     * even itself. This method uses the total order imposed by the method
+     * {@link Float#compareTo}: {@code -0.0f} is treated as less than value
+     * {@code 0.0f} and {@code Float.NaN} is considered greater than any
+     * other value and all {@code Float.NaN} values are considered equal.
+     *
+     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
+     * that breaks the array into sub-arrays that are themselves sorted and then
+     * merged. When the sub-array length reaches a minimum granularity, the
+     * sub-array is sorted using the appropriate {@link Arrays#sort(float[])
+     * Arrays.sort} method. The algorithm requires a working space equal to the
+     * size of the original array. The {@link
+     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(float[] a) {
+        parallelSort(a, 0, a.length);
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending order. The range
+     * to be sorted extends from the index {@code fromIndex}, inclusive, to
+     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
+     * the range to be sorted is empty.
+     *
+     * <p>The {@code <} relation does not provide a total order on all float
+     * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN}
+     * value compares neither less than, greater than, nor equal to any value,
+     * even itself. This method uses the total order imposed by the method
+     * {@link Float#compareTo}: {@code -0.0f} is treated as less than value
+     * {@code 0.0f} and {@code Float.NaN} is considered greater than any
+     * other value and all {@code Float.NaN} values are considered equal.
+     *
+     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
+     * that breaks the array into sub-arrays that are themselves sorted and then
+     * merged. When the sub-array length reaches a minimum granularity, the
+     * sub-array is sorted using the appropriate {@link Arrays#sort(float[])
+     * Arrays.sort} method. The algorithm requires a working space equal to the
+     * size of the original array. The {@link
+     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(float[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        int nelements = toIndex - fromIndex;
+        int gran = getSplitThreshold(nelements);
+        FJFloat.Sorter task = new FJFloat.Sorter(a, new float[a.length], fromIndex,
+                                                 nelements, gran);
+        task.invoke();
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * <p>The {@code <} relation does not provide a total order on all double
+     * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN}
+     * value compares neither less than, greater than, nor equal to any value,
+     * even itself. This method uses the total order imposed by the method
+     * {@link Double#compareTo}: {@code -0.0d} is treated as less than value
+     * {@code 0.0d} and {@code Double.NaN} is considered greater than any
+     * other value and all {@code Double.NaN} values are considered equal.
+     *
+     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
+     * that breaks the array into sub-arrays that are themselves sorted and then
+     * merged. When the sub-array length reaches a minimum granularity, the
+     * sub-array is sorted using the appropriate {@link Arrays#sort(double[])
+     * Arrays.sort} method. The algorithm requires a working space equal to the
+     * size of the original array. The {@link
+     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(double[] a) {
+        parallelSort(a, 0, a.length);
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending order. The range
+     * to be sorted extends from the index {@code fromIndex}, inclusive, to
+     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
+     * the range to be sorted is empty.
+     *
+     * <p>The {@code <} relation does not provide a total order on all double
+     * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN}
+     * value compares neither less than, greater than, nor equal to any value,
+     * even itself. This method uses the total order imposed by the method
+     * {@link Double#compareTo}: {@code -0.0d} is treated as less than value
+     * {@code 0.0d} and {@code Double.NaN} is considered greater than any
+     * other value and all {@code Double.NaN} values are considered equal.
+     *
+     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
+     * that breaks the array into sub-arrays that are themselves sorted and then
+     * merged. When the sub-array length reaches a minimum granularity, the
+     * sub-array is sorted using the appropriate {@link Arrays#sort(double[])
+     * Arrays.sort} method. The algorithm requires a working space equal to the
+     * size of the original array. The {@link
+     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(double[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        int nelements = toIndex - fromIndex;
+        int gran = getSplitThreshold(nelements);
+        FJDouble.Sorter task = new FJDouble.Sorter(a, new double[a.length],
+                                                   fromIndex, nelements, gran);
+        task.invoke();
+    }
+
+    /*
+     * Parallel sorting of complex type arrays.
+     */
+
+    /**
+     * Sorts the specified array of objects into ascending order, according
+     * to the {@linkplain Comparable natural ordering} of its elements.
+     * All elements in the array must implement the {@link Comparable}
+     * interface.  Furthermore, all elements in the array must be
+     * <i>mutually comparable</i> (that is, {@code e1.compareTo(e2)} must
+     * not throw a {@code ClassCastException} for any elements {@code e1}
+     * and {@code e2} in the array).
+     *
+     * <p>This sort is not guaranteed to be <i>stable</i>:  equal elements
+     * may be reordered as a result of the sort.
+     *
+     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
+     * that breaks the array into sub-arrays that are themselves sorted and then
+     * merged. When the sub-array length reaches a minimum granularity, the
+     * sub-array is sorted using the appropriate {@link Arrays#sort(Object[])
+     * Arrays.sort} method. The algorithm requires a working space equal to the
+     * size of the original array. The {@link
+     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     *
+     * @throws ClassCastException if the array contains elements that are not
+     *         <i>mutually comparable</i> (for example, strings and integers)
+     * @throws IllegalArgumentException (optional) if the natural
+     *         ordering of the array elements is found to violate the
+     *         {@link Comparable} contract
+     *
+     * @since 1.8
+     */
+    public static <T extends Comparable<? super T>> void parallelSort(T[] a) {
+        parallelSort(a, 0, a.length);
+    }
+
+    /**
+     * Sorts the specified range of the specified array of objects into
+     * ascending order, according to the
+     * {@linkplain Comparable natural ordering} of its
+     * elements.  The range to be sorted extends from index
+     * {@code fromIndex}, inclusive, to index {@code toIndex}, exclusive.
+     * (If {@code fromIndex==toIndex}, the range to be sorted is empty.)  All
+     * elements in this range must implement the {@link Comparable}
+     * interface.  Furthermore, all elements in this range must be <i>mutually
+     * comparable</i> (that is, {@code e1.compareTo(e2)} must not throw a
+     * {@code ClassCastException} for any elements {@code e1} and
+     * {@code e2} in the array).
+     *
+     * <p>This sort is not guaranteed to be <i>stable</i>:  equal elements
+     * may be reordered as a result of the sort.
+     *
+     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
+     * that breaks the array into sub-arrays that are themselves sorted and then
+     * merged. When the sub-array length reaches a minimum granularity, the
+     * sub-array is sorted using the appropriate {@link Arrays#sort(Object[])
+     * Arrays.sort} method. The algorithm requires a working space equal to the
+     * size of the original array. The {@link
+     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        sorted
+     * @param toIndex the index of the last element (exclusive) to be sorted
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex} or
+     *         (optional) if the natural ordering of the array elements is
+     *         found to violate the {@link Comparable} contract
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
+     *         {@code toIndex > a.length}
+     * @throws ClassCastException if the array contains elements that are
+     *         not <i>mutually comparable</i> (for example, strings and
+     *         integers).
+     *
+     * @since 1.8
+     */
+    public static <T extends Comparable<? super T>>
+            void parallelSort(T[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        int nelements = toIndex - fromIndex;
+        Class<?> tc = a.getClass().getComponentType();
+        @SuppressWarnings("unchecked")
+        T[] workspace = (T[])Array.newInstance(tc, a.length);
+        int gran = getSplitThreshold(nelements);
+        FJComparable.Sorter<T> task = new FJComparable.Sorter<>(a, workspace,
+                                                                fromIndex,
+                                                                nelements, gran);
+        task.invoke();
+    }
+
+    /**
+     * Sorts the specified array of objects according to the order induced by
+     * the specified comparator.  All elements in the array must be
+     * <i>mutually comparable</i> by the specified comparator (that is,
+     * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException}
+     * for any elements {@code e1} and {@code e2} in the array).
+     *
+     * <p>This sort is not guaranteed to be <i>stable</i>:  equal elements
+     * may be reordered as a result of the sort.
+     *
+     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
+     * that breaks the array into sub-arrays that are themselves sorted and then
+     * merged. When the sub-array length reaches a minimum granularity, the
+     * sub-array is sorted using the appropriate {@link Arrays#sort(Object[])
+     * Arrays.sort} method. The algorithm requires a working space equal to the
+     * size of the original array. The {@link
+     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     * @param c the comparator to determine the order of the array.  A
+     *        {@code null} value indicates that the elements'
+     *        {@linkplain Comparable natural ordering} should be used.
+     * @throws ClassCastException if the array contains elements that are
+     *         not <i>mutually comparable</i> using the specified comparator
+     * @throws IllegalArgumentException (optional) if the comparator is
+     *         found to violate the {@link java.util.Comparator} contract
+     *
+     * @since 1.8
+     */
+    public static <T> void parallelSort(T[] a, Comparator<? super T> c) {
+        parallelSort(a, 0, a.length, c);
+    }
+
+    /**
+     * Sorts the specified range of the specified array of objects according
+     * to the order induced by the specified comparator.  The range to be
+     * sorted extends from index {@code fromIndex}, inclusive, to index
+     * {@code toIndex}, exclusive.  (If {@code fromIndex==toIndex}, the
+     * range to be sorted is empty.)  All elements in the range must be
+     * <i>mutually comparable</i> by the specified comparator (that is,
+     * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException}
+     * for any elements {@code e1} and {@code e2} in the range).
+     *
+     * <p>This sort is not guaranteed to be <i>stable</i>:  equal elements
+     * may be reordered as a result of the sort.
+     *
+     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
+     * that breaks the array into sub-arrays that are themselves sorted and then
+     * merged. When the sub-array length reaches a minimum granularity, the
+     * sub-array is sorted using the appropriate {@link Arrays#sort(Object[])
+     * Arrays.sort} method. The algorithm requires a working space equal to the
+     * size of the original array. The {@link
+     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        sorted
+     * @param toIndex the index of the last element (exclusive) to be sorted
+     * @param c the comparator to determine the order of the array.  A
+     *        {@code null} value indicates that the elements'
+     *        {@linkplain Comparable natural ordering} should be used.
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex} or
+     *         (optional) if the natural ordering of the array elements is
+     *         found to violate the {@link Comparable} contract
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
+     *         {@code toIndex > a.length}
+     * @throws ClassCastException if the array contains elements that are
+     *         not <i>mutually comparable</i> (for example, strings and
+     *         integers).
+     *
+     * @since 1.8
+     */
+    public static <T> void parallelSort(T[] a, int fromIndex, int toIndex,
+                                        Comparator<? super T> c) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        int nelements = toIndex - fromIndex;
+        Class<?> tc = a.getClass().getComponentType();
+        @SuppressWarnings("unchecked")
+        T[] workspace = (T[])Array.newInstance(tc, a.length);
+        int gran = getSplitThreshold(nelements);
+        FJComparator.Sorter<T> task = new FJComparator.Sorter<>(a, workspace,
+                                                                fromIndex,
+                                                                nelements, gran, c);
+        task.invoke();
+    }
+
+    /**
+     * Returns the size threshold for splitting into subtasks.
+     * By default, uses about 8 times as many tasks as threads
+     *
+     * @param n number of elements in the array to be processed
+     */
+    private static int getSplitThreshold(int n) {
+        int p = java.util.concurrent.ForkJoinPool.getCommonPoolParallelism();
+        int t = (p > 1) ? (1 + n / (p << 3)) : n;
+        return t < MIN_ARRAY_SORT_GRAN ? MIN_ARRAY_SORT_GRAN : t;
+    }
+
     /**
      * Checks that {@code fromIndex} and {@code toIndex} are in
      * the range and throws an appropriate exception, if they aren't.
@@ -1480,9 +2095,9 @@
         while (low <= high) {
             int mid = (low + high) >>> 1;
             @SuppressWarnings("rawtypes")
-                Comparable midVal = (Comparable)a[mid];
+            Comparable midVal = (Comparable)a[mid];
             @SuppressWarnings("unchecked")
-                int cmp = midVal.compareTo(key);
+            int cmp = midVal.compareTo(key);
 
             if (cmp < 0)
                 low = mid + 1;
@@ -2847,19 +3462,20 @@
         private final E[] a;
 
         ArrayList(E[] array) {
-            if (array==null)
-                throw new NullPointerException();
-            a = array;
+            a = Objects.requireNonNull(array);
         }
 
+        @Override
         public int size() {
             return a.length;
         }
 
+        @Override
         public Object[] toArray() {
             return a.clone();
         }
 
+        @Override
         @SuppressWarnings("unchecked")
         public <T> T[] toArray(T[] a) {
             int size = size();
@@ -2872,16 +3488,19 @@
             return a;
         }
 
+        @Override
         public E get(int index) {
             return a[index];
         }
 
+        @Override
         public E set(int index, E element) {
             E oldValue = a[index];
             a[index] = element;
             return oldValue;
         }
 
+        @Override
         public int indexOf(Object o) {
             if (o==null) {
                 for (int i=0; i<a.length; i++)
@@ -2895,6 +3514,7 @@
             return -1;
         }
 
+        @Override
         public boolean contains(Object o) {
             return indexOf(o) != -1;
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/util/ArraysParallelSortHelpers.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,1223 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.util.concurrent.RecursiveAction;
+
+/**
+ * Helper utilities for the parallel sort methods in Arrays.parallelSort.
+ *
+ * For each primitive type, plus Object, we define a static class to
+ * contain the Sorter and Merger implementations for that type:
+ *
+ * Sorter classes based mainly on CilkSort
+ * <A href="http://supertech.lcs.mit.edu/cilk/"> Cilk</A>:
+ * Basic algorithm:
+ * if array size is small, just use a sequential quicksort (via Arrays.sort)
+ *         Otherwise:
+ *         1. Break array in half.
+ *         2. For each half,
+ *             a. break the half in half (i.e., quarters),
+ *             b. sort the quarters
+ *             c. merge them together
+ *         3. merge together the two halves.
+ *
+ * One reason for splitting in quarters is that this guarantees
+ * that the final sort is in the main array, not the workspace
+ * array.  (workspace and main swap roles on each subsort step.)
+ * Leaf-level sorts use a Sequential quicksort, that in turn uses
+ * insertion sort if under threshold.  Otherwise it uses median of
+ * three to pick pivot, and loops rather than recurses along left
+ * path.
+ *
+ *
+ * Merger classes perform merging for Sorter. If big enough, splits Left
+ * partition in half; finds the greatest point in Right partition
+ * less than the beginning of the second half of Left via binary
+ * search; and then, in parallel, merges left half of Left with
+ * elements of Right up to split point, and merges right half of
+ * Left with elements of R past split point. At leaf, it just
+ * sequentially merges. This is all messy to code; sadly we need
+ * distinct versions for each type.
+ *
+ */
+/*package*/ class ArraysParallelSortHelpers {
+
+    // RFE: we should only need a working array as large as the subarray
+    //      to be sorted, but the logic assumes that indices in the two
+    //      arrays always line-up
+
+    /** byte support class */
+    static final class FJByte {
+        static final class Sorter extends RecursiveAction {
+            static final long serialVersionUID = 749471161188027634L;
+            final byte[] a;     // array to be sorted.
+            final byte[] w;     // workspace for merge
+            final int origin;   // origin of the part of array we deal with
+            final int n;        // Number of elements in (sub)arrays.
+            final int gran;     // split control
+
+            Sorter(byte[] a, byte[] w, int origin, int n, int gran) {
+                this.a = a;
+                this.w = w;
+                this.origin = origin;
+                this.n = n;
+                this.gran = gran;
+            }
+
+            public void compute() {
+                final int l = origin;
+                final int g = gran;
+                final int n = this.n;
+                final byte[] a = this.a;
+                final byte[] w = this.w;
+                if (n > g) {
+                    int h = n >>> 1; // half
+                    int q = n >>> 2; // lower quarter index
+                    int u = h + q;   // upper quarter
+                    FJSubSorter ls = new FJSubSorter(new Sorter(a, w, l, q,  g),
+                                                     new Sorter(a, w, l+q, h-q, g),
+                                                     new Merger(a, w, l,   q,
+                                                                l+q, h-q, l, g, null));
+                    FJSubSorter rs = new FJSubSorter(new Sorter(a, w, l+h, q,   g),
+                                                     new Sorter(a, w, l+u, n-u, g),
+                                                     new Merger(a, w, l+h, q,
+                                                                l+u, n-u, l+h, g, null));
+                    rs.fork();
+                    ls.compute();
+                    if (rs.tryUnfork()) rs.compute(); else rs.join();
+                    new Merger(w, a, l, h,
+                               l+h, n-h, l, g, null).compute();
+                } else {
+                    DualPivotQuicksort.sort(a, l, l+n-1);   //skip rangeCheck
+                }
+            }
+        }
+
+        static final class Merger extends RecursiveAction {
+            static final long serialVersionUID = -9090258248781844470L;
+            final byte[] a;
+            final byte[] w;
+            final int lo;
+            final int ln;
+            final int ro;
+            final int rn;
+            final int wo;
+            final int gran;
+            final Merger next;
+
+            Merger(byte[] a, byte[] w, int lo, int ln, int ro, int rn, int wo,
+                   int gran, Merger next) {
+                this.a = a;
+                this.w = w;
+                this.lo = lo;
+                this.ln = ln;
+                this.ro = ro;
+                this.rn = rn;
+                this.wo = wo;
+                this.gran = gran;
+                this.next = next;
+            }
+
+            public void compute() {
+                final byte[] a = this.a;
+                final byte[] w = this.w;
+                Merger rights = null;
+                int nleft = ln;
+                int nright = rn;
+                while (nleft > gran) {
+                    int lh = nleft >>> 1;
+                    int splitIndex = lo + lh;
+                    byte split = a[splitIndex];
+                    int rl = 0;
+                    int rh = nright;
+                    while (rl < rh) {
+                        int mid = (rl + rh) >>> 1;
+                        if (split <= a[ro + mid])
+                            rh = mid;
+                        else
+                            rl = mid + 1;
+                    }
+                    (rights = new Merger(a, w, splitIndex, nleft-lh, ro+rh,
+                                         nright-rh, wo+lh+rh, gran, rights)).fork();
+                    nleft = lh;
+                    nright = rh;
+                }
+
+                int l = lo;
+                int lFence = l + nleft;
+                int r = ro;
+                int rFence = r + nright;
+                int k = wo;
+                while (l < lFence && r < rFence) {
+                    byte al = a[l];
+                    byte ar = a[r];
+                    byte t;
+                    if (al <= ar) {++l; t=al;} else {++r; t = ar;}
+                    w[k++] = t;
+                }
+                while (l < lFence)
+                    w[k++] = a[l++];
+                while (r < rFence)
+                    w[k++] = a[r++];
+                while (rights != null) {
+                    if (rights.tryUnfork())
+                        rights.compute();
+                    else
+                        rights.join();
+                    rights = rights.next;
+                }
+            }
+        }
+    } // FJByte
+
+    /** char support class */
+    static final class FJChar {
+        static final class Sorter extends RecursiveAction {
+            static final long serialVersionUID = 8723376019074596641L;
+            final char[] a;     // array to be sorted.
+            final char[] w;     // workspace for merge
+            final int origin;   // origin of the part of array we deal with
+            final int n;        // Number of elements in (sub)arrays.
+            final int gran;     // split control
+
+            Sorter(char[] a, char[] w, int origin, int n, int gran) {
+                this.a = a;
+                this.w = w;
+                this.origin = origin;
+                this.n = n;
+                this.gran = gran;
+            }
+
+            public void compute() {
+                final int l = origin;
+                final int g = gran;
+                final int n = this.n;
+                final char[] a = this.a;
+                final char[] w = this.w;
+                if (n > g) {
+                    int h = n >>> 1; // half
+                    int q = n >>> 2; // lower quarter index
+                    int u = h + q;   // upper quarter
+                    FJSubSorter ls = new FJSubSorter(new Sorter(a, w, l, q,   g),
+                                                     new Sorter(a, w, l+q, h-q, g),
+                                                     new Merger(a, w, l,   q,
+                                                                l+q, h-q, l, g, null));
+                    FJSubSorter rs = new FJSubSorter(new Sorter(a, w, l + h, q,   g),
+                                                     new Sorter(a, w, l+u, n-u, g),
+                                                     new Merger(a, w, l+h, q,
+                                                                l+u, n-u, l+h, g, null));
+                    rs.fork();
+                    ls.compute();
+                    if (rs.tryUnfork()) rs.compute(); else rs.join();
+                    new Merger(w, a, l, h, l + h, n - h, l, g, null).compute();
+                } else {
+                    DualPivotQuicksort.sort(a, l, l+n-1);   // skip rangeCheck
+                }
+            }
+        }
+
+        static final class Merger extends RecursiveAction {
+            static final long serialVersionUID = -1383975444621698926L;
+            final char[] a;
+            final char[] w;
+            final int lo;
+            final int ln;
+            final int ro;
+            final int rn;
+            final int wo;
+            final int gran;
+            final Merger next;
+
+            Merger(char[] a, char[] w, int lo, int ln, int ro, int rn, int wo,
+                   int gran, Merger next) {
+                this.a = a;
+                this.w = w;
+                this.lo = lo;
+                this.ln = ln;
+                this.ro = ro;
+                this.rn = rn;
+                this.wo = wo;
+                this.gran = gran;
+                this.next = next;
+            }
+
+            public void compute() {
+                final char[] a = this.a;
+                final char[] w = this.w;
+                Merger rights = null;
+                int nleft = ln;
+                int nright = rn;
+                while (nleft > gran) {
+                    int lh = nleft >>> 1;
+                    int splitIndex = lo + lh;
+                    char split = a[splitIndex];
+                    int rl = 0;
+                    int rh = nright;
+                    while (rl < rh) {
+                        int mid = (rl + rh) >>> 1;
+                        if (split <= a[ro + mid])
+                            rh = mid;
+                        else
+                            rl = mid + 1;
+                    }
+                    (rights = new Merger(a, w, splitIndex, nleft-lh, ro+rh,
+                                         nright-rh, wo+lh+rh, gran, rights)).fork();
+                    nleft = lh;
+                    nright = rh;
+                }
+
+                int l = lo;
+                int lFence = l + nleft;
+                int r = ro;
+                int rFence = r + nright;
+                int k = wo;
+                while (l < lFence && r < rFence) {
+                    char al = a[l];
+                    char ar = a[r];
+                    char t;
+                    if (al <= ar) {++l; t=al;} else {++r; t = ar;}
+                    w[k++] = t;
+                }
+                while (l < lFence)
+                    w[k++] = a[l++];
+                while (r < rFence)
+                    w[k++] = a[r++];
+                while (rights != null) {
+                    if (rights.tryUnfork())
+                        rights.compute();
+                    else
+                        rights.join();
+                    rights = rights.next;
+                }
+            }
+        }
+    } // FJChar
+
+    /** short support class */
+    static final class FJShort {
+        static final class Sorter extends RecursiveAction {
+            static final long serialVersionUID = -7886754793730583084L;
+            final short[] a;    // array to be sorted.
+            final short[] w;    // workspace for merge
+            final int origin;   // origin of the part of array we deal with
+            final int n;        // Number of elements in (sub)arrays.
+            final int gran;     // split control
+
+            Sorter(short[] a, short[] w, int origin, int n, int gran) {
+                this.a = a;
+                this.w = w;
+                this.origin = origin;
+                this.n = n;
+                this.gran = gran;
+            }
+
+            public void compute() {
+                final int l = origin;
+                final int g = gran;
+                final int n = this.n;
+                final short[] a = this.a;
+                final short[] w = this.w;
+                if (n > g) {
+                    int h = n >>> 1; // half
+                    int q = n >>> 2; // lower quarter index
+                    int u = h + q;   // upper quarter
+                    FJSubSorter ls = new FJSubSorter(new Sorter(a, w, l, q,   g),
+                                                     new Sorter(a, w, l+q, h-q, g),
+                                                     new Merger(a, w, l,   q,
+                                                                l+q, h-q, l, g, null));
+                    FJSubSorter rs = new FJSubSorter(new Sorter(a, w, l + h, q,   g),
+                                                     new Sorter(a, w, l+u, n-u, g),
+                                                     new Merger(a, w, l+h, q,
+                                                                l+u, n-u, l+h, g, null));
+                    rs.fork();
+                    ls.compute();
+                    if (rs.tryUnfork()) rs.compute(); else rs.join();
+                    new Merger(w, a, l, h, l + h, n - h, l, g, null).compute();
+                } else {
+                    DualPivotQuicksort.sort(a, l, l+n-1);   // skip rangeCheck
+                }
+            }
+        }
+
+        static final class Merger extends RecursiveAction {
+            static final long serialVersionUID = 3895749408536700048L;
+            final short[] a;
+            final short[] w;
+            final int lo;
+            final int ln;
+            final int ro;
+            final int rn;
+            final int wo;
+            final int gran;
+            final Merger next;
+
+            Merger(short[] a, short[] w, int lo, int ln, int ro, int rn, int wo,
+                   int gran, Merger next) {
+                this.a = a;
+                this.w = w;
+                this.lo = lo;
+                this.ln = ln;
+                this.ro = ro;
+                this.rn = rn;
+                this.wo = wo;
+                this.gran = gran;
+                this.next = next;
+            }
+
+            public void compute() {
+                final short[] a = this.a;
+                final short[] w = this.w;
+                Merger rights = null;
+                int nleft = ln;
+                int nright = rn;
+                while (nleft > gran) {
+                    int lh = nleft >>> 1;
+                    int splitIndex = lo + lh;
+                    short split = a[splitIndex];
+                    int rl = 0;
+                    int rh = nright;
+                    while (rl < rh) {
+                        int mid = (rl + rh) >>> 1;
+                        if (split <= a[ro + mid])
+                            rh = mid;
+                        else
+                            rl = mid + 1;
+                    }
+                    (rights = new Merger(a, w, splitIndex, nleft-lh, ro+rh,
+                                         nright-rh, wo+lh+rh, gran, rights)).fork();
+                    nleft = lh;
+                    nright = rh;
+                }
+
+                int l = lo;
+                int lFence = l + nleft;
+                int r = ro;
+                int rFence = r + nright;
+                int k = wo;
+                while (l < lFence && r < rFence) {
+                    short al = a[l];
+                    short ar = a[r];
+                    short t;
+                    if (al <= ar) {++l; t=al;} else {++r; t = ar;}
+                    w[k++] = t;
+                }
+                while (l < lFence)
+                    w[k++] = a[l++];
+                while (r < rFence)
+                    w[k++] = a[r++];
+                while (rights != null) {
+                    if (rights.tryUnfork())
+                        rights.compute();
+                    else
+                        rights.join();
+                    rights = rights.next;
+                }
+            }
+        }
+    } // FJShort
+
+    /** int support class */
+    static final class FJInt {
+        static final class Sorter extends RecursiveAction {
+            static final long serialVersionUID = 4263311808957292729L;
+            final int[] a;     // array to be sorted.
+            final int[] w;     // workspace for merge
+            final int origin;  // origin of the part of array we deal with
+            final int n;       // Number of elements in (sub)arrays.
+            final int gran;    // split control
+
+            Sorter(int[] a, int[] w, int origin, int n, int gran) {
+                this.a = a;
+                this.w = w;
+                this.origin = origin;
+                this.n = n;
+                this.gran = gran;
+            }
+
+            public void compute() {
+                final int l = origin;
+                final int g = gran;
+                final int n = this.n;
+                final int[] a = this.a;
+                final int[] w = this.w;
+                if (n > g) {
+                    int h = n >>> 1; // half
+                    int q = n >>> 2; // lower quarter index
+                    int u = h + q;   // upper quarter
+                    FJSubSorter ls = new FJSubSorter(new Sorter(a, w, l, q,   g),
+                                                     new Sorter(a, w, l+q, h-q, g),
+                                                     new Merger(a, w, l,   q,
+                                                                l+q, h-q, l, g, null));
+                    FJSubSorter rs = new FJSubSorter(new Sorter(a, w, l + h, q,   g),
+                                                     new Sorter(a, w, l+u, n-u, g),
+                                                     new Merger(a, w, l+h, q,
+                                                                l+u, n-u, l+h, g, null));
+                    rs.fork();
+                    ls.compute();
+                    if (rs.tryUnfork()) rs.compute(); else rs.join();
+                    new Merger(w, a, l, h, l + h, n - h, l, g, null).compute();
+                } else {
+                    DualPivotQuicksort.sort(a, l, l+n-1);   // skip rangeCheck
+                }
+            }
+        }
+
+        static final class Merger extends RecursiveAction {
+            static final long serialVersionUID = -8727507284219982792L;
+            final int[] a;
+            final int[] w;
+            final int lo;
+            final int ln;
+            final int ro;
+            final int rn;
+            final int wo;
+            final int gran;
+            final Merger next;
+
+            Merger(int[] a, int[] w, int lo, int ln, int ro, int rn, int wo,
+                   int gran, Merger next) {
+                this.a = a;
+                this.w = w;
+                this.lo = lo;
+                this.ln = ln;
+                this.ro = ro;
+                this.rn = rn;
+                this.wo = wo;
+                this.gran = gran;
+                this.next = next;
+            }
+
+            public void compute() {
+                final int[] a = this.a;
+                final int[] w = this.w;
+                Merger rights = null;
+                int nleft = ln;
+                int nright = rn;
+                while (nleft > gran) {
+                    int lh = nleft >>> 1;
+                    int splitIndex = lo + lh;
+                    int split = a[splitIndex];
+                    int rl = 0;
+                    int rh = nright;
+                    while (rl < rh) {
+                        int mid = (rl + rh) >>> 1;
+                        if (split <= a[ro + mid])
+                            rh = mid;
+                        else
+                            rl = mid + 1;
+                    }
+                    (rights = new Merger(a, w, splitIndex, nleft-lh, ro+rh,
+                                         nright-rh, wo+lh+rh, gran, rights)).fork();
+                    nleft = lh;
+                    nright = rh;
+                }
+
+                int l = lo;
+                int lFence = l + nleft;
+                int r = ro;
+                int rFence = r + nright;
+                int k = wo;
+                while (l < lFence && r < rFence) {
+                    int al = a[l];
+                    int ar = a[r];
+                    int t;
+                    if (al <= ar) {++l; t=al;} else {++r; t = ar;}
+                    w[k++] = t;
+                }
+                while (l < lFence)
+                    w[k++] = a[l++];
+                while (r < rFence)
+                    w[k++] = a[r++];
+                while (rights != null) {
+                    if (rights.tryUnfork())
+                        rights.compute();
+                    else
+                        rights.join();
+                    rights = rights.next;
+                }
+            }
+        }
+    } // FJInt
+
+    /** long support class */
+    static final class FJLong {
+        static final class Sorter extends RecursiveAction {
+            static final long serialVersionUID = 6553695007444392455L;
+            final long[] a;     // array to be sorted.
+            final long[] w;     // workspace for merge
+            final int origin;   // origin of the part of array we deal with
+            final int n;        // Number of elements in (sub)arrays.
+            final int gran;     // split control
+
+            Sorter(long[] a, long[] w, int origin, int n, int gran) {
+                this.a = a;
+                this.w = w;
+                this.origin = origin;
+                this.n = n;
+                this.gran = gran;
+            }
+
+            public void compute() {
+                final int l = origin;
+                final int g = gran;
+                final int n = this.n;
+                final long[] a = this.a;
+                final long[] w = this.w;
+                if (n > g) {
+                    int h = n >>> 1; // half
+                    int q = n >>> 2; // lower quarter index
+                    int u = h + q;   // upper quarter
+                    FJSubSorter ls = new FJSubSorter(new Sorter(a, w, l, q,   g),
+                                                     new Sorter(a, w, l+q, h-q, g),
+                                                     new Merger(a, w, l,   q,
+                                                                l+q, h-q, l, g, null));
+                    FJSubSorter rs = new FJSubSorter(new Sorter(a, w, l + h, q,   g),
+                                                     new Sorter(a, w, l+u, n-u, g),
+                                                     new Merger(a, w, l+h, q,
+                                                                l+u, n-u, l+h, g, null));
+                    rs.fork();
+                    ls.compute();
+                    if (rs.tryUnfork()) rs.compute(); else rs.join();
+                    new Merger(w, a, l, h, l + h, n - h, l, g, null).compute();
+                } else {
+                    DualPivotQuicksort.sort(a, l, l+n-1);   // skip rangeCheck
+                }
+            }
+        }
+
+        static final class Merger extends RecursiveAction {
+            static final long serialVersionUID = 8843567516333283861L;
+            final long[] a;
+            final long[] w;
+            final int lo;
+            final int ln;
+            final int ro;
+            final int rn;
+            final int wo;
+            final int gran;
+            final Merger next;
+
+            Merger(long[] a, long[] w, int lo, int ln, int ro, int rn, int wo,
+                   int gran, Merger next) {
+                this.a = a;
+                this.w = w;
+                this.lo = lo;
+                this.ln = ln;
+                this.ro = ro;
+                this.rn = rn;
+                this.wo = wo;
+                this.gran = gran;
+                this.next = next;
+            }
+
+            public void compute() {
+                final long[] a = this.a;
+                final long[] w = this.w;
+                Merger rights = null;
+                int nleft = ln;
+                int nright = rn;
+                while (nleft > gran) {
+                    int lh = nleft >>> 1;
+                    int splitIndex = lo + lh;
+                    long split = a[splitIndex];
+                    int rl = 0;
+                    int rh = nright;
+                    while (rl < rh) {
+                        int mid = (rl + rh) >>> 1;
+                        if (split <= a[ro + mid])
+                            rh = mid;
+                        else
+                            rl = mid + 1;
+                    }
+                    (rights = new Merger(a, w, splitIndex, nleft-lh, ro+rh,
+                      nright-rh, wo+lh+rh, gran, rights)).fork();
+                    nleft = lh;
+                    nright = rh;
+                }
+
+                int l = lo;
+                int lFence = l + nleft;
+                int r = ro;
+                int rFence = r + nright;
+                int k = wo;
+                while (l < lFence && r < rFence) {
+                    long al = a[l];
+                    long ar = a[r];
+                    long t;
+                    if (al <= ar) {++l; t=al;} else {++r; t = ar;}
+                    w[k++] = t;
+                }
+                while (l < lFence)
+                    w[k++] = a[l++];
+                while (r < rFence)
+                    w[k++] = a[r++];
+                while (rights != null) {
+                    if (rights.tryUnfork())
+                        rights.compute();
+                    else
+                        rights.join();
+                    rights = rights.next;
+                }
+            }
+        }
+    } // FJLong
+
+    /** float support class */
+    static final class FJFloat {
+        static final class Sorter extends RecursiveAction {
+            static final long serialVersionUID = 1602600178202763377L;
+            final float[] a;    // array to be sorted.
+            final float[] w;    // workspace for merge
+            final int origin;   // origin of the part of array we deal with
+            final int n;        // Number of elements in (sub)arrays.
+            final int gran;     // split control
+
+            Sorter(float[] a, float[] w, int origin, int n, int gran) {
+                this.a = a;
+                this.w = w;
+                this.origin = origin;
+                this.n = n;
+                this.gran = gran;
+            }
+
+            public void compute() {
+                final int l = origin;
+                final int g = gran;
+                final int n = this.n;
+                final float[] a = this.a;
+                final float[] w = this.w;
+                if (n > g) {
+                    int h = n >>> 1; // half
+                    int q = n >>> 2; // lower quarter index
+                    int u = h + q;   // upper quarter
+                    FJSubSorter ls = new FJSubSorter(new Sorter(a, w, l, q,   g),
+                                                     new Sorter(a, w, l+q, h-q, g),
+                                                     new Merger(a, w, l,   q,
+                                                                l+q, h-q, l, g, null));
+                    FJSubSorter rs = new FJSubSorter(new Sorter(a, w, l + h, q,   g),
+                                                     new Sorter(a, w, l+u, n-u, g),
+                                                     new Merger(a, w, l+h, q,
+                                                                l+u, n-u, l+h, g, null));
+                    rs.fork();
+                    ls.compute();
+                    if (rs.tryUnfork()) rs.compute(); else rs.join();
+                    new Merger(w, a, l, h, l + h, n - h, l, g, null).compute();
+                } else {
+                    DualPivotQuicksort.sort(a, l, l+n-1);   // skip rangeCheck
+                }
+            }
+        }
+
+        static final class Merger extends RecursiveAction {
+            static final long serialVersionUID = 1518176433845397426L;
+            final float[] a;
+            final float[] w;
+            final int lo;
+            final int ln;
+            final int ro;
+            final int rn;
+            final int wo;
+            final int gran;
+            final Merger next;
+
+            Merger(float[] a, float[] w, int lo, int ln, int ro, int rn, int wo,
+                   int gran, Merger next) {
+                this.a = a;
+                this.w = w;
+                this.lo = lo;
+                this.ln = ln;
+                this.ro = ro;
+                this.rn = rn;
+                this.wo = wo;
+                this.gran = gran;
+                this.next = next;
+            }
+
+            public void compute() {
+                final float[] a = this.a;
+                final float[] w = this.w;
+                Merger rights = null;
+                int nleft = ln;
+                int nright = rn;
+                while (nleft > gran) {
+                    int lh = nleft >>> 1;
+                    int splitIndex = lo + lh;
+                    float split = a[splitIndex];
+                    int rl = 0;
+                    int rh = nright;
+                    while (rl < rh) {
+                        int mid = (rl + rh) >>> 1;
+                        if (Float.compare(split, a[ro+mid]) <= 0)
+                            rh = mid;
+                        else
+                            rl = mid + 1;
+                    }
+                    (rights = new Merger(a, w, splitIndex, nleft-lh, ro+rh,
+                                         nright-rh, wo+lh+rh, gran, rights)).fork();
+                    nleft = lh;
+                    nright = rh;
+                }
+
+                int l = lo;
+                int lFence = l + nleft;
+                int r = ro;
+                int rFence = r + nright;
+                int k = wo;
+                while (l < lFence && r < rFence) {
+                    float al = a[l];
+                    float ar = a[r];
+                    float t;
+                    if (Float.compare(al, ar) <= 0) {
+                        ++l;
+                        t = al;
+                    } else {
+                        ++r;
+                        t = ar;
+                    }
+                    w[k++] = t;
+                }
+                while (l < lFence)
+                    w[k++] = a[l++];
+                while (r < rFence)
+                    w[k++] = a[r++];
+                while (rights != null) {
+                    if (rights.tryUnfork())
+                        rights.compute();
+                    else
+                        rights.join();
+                    rights = rights.next;
+                }
+            }
+        }
+    } // FJFloat
+
+    /** double support class */
+    static final class FJDouble {
+        static final class Sorter extends RecursiveAction {
+            static final long serialVersionUID = 2446542900576103244L;
+            final double[] a;    // array to be sorted.
+            final double[] w;    // workspace for merge
+            final int origin;    // origin of the part of array we deal with
+            final int n;         // Number of elements in (sub)arrays.
+            final int gran;      // split control
+
+            Sorter(double[] a, double[] w, int origin, int n, int gran) {
+                this.a = a;
+                this.w = w;
+                this.origin = origin;
+                this.n = n;
+                this.gran = gran;
+            }
+
+            public void compute() {
+                final int l = origin;
+                final int g = gran;
+                final int n = this.n;
+                final double[] a = this.a;
+                final double[] w = this.w;
+                if (n > g) {
+                    int h = n >>> 1; // half
+                    int q = n >>> 2; // lower quarter index
+                    int u = h + q;   // upper quarter
+                    FJSubSorter ls = new FJSubSorter(new Sorter(a, w, l, q,   g),
+                                                     new Sorter(a, w, l+q, h-q, g),
+                                                     new Merger(a, w, l,   q,
+                                                                l+q, h-q, l, g, null));
+                    FJSubSorter rs = new FJSubSorter(new Sorter(a, w, l + h, q,   g),
+                                                     new Sorter(a, w, l+u, n-u, g),
+                                                     new Merger(a, w, l+h, q,
+                                                                l+u, n-u, l+h, g, null));
+                    rs.fork();
+                    ls.compute();
+                    if (rs.tryUnfork()) rs.compute(); else rs.join();
+                    new Merger(w, a, l, h, l + h, n - h, l, g, null).compute();
+                } else {
+                    DualPivotQuicksort.sort(a, l, l+n-1);   // skip rangeCheck
+                }
+            }
+        }
+
+        static final class Merger extends RecursiveAction {
+            static final long serialVersionUID = 8076242187166127592L;
+            final double[] a;
+            final double[] w;
+            final int lo;
+            final int ln;
+            final int ro;
+            final int rn;
+            final int wo;
+            final int gran;
+            final Merger next;
+
+            Merger(double[] a, double[] w, int lo, int ln, int ro, int rn, int wo,
+                   int gran, Merger next) {
+                this.a = a;
+                this.w = w;
+                this.lo = lo;
+                this.ln = ln;
+                this.ro = ro;
+                this.rn = rn;
+                this.wo = wo;
+                this.gran = gran;
+                this.next = next;
+            }
+
+            public void compute() {
+                final double[] a = this.a;
+                final double[] w = this.w;
+                Merger rights = null;
+                int nleft = ln;
+                int nright = rn;
+                while (nleft > gran) {
+                    int lh = nleft >>> 1;
+                    int splitIndex = lo + lh;
+                    double split = a[splitIndex];
+                    int rl = 0;
+                    int rh = nright;
+                    while (rl < rh) {
+                        int mid = (rl + rh) >>> 1;
+                        if (Double.compare(split, a[ro+mid]) <= 0)
+                            rh = mid;
+                        else
+                            rl = mid + 1;
+                    }
+                    (rights = new Merger(a, w, splitIndex, nleft-lh, ro+rh,
+                                         nright-rh, wo+lh+rh, gran, rights)).fork();
+                    nleft = lh;
+                    nright = rh;
+                }
+
+                int l = lo;
+                int lFence = l + nleft;
+                int r = ro;
+                int rFence = r + nright;
+                int k = wo;
+                while (l < lFence && r < rFence) {
+                    double al = a[l];
+                    double ar = a[r];
+                    double t;
+                    if (Double.compare(al, ar) <= 0) {
+                        ++l;
+                        t = al;
+                    } else {
+                        ++r;
+                        t = ar;
+                    }
+                    w[k++] = t;
+                }
+                while (l < lFence)
+                    w[k++] = a[l++];
+                while (r < rFence)
+                    w[k++] = a[r++];
+                while (rights != null) {
+                    if (rights.tryUnfork())
+                        rights.compute();
+                    else
+                        rights.join();
+                    rights = rights.next;
+                }
+            }
+        }
+    } // FJDouble
+
+    /** Comparable support class */
+    static final class FJComparable {
+        static final class Sorter<T extends Comparable<? super T>> extends RecursiveAction {
+            static final long serialVersionUID = -1024003289463302522L;
+            final T[] a;
+            final T[] w;
+            final int origin;
+            final int n;
+            final int gran;
+
+            Sorter(T[] a, T[] w, int origin, int n, int gran) {
+                this.a = a;
+                this.w = w;
+                this.origin = origin;
+                this.n = n;
+                this.gran = gran;
+            }
+
+            public void compute() {
+                final int l = origin;
+                final int g = gran;
+                final int n = this.n;
+                final T[] a = this.a;
+                final T[] w = this.w;
+                if (n > g) {
+                    int h = n >>> 1;
+                    int q = n >>> 2;
+                    int u = h + q;
+                    FJSubSorter ls = new FJSubSorter(new Sorter<>(a, w, l, q,   g),
+                                                     new Sorter<>(a, w, l+q, h-q, g),
+                                                     new Merger<>(a, w, l,   q,
+                                                                  l+q, h-q, l, g, null));
+                    FJSubSorter rs = new FJSubSorter(new Sorter<>(a, w, l+h, q,   g),
+                                                     new Sorter<>(a, w, l+u, n-u, g),
+                                                     new Merger<>(a, w, l+h, q,
+                                                                  l+u, n-u, l+h, g, null));
+                    rs.fork();
+                    ls.compute();
+                    if (rs.tryUnfork()) rs.compute(); else rs.join();
+                    new Merger<>(w, a, l, h, l + h, n - h, l, g, null).compute();
+                } else {
+                    Arrays.sort(a, l, l+n);
+                }
+            }
+        }
+
+        static final class Merger<T extends Comparable<? super T>> extends RecursiveAction {
+            static final long serialVersionUID = -3989771675258379302L;
+            final T[] a;
+            final T[] w;
+            final int lo;
+            final int ln;
+            final int ro;
+            final int rn;
+            final int wo;
+            final int gran;
+            final Merger<T> next;
+
+            Merger(T[] a, T[] w, int lo, int ln, int ro, int rn, int wo,
+                   int gran, Merger<T> next) {
+                this.a = a;
+                this.w = w;
+                this.lo = lo;
+                this.ln = ln;
+                this.ro = ro;
+                this.rn = rn;
+                this.wo = wo;
+                this.gran = gran;
+                this.next = next;
+            }
+
+            public void compute() {
+                final T[] a = this.a;
+                final T[] w = this.w;
+                Merger<T> rights = null;
+                int nleft = ln;
+                int nright = rn;
+                while (nleft > gran) {
+                    int lh = nleft >>> 1;
+                    int splitIndex = lo + lh;
+                    T split = a[splitIndex];
+                    int rl = 0;
+                    int rh = nright;
+                    while (rl < rh) {
+                        int mid = (rl + rh) >>> 1;
+                        if (split.compareTo(a[ro + mid]) <= 0)
+                            rh = mid;
+                        else
+                            rl = mid + 1;
+                    }
+                    (rights = new Merger<>(a, w, splitIndex, nleft-lh, ro+rh,
+                                           nright-rh, wo+lh+rh, gran, rights)).fork();
+                    nleft = lh;
+                    nright = rh;
+                }
+
+                int l = lo;
+                int lFence = l + nleft;
+                int r = ro;
+                int rFence = r + nright;
+                int k = wo;
+                while (l < lFence && r < rFence) {
+                    T al = a[l];
+                    T ar = a[r];
+                    T t;
+                    if (al.compareTo(ar) <= 0) {++l; t=al;} else {++r; t=ar; }
+                    w[k++] = t;
+                }
+                while (l < lFence)
+                    w[k++] = a[l++];
+                while (r < rFence)
+                    w[k++] = a[r++];
+                while (rights != null) {
+                    if (rights.tryUnfork())
+                        rights.compute();
+                    else
+                        rights.join();
+                    rights = rights.next;
+                }
+            }
+        }
+    } // FJComparable
+
+    /** Object + Comparator support class */
+    static final class FJComparator {
+        static final class Sorter<T> extends RecursiveAction {
+            static final long serialVersionUID = 9191600840025808581L;
+            final T[] a;       // array to be sorted.
+            final T[] w;       // workspace for merge
+            final int origin;  // origin of the part of array we deal with
+            final int n;       // Number of elements in (sub)arrays.
+            final int gran;    // split control
+            final Comparator<? super T> cmp; // Comparator to use
+
+            Sorter(T[] a, T[] w, int origin, int n, int gran, Comparator<? super T> cmp) {
+                this.a = a;
+                this.w = w;
+                this.origin = origin;
+                this.n = n;
+                this.cmp = cmp;
+                this.gran = gran;
+            }
+
+            public void compute() {
+                final int l = origin;
+                final int g = gran;
+                final int n = this.n;
+                final T[] a = this.a;
+                final T[] w = this.w;
+                if (n > g) {
+                    int h = n >>> 1; // half
+                    int q = n >>> 2; // lower quarter index
+                    int u = h + q;   // upper quarter
+                    FJSubSorter ls = new FJSubSorter(new Sorter<>(a, w, l, q,   g, cmp),
+                                                     new Sorter<>(a, w, l+q, h-q, g, cmp),
+                                                     new Merger<>(a, w, l,   q,
+                                                                  l+q, h-q, l, g, null, cmp));
+                    FJSubSorter rs = new FJSubSorter(new Sorter<>(a, w, l + h, q,   g, cmp),
+                                                     new Sorter<>(a, w, l+u, n-u, g, cmp),
+                                                     new Merger<>(a, w, l+h, q,
+                                                                  l+u, n-u, l+h, g, null, cmp));
+                    rs.fork();
+                    ls.compute();
+                    if (rs.tryUnfork()) rs.compute(); else rs.join();
+                    new Merger<>(w, a, l, h, l + h, n - h, l, g, null, cmp).compute();
+                } else {
+                    Arrays.sort(a, l, l+n, cmp);
+                }
+            }
+        }
+
+        static final class Merger<T> extends RecursiveAction {
+            static final long serialVersionUID = -2679539040379156203L;
+            final T[] a;
+            final T[] w;
+            final int lo;
+            final int ln;
+            final int ro;
+            final int rn;
+            final int wo;
+            final int gran;
+            final Merger<T> next;
+            final Comparator<? super T> cmp;
+
+            Merger(T[] a, T[] w, int lo, int ln, int ro, int rn, int wo,
+                   int gran, Merger<T> next, Comparator<? super T> cmp) {
+                this.a = a;
+                this.w = w;
+                this.lo = lo;
+                this.ln = ln;
+                this.ro = ro;
+                this.rn = rn;
+                this.wo = wo;
+                this.gran = gran;
+                this.next = next;
+                this.cmp = cmp;
+            }
+
+            public void compute() {
+                final T[] a = this.a;
+                final T[] w = this.w;
+                Merger<T> rights = null;
+                int nleft = ln;
+                int nright = rn;
+                while (nleft > gran) {
+                    int lh = nleft >>> 1;
+                    int splitIndex = lo + lh;
+                    T split = a[splitIndex];
+                    int rl = 0;
+                    int rh = nright;
+                    while (rl < rh) {
+                        int mid = (rl + rh) >>> 1;
+                        if (cmp.compare(split, a[ro+mid]) <= 0)
+                            rh = mid;
+                        else
+                            rl = mid + 1;
+                    }
+                    (rights = new Merger<>(a, w, splitIndex, nleft-lh, ro+rh,
+                                           nright-rh, wo+lh+rh, gran, rights, cmp)).fork();
+                    nleft = lh;
+                    nright = rh;
+                }
+
+                int l = lo;
+                int lFence = l + nleft;
+                int r = ro;
+                int rFence = r + nright;
+                int k = wo;
+                while (l < lFence && r < rFence) {
+                    T al = a[l];
+                    T ar = a[r];
+                    T t;
+                    if (cmp.compare(al, ar) <= 0) {
+                        ++l;
+                        t = al;
+                    } else {
+                        ++r;
+                        t = ar;
+                    }
+                    w[k++] = t;
+                }
+                while (l < lFence)
+                    w[k++] = a[l++];
+                while (r < rFence)
+                    w[k++] = a[r++];
+                while (rights != null) {
+                    if (rights.tryUnfork())
+                        rights.compute();
+                    else
+                        rights.join();
+                    rights = rights.next;
+                }
+            }
+        }
+    } // FJComparator
+
+    /** Utility class to sort half a partitioned array */
+    private static final class FJSubSorter extends RecursiveAction {
+        static final long serialVersionUID = 9159249695527935512L;
+        final RecursiveAction left;
+        final RecursiveAction right;
+        final RecursiveAction merger;
+
+        FJSubSorter(RecursiveAction left, RecursiveAction right,
+                    RecursiveAction merger) {
+            this.left = left;
+            this.right = right;
+            this.merger = merger;
+        }
+
+        public void compute() {
+            right.fork();
+            left.invoke();
+            right.join();
+            merger.invoke();
+        }
+    }
+}
--- a/jdk/src/share/classes/java/util/Calendar.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/java/util/Calendar.java	Wed Jul 05 18:34:47 2017 +0200
@@ -749,7 +749,7 @@
      *
      * @see #NARROW_STANDALONE
      * @see #SHORT_FORMAT
-     * @see #LONG_FOTMAT
+     * @see #LONG_FORMAT
      * @since 1.8
      */
     public static final int NARROW_FORMAT = 4;
--- a/jdk/src/share/classes/java/util/Properties.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/java/util/Properties.java	Wed Jul 05 18:34:47 2017 +0200
@@ -1188,7 +1188,7 @@
                         provider = loadProviderAsService(cl);
                         if (provider != null)
                             return provider;
-                        throw new InternalError("No fallback");
+                        return new jdk.internal.util.xml.BasicXmlPropertiesProvider();
                 }});
         }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/util/concurrent/CountedCompleter.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,743 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A {@link ForkJoinTask} with a completion action performed when
+ * triggered and there are no remaining pending
+ * actions. CountedCompleters are in general more robust in the
+ * presence of subtask stalls and blockage than are other forms of
+ * ForkJoinTasks, but are less intuitive to program.  Uses of
+ * CountedCompleter are similar to those of other completion based
+ * components (such as {@link java.nio.channels.CompletionHandler})
+ * except that multiple <em>pending</em> completions may be necessary
+ * to trigger the completion action {@link #onCompletion}, not just one.
+ * Unless initialized otherwise, the {@linkplain #getPendingCount pending
+ * count} starts at zero, but may be (atomically) changed using
+ * methods {@link #setPendingCount}, {@link #addToPendingCount}, and
+ * {@link #compareAndSetPendingCount}. Upon invocation of {@link
+ * #tryComplete}, if the pending action count is nonzero, it is
+ * decremented; otherwise, the completion action is performed, and if
+ * this completer itself has a completer, the process is continued
+ * with its completer.  As is the case with related synchronization
+ * components such as {@link java.util.concurrent.Phaser Phaser} and
+ * {@link java.util.concurrent.Semaphore Semaphore}, these methods
+ * affect only internal counts; they do not establish any further
+ * internal bookkeeping. In particular, the identities of pending
+ * tasks are not maintained. As illustrated below, you can create
+ * subclasses that do record some or all pending tasks or their
+ * results when needed.  As illustrated below, utility methods
+ * supporting customization of completion traversals are also
+ * provided. However, because CountedCompleters provide only basic
+ * synchronization mechanisms, it may be useful to create further
+ * abstract subclasses that maintain linkages, fields, and additional
+ * support methods appropriate for a set of related usages.
+ *
+ * <p>A concrete CountedCompleter class must define method {@link
+ * #compute}, that should in most cases (as illustrated below), invoke
+ * {@code tryComplete()} once before returning. The class may also
+ * optionally override method {@link #onCompletion} to perform an
+ * action upon normal completion, and method {@link
+ * #onExceptionalCompletion} to perform an action upon any exception.
+ *
+ * <p>CountedCompleters most often do not bear results, in which case
+ * they are normally declared as {@code CountedCompleter<Void>}, and
+ * will always return {@code null} as a result value.  In other cases,
+ * you should override method {@link #getRawResult} to provide a
+ * result from {@code join(), invoke()}, and related methods.  In
+ * general, this method should return the value of a field (or a
+ * function of one or more fields) of the CountedCompleter object that
+ * holds the result upon completion. Method {@link #setRawResult} by
+ * default plays no role in CountedCompleters.  It is possible, but
+ * rarely applicable, to override this method to maintain other
+ * objects or fields holding result data.
+ *
+ * <p>A CountedCompleter that does not itself have a completer (i.e.,
+ * one for which {@link #getCompleter} returns {@code null}) can be
+ * used as a regular ForkJoinTask with this added functionality.
+ * However, any completer that in turn has another completer serves
+ * only as an internal helper for other computations, so its own task
+ * status (as reported in methods such as {@link ForkJoinTask#isDone})
+ * is arbitrary; this status changes only upon explicit invocations of
+ * {@link #complete}, {@link ForkJoinTask#cancel}, {@link
+ * ForkJoinTask#completeExceptionally} or upon exceptional completion
+ * of method {@code compute}. Upon any exceptional completion, the
+ * exception may be relayed to a task's completer (and its completer,
+ * and so on), if one exists and it has not otherwise already
+ * completed. Similarly, cancelling an internal CountedCompleter has
+ * only a local effect on that completer, so is not often useful.
+ *
+ * <p><b>Sample Usages.</b>
+ *
+ * <p><b>Parallel recursive decomposition.</b> CountedCompleters may
+ * be arranged in trees similar to those often used with {@link
+ * RecursiveAction}s, although the constructions involved in setting
+ * them up typically vary. Here, the completer of each task is its
+ * parent in the computation tree. Even though they entail a bit more
+ * bookkeeping, CountedCompleters may be better choices when applying
+ * a possibly time-consuming operation (that cannot be further
+ * subdivided) to each element of an array or collection; especially
+ * when the operation takes a significantly different amount of time
+ * to complete for some elements than others, either because of
+ * intrinsic variation (for example I/O) or auxiliary effects such as
+ * garbage collection.  Because CountedCompleters provide their own
+ * continuations, other threads need not block waiting to perform
+ * them.
+ *
+ * <p>For example, here is an initial version of a class that uses
+ * divide-by-two recursive decomposition to divide work into single
+ * pieces (leaf tasks). Even when work is split into individual calls,
+ * tree-based techniques are usually preferable to directly forking
+ * leaf tasks, because they reduce inter-thread communication and
+ * improve load balancing. In the recursive case, the second of each
+ * pair of subtasks to finish triggers completion of its parent
+ * (because no result combination is performed, the default no-op
+ * implementation of method {@code onCompletion} is not overridden). A
+ * static utility method sets up the base task and invokes it
+ * (here, implicitly using the {@link ForkJoinPool#commonPool()}).
+ *
+ * <pre> {@code
+ * class MyOperation<E> { void apply(E e) { ... }  }
+ *
+ * class ForEach<E> extends CountedCompleter<Void> {
+ *
+ *   public static <E> void forEach(E[] array, MyOperation<E> op) {
+ *     new ForEach<E>(null, array, op, 0, array.length).invoke();
+ *   }
+ *
+ *   final E[] array; final MyOperation<E> op; final int lo, hi;
+ *   ForEach(CountedCompleter<?> p, E[] array, MyOperation<E> op, int lo, int hi) {
+ *     super(p);
+ *     this.array = array; this.op = op; this.lo = lo; this.hi = hi;
+ *   }
+ *
+ *   public void compute() { // version 1
+ *     if (hi - lo >= 2) {
+ *       int mid = (lo + hi) >>> 1;
+ *       setPendingCount(2); // must set pending count before fork
+ *       new ForEach(this, array, op, mid, hi).fork(); // right child
+ *       new ForEach(this, array, op, lo, mid).fork(); // left child
+ *     }
+ *     else if (hi > lo)
+ *       op.apply(array[lo]);
+ *     tryComplete();
+ *   }
+ * }}</pre>
+ *
+ * This design can be improved by noticing that in the recursive case,
+ * the task has nothing to do after forking its right task, so can
+ * directly invoke its left task before returning. (This is an analog
+ * of tail recursion removal.)  Also, because the task returns upon
+ * executing its left task (rather than falling through to invoke
+ * {@code tryComplete}) the pending count is set to one:
+ *
+ * <pre> {@code
+ * class ForEach<E> ...
+ *   public void compute() { // version 2
+ *     if (hi - lo >= 2) {
+ *       int mid = (lo + hi) >>> 1;
+ *       setPendingCount(1); // only one pending
+ *       new ForEach(this, array, op, mid, hi).fork(); // right child
+ *       new ForEach(this, array, op, lo, mid).compute(); // direct invoke
+ *     }
+ *     else {
+ *       if (hi > lo)
+ *         op.apply(array[lo]);
+ *       tryComplete();
+ *     }
+ *   }
+ * }</pre>
+ *
+ * As a further improvement, notice that the left task need not even
+ * exist.  Instead of creating a new one, we can iterate using the
+ * original task, and add a pending count for each fork. Additionally,
+ * because no task in this tree implements an {@link #onCompletion}
+ * method, {@code tryComplete()} can be replaced with {@link
+ * #propagateCompletion}.
+ *
+ * <pre> {@code
+ * class ForEach<E> ...
+ *   public void compute() { // version 3
+ *     int l = lo,  h = hi;
+ *     while (h - l >= 2) {
+ *       int mid = (l + h) >>> 1;
+ *       addToPendingCount(1);
+ *       new ForEach(this, array, op, mid, h).fork(); // right child
+ *       h = mid;
+ *     }
+ *     if (h > l)
+ *       op.apply(array[l]);
+ *     propagateCompletion();
+ *   }
+ * }</pre>
+ *
+ * Additional improvements of such classes might entail precomputing
+ * pending counts so that they can be established in constructors,
+ * specializing classes for leaf steps, subdividing by say, four,
+ * instead of two per iteration, and using an adaptive threshold
+ * instead of always subdividing down to single elements.
+ *
+ * <p><b>Searching.</b> A tree of CountedCompleters can search for a
+ * value or property in different parts of a data structure, and
+ * report a result in an {@link
+ * java.util.concurrent.atomic.AtomicReference AtomicReference} as
+ * soon as one is found. The others can poll the result to avoid
+ * unnecessary work. (You could additionally {@linkplain #cancel
+ * cancel} other tasks, but it is usually simpler and more efficient
+ * to just let them notice that the result is set and if so skip
+ * further processing.)  Illustrating again with an array using full
+ * partitioning (again, in practice, leaf tasks will almost always
+ * process more than one element):
+ *
+ * <pre> {@code
+ * class Searcher<E> extends CountedCompleter<E> {
+ *   final E[] array; final AtomicReference<E> result; final int lo, hi;
+ *   Searcher(CountedCompleter<?> p, E[] array, AtomicReference<E> result, int lo, int hi) {
+ *     super(p);
+ *     this.array = array; this.result = result; this.lo = lo; this.hi = hi;
+ *   }
+ *   public E getRawResult() { return result.get(); }
+ *   public void compute() { // similar to ForEach version 3
+ *     int l = lo,  h = hi;
+ *     while (result.get() == null && h >= l) {
+ *       if (h - l >= 2) {
+ *         int mid = (l + h) >>> 1;
+ *         addToPendingCount(1);
+ *         new Searcher(this, array, result, mid, h).fork();
+ *         h = mid;
+ *       }
+ *       else {
+ *         E x = array[l];
+ *         if (matches(x) && result.compareAndSet(null, x))
+ *           quietlyCompleteRoot(); // root task is now joinable
+ *         break;
+ *       }
+ *     }
+ *     tryComplete(); // normally complete whether or not found
+ *   }
+ *   boolean matches(E e) { ... } // return true if found
+ *
+ *   public static <E> E search(E[] array) {
+ *       return new Searcher<E>(null, array, new AtomicReference<E>(), 0, array.length).invoke();
+ *   }
+ *}}</pre>
+ *
+ * In this example, as well as others in which tasks have no other
+ * effects except to compareAndSet a common result, the trailing
+ * unconditional invocation of {@code tryComplete} could be made
+ * conditional ({@code if (result.get() == null) tryComplete();})
+ * because no further bookkeeping is required to manage completions
+ * once the root task completes.
+ *
+ * <p><b>Recording subtasks.</b> CountedCompleter tasks that combine
+ * results of multiple subtasks usually need to access these results
+ * in method {@link #onCompletion}. As illustrated in the following
+ * class (that performs a simplified form of map-reduce where mappings
+ * and reductions are all of type {@code E}), one way to do this in
+ * divide and conquer designs is to have each subtask record its
+ * sibling, so that it can be accessed in method {@code onCompletion}.
+ * This technique applies to reductions in which the order of
+ * combining left and right results does not matter; ordered
+ * reductions require explicit left/right designations.  Variants of
+ * other streamlinings seen in the above examples may also apply.
+ *
+ * <pre> {@code
+ * class MyMapper<E> { E apply(E v) {  ...  } }
+ * class MyReducer<E> { E apply(E x, E y) {  ...  } }
+ * class MapReducer<E> extends CountedCompleter<E> {
+ *   final E[] array; final MyMapper<E> mapper;
+ *   final MyReducer<E> reducer; final int lo, hi;
+ *   MapReducer<E> sibling;
+ *   E result;
+ *   MapReducer(CountedCompleter<?> p, E[] array, MyMapper<E> mapper,
+ *              MyReducer<E> reducer, int lo, int hi) {
+ *     super(p);
+ *     this.array = array; this.mapper = mapper;
+ *     this.reducer = reducer; this.lo = lo; this.hi = hi;
+ *   }
+ *   public void compute() {
+ *     if (hi - lo >= 2) {
+ *       int mid = (lo + hi) >>> 1;
+ *       MapReducer<E> left = new MapReducer(this, array, mapper, reducer, lo, mid);
+ *       MapReducer<E> right = new MapReducer(this, array, mapper, reducer, mid, hi);
+ *       left.sibling = right;
+ *       right.sibling = left;
+ *       setPendingCount(1); // only right is pending
+ *       right.fork();
+ *       left.compute();     // directly execute left
+ *     }
+ *     else {
+ *       if (hi > lo)
+ *           result = mapper.apply(array[lo]);
+ *       tryComplete();
+ *     }
+ *   }
+ *   public void onCompletion(CountedCompleter<?> caller) {
+ *     if (caller != this) {
+ *       MapReducer<E> child = (MapReducer<E>)caller;
+ *       MapReducer<E> sib = child.sibling;
+ *       if (sib == null || sib.result == null)
+ *         result = child.result;
+ *       else
+ *         result = reducer.apply(child.result, sib.result);
+ *     }
+ *   }
+ *   public E getRawResult() { return result; }
+ *
+ *   public static <E> E mapReduce(E[] array, MyMapper<E> mapper, MyReducer<E> reducer) {
+ *     return new MapReducer<E>(null, array, mapper, reducer,
+ *                              0, array.length).invoke();
+ *   }
+ * }}</pre>
+ *
+ * Here, method {@code onCompletion} takes a form common to many
+ * completion designs that combine results. This callback-style method
+ * is triggered once per task, in either of the two different contexts
+ * in which the pending count is, or becomes, zero: (1) by a task
+ * itself, if its pending count is zero upon invocation of {@code
+ * tryComplete}, or (2) by any of its subtasks when they complete and
+ * decrement the pending count to zero. The {@code caller} argument
+ * distinguishes cases.  Most often, when the caller is {@code this},
+ * no action is necessary. Otherwise the caller argument can be used
+ * (usually via a cast) to supply a value (and/or links to other
+ * values) to be combined.  Assuming proper use of pending counts, the
+ * actions inside {@code onCompletion} occur (once) upon completion of
+ * a task and its subtasks. No additional synchronization is required
+ * within this method to ensure thread safety of accesses to fields of
+ * this task or other completed tasks.
+ *
+ * <p><b>Completion Traversals</b>. If using {@code onCompletion} to
+ * process completions is inapplicable or inconvenient, you can use
+ * methods {@link #firstComplete} and {@link #nextComplete} to create
+ * custom traversals.  For example, to define a MapReducer that only
+ * splits out right-hand tasks in the form of the third ForEach
+ * example, the completions must cooperatively reduce along
+ * unexhausted subtask links, which can be done as follows:
+ *
+ * <pre> {@code
+ * class MapReducer<E> extends CountedCompleter<E> { // version 2
+ *   final E[] array; final MyMapper<E> mapper;
+ *   final MyReducer<E> reducer; final int lo, hi;
+ *   MapReducer<E> forks, next; // record subtask forks in list
+ *   E result;
+ *   MapReducer(CountedCompleter<?> p, E[] array, MyMapper<E> mapper,
+ *              MyReducer<E> reducer, int lo, int hi, MapReducer<E> next) {
+ *     super(p);
+ *     this.array = array; this.mapper = mapper;
+ *     this.reducer = reducer; this.lo = lo; this.hi = hi;
+ *     this.next = next;
+ *   }
+ *   public void compute() {
+ *     int l = lo,  h = hi;
+ *     while (h - l >= 2) {
+ *       int mid = (l + h) >>> 1;
+ *       addToPendingCount(1);
+ *       (forks = new MapReducer(this, array, mapper, reducer, mid, h, forks)).fork;
+ *       h = mid;
+ *     }
+ *     if (h > l)
+ *       result = mapper.apply(array[l]);
+ *     // process completions by reducing along and advancing subtask links
+ *     for (CountedCompleter<?> c = firstComplete(); c != null; c = c.nextComplete()) {
+ *       for (MapReducer t = (MapReducer)c, s = t.forks;  s != null; s = t.forks = s.next)
+ *         t.result = reducer.apply(t.result, s.result);
+ *     }
+ *   }
+ *   public E getRawResult() { return result; }
+ *
+ *   public static <E> E mapReduce(E[] array, MyMapper<E> mapper, MyReducer<E> reducer) {
+ *     return new MapReducer<E>(null, array, mapper, reducer,
+ *                              0, array.length, null).invoke();
+ *   }
+ * }}</pre>
+ *
+ * <p><b>Triggers.</b> Some CountedCompleters are themselves never
+ * forked, but instead serve as bits of plumbing in other designs;
+ * including those in which the completion of one of more async tasks
+ * triggers another async task. For example:
+ *
+ * <pre> {@code
+ * class HeaderBuilder extends CountedCompleter<...> { ... }
+ * class BodyBuilder extends CountedCompleter<...> { ... }
+ * class PacketSender extends CountedCompleter<...> {
+ *   PacketSender(...) { super(null, 1); ... } // trigger on second completion
+ *   public void compute() { } // never called
+ *   public void onCompletion(CountedCompleter<?> caller) { sendPacket(); }
+ * }
+ * // sample use:
+ * PacketSender p = new PacketSender();
+ * new HeaderBuilder(p, ...).fork();
+ * new BodyBuilder(p, ...).fork();
+ * }</pre>
+ *
+ * @since 1.8
+ * @author Doug Lea
+ */
+public abstract class CountedCompleter<T> extends ForkJoinTask<T> {
+    private static final long serialVersionUID = 5232453752276485070L;
+
+    /** This task's completer, or null if none */
+    final CountedCompleter<?> completer;
+    /** The number of pending tasks until completion */
+    volatile int pending;
+
+    /**
+     * Creates a new CountedCompleter with the given completer
+     * and initial pending count.
+     *
+     * @param completer this task's completer, or {@code null} if none
+     * @param initialPendingCount the initial pending count
+     */
+    protected CountedCompleter(CountedCompleter<?> completer,
+                               int initialPendingCount) {
+        this.completer = completer;
+        this.pending = initialPendingCount;
+    }
+
+    /**
+     * Creates a new CountedCompleter with the given completer
+     * and an initial pending count of zero.
+     *
+     * @param completer this task's completer, or {@code null} if none
+     */
+    protected CountedCompleter(CountedCompleter<?> completer) {
+        this.completer = completer;
+    }
+
+    /**
+     * Creates a new CountedCompleter with no completer
+     * and an initial pending count of zero.
+     */
+    protected CountedCompleter() {
+        this.completer = null;
+    }
+
+    /**
+     * The main computation performed by this task.
+     */
+    public abstract void compute();
+
+    /**
+     * Performs an action when method {@link #tryComplete} is invoked
+     * and the pending count is zero, or when the unconditional
+     * method {@link #complete} is invoked.  By default, this method
+     * does nothing. You can distinguish cases by checking the
+     * identity of the given caller argument. If not equal to {@code
+     * this}, then it is typically a subtask that may contain results
+     * (and/or links to other results) to combine.
+     *
+     * @param caller the task invoking this method (which may
+     * be this task itself).
+     */
+    public void onCompletion(CountedCompleter<?> caller) {
+    }
+
+    /**
+     * Performs an action when method {@link #completeExceptionally}
+     * is invoked or method {@link #compute} throws an exception, and
+     * this task has not otherwise already completed normally. On
+     * entry to this method, this task {@link
+     * ForkJoinTask#isCompletedAbnormally}.  The return value of this
+     * method controls further propagation: If {@code true} and this
+     * task has a completer, then this completer is also completed
+     * exceptionally.  The default implementation of this method does
+     * nothing except return {@code true}.
+     *
+     * @param ex the exception
+     * @param caller the task invoking this method (which may
+     * be this task itself).
+     * @return true if this exception should be propagated to this
+     * task's completer, if one exists.
+     */
+    public boolean onExceptionalCompletion(Throwable ex, CountedCompleter<?> caller) {
+        return true;
+    }
+
+    /**
+     * Returns the completer established in this task's constructor,
+     * or {@code null} if none.
+     *
+     * @return the completer
+     */
+    public final CountedCompleter<?> getCompleter() {
+        return completer;
+    }
+
+    /**
+     * Returns the current pending count.
+     *
+     * @return the current pending count
+     */
+    public final int getPendingCount() {
+        return pending;
+    }
+
+    /**
+     * Sets the pending count to the given value.
+     *
+     * @param count the count
+     */
+    public final void setPendingCount(int count) {
+        pending = count;
+    }
+
+    /**
+     * Adds (atomically) the given value to the pending count.
+     *
+     * @param delta the value to add
+     */
+    public final void addToPendingCount(int delta) {
+        int c; // note: can replace with intrinsic in jdk8
+        do {} while (!U.compareAndSwapInt(this, PENDING, c = pending, c+delta));
+    }
+
+    /**
+     * Sets (atomically) the pending count to the given count only if
+     * it currently holds the given expected value.
+     *
+     * @param expected the expected value
+     * @param count the new value
+     * @return true if successful
+     */
+    public final boolean compareAndSetPendingCount(int expected, int count) {
+        return U.compareAndSwapInt(this, PENDING, expected, count);
+    }
+
+    /**
+     * If the pending count is nonzero, (atomically) decrements it.
+     *
+     * @return the initial (undecremented) pending count holding on entry
+     * to this method
+     */
+    public final int decrementPendingCountUnlessZero() {
+        int c;
+        do {} while ((c = pending) != 0 &&
+                     !U.compareAndSwapInt(this, PENDING, c, c - 1));
+        return c;
+    }
+
+    /**
+     * Returns the root of the current computation; i.e., this
+     * task if it has no completer, else its completer's root.
+     *
+     * @return the root of the current computation
+     */
+    public final CountedCompleter<?> getRoot() {
+        CountedCompleter<?> a = this, p;
+        while ((p = a.completer) != null)
+            a = p;
+        return a;
+    }
+
+    /**
+     * If the pending count is nonzero, decrements the count;
+     * otherwise invokes {@link #onCompletion} and then similarly
+     * tries to complete this task's completer, if one exists,
+     * else marks this task as complete.
+     */
+    public final void tryComplete() {
+        CountedCompleter<?> a = this, s = a;
+        for (int c;;) {
+            if ((c = a.pending) == 0) {
+                a.onCompletion(s);
+                if ((a = (s = a).completer) == null) {
+                    s.quietlyComplete();
+                    return;
+                }
+            }
+            else if (U.compareAndSwapInt(a, PENDING, c, c - 1))
+                return;
+        }
+    }
+
+    /**
+     * Equivalent to {@link #tryComplete} but does not invoke {@link
+     * #onCompletion} along the completion path: If the pending count
+     * is nonzero, decrements the count; otherwise, similarly tries to
+     * complete this task's completer, if one exists, else marks this
+     * task as complete. This method may be useful in cases where
+     * {@code onCompletion} should not, or need not, be invoked for
+     * each completer in a computation.
+     */
+    public final void propagateCompletion() {
+        CountedCompleter<?> a = this, s = a;
+        for (int c;;) {
+            if ((c = a.pending) == 0) {
+                if ((a = (s = a).completer) == null) {
+                    s.quietlyComplete();
+                    return;
+                }
+            }
+            else if (U.compareAndSwapInt(a, PENDING, c, c - 1))
+                return;
+        }
+    }
+
+    /**
+     * Regardless of pending count, invokes {@link #onCompletion},
+     * marks this task as complete and further triggers {@link
+     * #tryComplete} on this task's completer, if one exists.  The
+     * given rawResult is used as an argument to {@link #setRawResult}
+     * before invoking {@link #onCompletion} or marking this task as
+     * complete; its value is meaningful only for classes overriding
+     * {@code setRawResult}.
+     *
+     * <p>This method may be useful when forcing completion as soon as
+     * any one (versus all) of several subtask results are obtained.
+     * However, in the common (and recommended) case in which {@code
+     * setRawResult} is not overridden, this effect can be obtained
+     * more simply using {@code quietlyCompleteRoot();}.
+     *
+     * @param rawResult the raw result
+     */
+    public void complete(T rawResult) {
+        CountedCompleter<?> p;
+        setRawResult(rawResult);
+        onCompletion(this);
+        quietlyComplete();
+        if ((p = completer) != null)
+            p.tryComplete();
+    }
+
+
+    /**
+     * If this task's pending count is zero, returns this task;
+     * otherwise decrements its pending count and returns {@code
+     * null}. This method is designed to be used with {@link
+     * #nextComplete} in completion traversal loops.
+     *
+     * @return this task, if pending count was zero, else {@code null}
+     */
+    public final CountedCompleter<?> firstComplete() {
+        for (int c;;) {
+            if ((c = pending) == 0)
+                return this;
+            else if (U.compareAndSwapInt(this, PENDING, c, c - 1))
+                return null;
+        }
+    }
+
+    /**
+     * If this task does not have a completer, invokes {@link
+     * ForkJoinTask#quietlyComplete} and returns {@code null}.  Or, if
+     * this task's pending count is non-zero, decrements its pending
+     * count and returns {@code null}.  Otherwise, returns the
+     * completer.  This method can be used as part of a completion
+     * traversal loop for homogeneous task hierarchies:
+     *
+     * <pre> {@code
+     * for (CountedCompleter<?> c = firstComplete();
+     *      c != null;
+     *      c = c.nextComplete()) {
+     *   // ... process c ...
+     * }}</pre>
+     *
+     * @return the completer, or {@code null} if none
+     */
+    public final CountedCompleter<?> nextComplete() {
+        CountedCompleter<?> p;
+        if ((p = completer) != null)
+            return p.firstComplete();
+        else {
+            quietlyComplete();
+            return null;
+        }
+    }
+
+    /**
+     * Equivalent to {@code getRoot().quietlyComplete()}.
+     */
+    public final void quietlyCompleteRoot() {
+        for (CountedCompleter<?> a = this, p;;) {
+            if ((p = a.completer) == null) {
+                a.quietlyComplete();
+                return;
+            }
+            a = p;
+        }
+    }
+
+    /**
+     * Supports ForkJoinTask exception propagation.
+     */
+    void internalPropagateException(Throwable ex) {
+        CountedCompleter<?> a = this, s = a;
+        while (a.onExceptionalCompletion(ex, s) &&
+               (a = (s = a).completer) != null && a.status >= 0)
+            a.recordExceptionalCompletion(ex);
+    }
+
+    /**
+     * Implements execution conventions for CountedCompleters.
+     */
+    protected final boolean exec() {
+        compute();
+        return false;
+    }
+
+    /**
+     * Returns the result of the computation. By default
+     * returns {@code null}, which is appropriate for {@code Void}
+     * actions, but in other cases should be overridden, almost
+     * always to return a field or function of a field that
+     * holds the result upon completion.
+     *
+     * @return the result of the computation
+     */
+    public T getRawResult() { return null; }
+
+    /**
+     * A method that result-bearing CountedCompleters may optionally
+     * use to help maintain result data.  By default, does nothing.
+     * Overrides are not recommended. However, if this method is
+     * overridden to update existing objects or fields, then it must
+     * in general be defined to be thread-safe.
+     */
+    protected void setRawResult(T t) { }
+
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe U;
+    private static final long PENDING;
+    static {
+        try {
+            U = sun.misc.Unsafe.getUnsafe();
+            PENDING = U.objectFieldOffset
+                (CountedCompleter.class.getDeclaredField("pending"));
+        } catch (Exception e) {
+            throw new Error(e);
+        }
+    }
+}
--- a/jdk/src/share/classes/java/util/concurrent/ForkJoinPool.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/java/util/concurrent/ForkJoinPool.java	Wed Jul 05 18:34:47 2017 +0200
@@ -40,7 +40,6 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
-import java.util.Random;
 import java.util.concurrent.AbstractExecutorService;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutorService;
@@ -48,11 +47,6 @@
 import java.util.concurrent.RejectedExecutionException;
 import java.util.concurrent.RunnableFuture;
 import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.locks.LockSupport;
-import java.util.concurrent.locks.ReentrantLock;
-import java.util.concurrent.locks.Condition;
 
 /**
  * An {@link ExecutorService} for running {@link ForkJoinTask}s.
@@ -63,21 +57,31 @@
  * <p>A {@code ForkJoinPool} differs from other kinds of {@link
  * ExecutorService} mainly by virtue of employing
  * <em>work-stealing</em>: all threads in the pool attempt to find and
- * execute subtasks created by other active tasks (eventually blocking
- * waiting for work if none exist). This enables efficient processing
- * when most tasks spawn other subtasks (as do most {@code
- * ForkJoinTask}s). When setting <em>asyncMode</em> to true in
- * constructors, {@code ForkJoinPool}s may also be appropriate for use
- * with event-style tasks that are never joined.
+ * execute tasks submitted to the pool and/or created by other active
+ * tasks (eventually blocking waiting for work if none exist). This
+ * enables efficient processing when most tasks spawn other subtasks
+ * (as do most {@code ForkJoinTask}s), as well as when many small
+ * tasks are submitted to the pool from external clients.  Especially
+ * when setting <em>asyncMode</em> to true in constructors, {@code
+ * ForkJoinPool}s may also be appropriate for use with event-style
+ * tasks that are never joined.
  *
- * <p>A {@code ForkJoinPool} is constructed with a given target
- * parallelism level; by default, equal to the number of available
- * processors. The pool attempts to maintain enough active (or
- * available) threads by dynamically adding, suspending, or resuming
- * internal worker threads, even if some tasks are stalled waiting to
- * join others. However, no such adjustments are guaranteed in the
- * face of blocked IO or other unmanaged synchronization. The nested
- * {@link ManagedBlocker} interface enables extension of the kinds of
+ * <p>A static {@link #commonPool()} is available and appropriate for
+ * most applications. The common pool is used by any ForkJoinTask that
+ * is not explicitly submitted to a specified pool. Using the common
+ * pool normally reduces resource usage (its threads are slowly
+ * reclaimed during periods of non-use, and reinstated upon subsequent
+ * use).
+ *
+ * <p>For applications that require separate or custom pools, a {@code
+ * ForkJoinPool} may be constructed with a given target parallelism
+ * level; by default, equal to the number of available processors. The
+ * pool attempts to maintain enough active (or available) threads by
+ * dynamically adding, suspending, or resuming internal worker
+ * threads, even if some tasks are stalled waiting to join
+ * others. However, no such adjustments are guaranteed in the face of
+ * blocked I/O or other unmanaged synchronization. The nested {@link
+ * ManagedBlocker} interface enables extension of the kinds of
  * synchronization accommodated.
  *
  * <p>In addition to execution and lifecycle control methods, this
@@ -87,16 +91,17 @@
  * {@link #toString} returns indications of pool state in a
  * convenient form for informal monitoring.
  *
- * <p> As is the case with other ExecutorServices, there are three
- * main task execution methods summarized in the following
- * table. These are designed to be used by clients not already engaged
- * in fork/join computations in the current pool.  The main forms of
- * these methods accept instances of {@code ForkJoinTask}, but
- * overloaded forms also allow mixed execution of plain {@code
+ * <p>As is the case with other ExecutorServices, there are three
+ * main task execution methods summarized in the following table.
+ * These are designed to be used primarily by clients not already
+ * engaged in fork/join computations in the current pool.  The main
+ * forms of these methods accept instances of {@code ForkJoinTask},
+ * but overloaded forms also allow mixed execution of plain {@code
  * Runnable}- or {@code Callable}- based activities as well.  However,
- * tasks that are already executing in a pool should normally
- * <em>NOT</em> use these pool execution methods, but instead use the
- * within-computation forms listed in the table.
+ * tasks that are already executing in a pool should normally instead
+ * use the within-computation forms listed in the table unless using
+ * async event-style tasks that are not usually joined, in which case
+ * there is little difference among choice of methods.
  *
  * <table BORDER CELLPADDING=3 CELLSPACING=1>
  *  <tr>
@@ -121,23 +126,16 @@
  *  </tr>
  * </table>
  *
- * <p><b>Sample Usage.</b> Normally a single {@code ForkJoinPool} is
- * used for all parallel task execution in a program or subsystem.
- * Otherwise, use would not usually outweigh the construction and
- * bookkeeping overhead of creating a large set of threads. For
- * example, a common pool could be used for the {@code SortTasks}
- * illustrated in {@link RecursiveAction}. Because {@code
- * ForkJoinPool} uses threads in {@linkplain java.lang.Thread#isDaemon
- * daemon} mode, there is typically no need to explicitly {@link
- * #shutdown} such a pool upon program exit.
- *
- * <pre>
- * static final ForkJoinPool mainPool = new ForkJoinPool();
- * ...
- * public void sort(long[] array) {
- *   mainPool.invoke(new SortTask(array, 0, array.length));
- * }
- * </pre>
+ * <p>The common pool is by default constructed with default
+ * parameters, but these may be controlled by setting three {@link
+ * System#getProperty system properties} with prefix {@code
+ * java.util.concurrent.ForkJoinPool.common}: {@code parallelism} --
+ * an integer greater than zero, {@code threadFactory} -- the class
+ * name of a {@link ForkJoinWorkerThreadFactory}, and {@code
+ * exceptionHandler} -- the class name of a {@link
+ * java.lang.Thread.UncaughtExceptionHandler
+ * Thread.UncaughtExceptionHandler}. Upon any error in establishing
+ * these settings, default parameters are used.
  *
  * <p><b>Implementation notes</b>: This implementation restricts the
  * maximum number of running threads to 32767. Attempts to create
@@ -156,214 +154,388 @@
     /*
      * Implementation Overview
      *
-     * This class provides the central bookkeeping and control for a
-     * set of worker threads: Submissions from non-FJ threads enter
-     * into a submission queue. Workers take these tasks and typically
-     * split them into subtasks that may be stolen by other workers.
-     * Preference rules give first priority to processing tasks from
-     * their own queues (LIFO or FIFO, depending on mode), then to
-     * randomized FIFO steals of tasks in other worker queues, and
-     * lastly to new submissions.
+     * This class and its nested classes provide the main
+     * functionality and control for a set of worker threads:
+     * Submissions from non-FJ threads enter into submission queues.
+     * Workers take these tasks and typically split them into subtasks
+     * that may be stolen by other workers.  Preference rules give
+     * first priority to processing tasks from their own queues (LIFO
+     * or FIFO, depending on mode), then to randomized FIFO steals of
+     * tasks in other queues.
+     *
+     * WorkQueues
+     * ==========
+     *
+     * Most operations occur within work-stealing queues (in nested
+     * class WorkQueue).  These are special forms of Deques that
+     * support only three of the four possible end-operations -- push,
+     * pop, and poll (aka steal), under the further constraints that
+     * push and pop are called only from the owning thread (or, as
+     * extended here, under a lock), while poll may be called from
+     * other threads.  (If you are unfamiliar with them, you probably
+     * want to read Herlihy and Shavit's book "The Art of
+     * Multiprocessor programming", chapter 16 describing these in
+     * more detail before proceeding.)  The main work-stealing queue
+     * design is roughly similar to those in the papers "Dynamic
+     * Circular Work-Stealing Deque" by Chase and Lev, SPAA 2005
+     * (http://research.sun.com/scalable/pubs/index.html) and
+     * "Idempotent work stealing" by Michael, Saraswat, and Vechev,
+     * PPoPP 2009 (http://portal.acm.org/citation.cfm?id=1504186).
+     * The main differences ultimately stem from GC requirements that
+     * we null out taken slots as soon as we can, to maintain as small
+     * a footprint as possible even in programs generating huge
+     * numbers of tasks. To accomplish this, we shift the CAS
+     * arbitrating pop vs poll (steal) from being on the indices
+     * ("base" and "top") to the slots themselves.  So, both a
+     * successful pop and poll mainly entail a CAS of a slot from
+     * non-null to null.  Because we rely on CASes of references, we
+     * do not need tag bits on base or top.  They are simple ints as
+     * used in any circular array-based queue (see for example
+     * ArrayDeque).  Updates to the indices must still be ordered in a
+     * way that guarantees that top == base means the queue is empty,
+     * but otherwise may err on the side of possibly making the queue
+     * appear nonempty when a push, pop, or poll have not fully
+     * committed. Note that this means that the poll operation,
+     * considered individually, is not wait-free. One thief cannot
+     * successfully continue until another in-progress one (or, if
+     * previously empty, a push) completes.  However, in the
+     * aggregate, we ensure at least probabilistic non-blockingness.
+     * If an attempted steal fails, a thief always chooses a different
+     * random victim target to try next. So, in order for one thief to
+     * progress, it suffices for any in-progress poll or new push on
+     * any empty queue to complete. (This is why we normally use
+     * method pollAt and its variants that try once at the apparent
+     * base index, else consider alternative actions, rather than
+     * method poll.)
+     *
+     * This approach also enables support of a user mode in which local
+     * task processing is in FIFO, not LIFO order, simply by using
+     * poll rather than pop.  This can be useful in message-passing
+     * frameworks in which tasks are never joined.  However neither
+     * mode considers affinities, loads, cache localities, etc, so
+     * rarely provide the best possible performance on a given
+     * machine, but portably provide good throughput by averaging over
+     * these factors.  (Further, even if we did try to use such
+     * information, we do not usually have a basis for exploiting it.
+     * For example, some sets of tasks profit from cache affinities,
+     * but others are harmed by cache pollution effects.)
+     *
+     * WorkQueues are also used in a similar way for tasks submitted
+     * to the pool. We cannot mix these tasks in the same queues used
+     * for work-stealing (this would contaminate lifo/fifo
+     * processing). Instead, we randomly associate submission queues
+     * with submitting threads, using a form of hashing.  The
+     * ThreadLocal Submitter class contains a value initially used as
+     * a hash code for choosing existing queues, but may be randomly
+     * repositioned upon contention with other submitters.  In
+     * essence, submitters act like workers except that they are
+     * restricted to executing local tasks that they submitted (or in
+     * the case of CountedCompleters, others with the same root task).
+     * However, because most shared/external queue operations are more
+     * expensive than internal, and because, at steady state, external
+     * submitters will compete for CPU with workers, ForkJoinTask.join
+     * and related methods disable them from repeatedly helping to
+     * process tasks if all workers are active.  Insertion of tasks in
+     * shared mode requires a lock (mainly to protect in the case of
+     * resizing) but we use only a simple spinlock (using bits in
+     * field qlock), because submitters encountering a busy queue move
+     * on to try or create other queues -- they block only when
+     * creating and registering new queues.
+     *
+     * Management
+     * ==========
      *
      * The main throughput advantages of work-stealing stem from
      * decentralized control -- workers mostly take tasks from
      * themselves or each other. We cannot negate this in the
      * implementation of other management responsibilities. The main
      * tactic for avoiding bottlenecks is packing nearly all
-     * essentially atomic control state into a single 64bit volatile
-     * variable ("ctl"). This variable is read on the order of 10-100
-     * times as often as it is modified (always via CAS). (There is
-     * some additional control state, for example variable "shutdown"
-     * for which we can cope with uncoordinated updates.)  This
-     * streamlines synchronization and control at the expense of messy
-     * constructions needed to repack status bits upon updates.
-     * Updates tend not to contend with each other except during
-     * bursts while submitted tasks begin or end.  In some cases when
-     * they do contend, threads can instead do something else
-     * (usually, scan for tasks) until contention subsides.
+     * essentially atomic control state into two volatile variables
+     * that are by far most often read (not written) as status and
+     * consistency checks.
      *
-     * To enable packing, we restrict maximum parallelism to (1<<15)-1
-     * (which is far in excess of normal operating range) to allow
-     * ids, counts, and their negations (used for thresholding) to fit
-     * into 16bit fields.
+     * Field "ctl" contains 64 bits holding all the information needed
+     * to atomically decide to add, inactivate, enqueue (on an event
+     * queue), dequeue, and/or re-activate workers.  To enable this
+     * packing, we restrict maximum parallelism to (1<<15)-1 (which is
+     * far in excess of normal operating range) to allow ids, counts,
+     * and their negations (used for thresholding) to fit into 16bit
+     * fields.
+     *
+     * Field "plock" is a form of sequence lock with a saturating
+     * shutdown bit (similarly for per-queue "qlocks"), mainly
+     * protecting updates to the workQueues array, as well as to
+     * enable shutdown.  When used as a lock, it is normally only very
+     * briefly held, so is nearly always available after at most a
+     * brief spin, but we use a monitor-based backup strategy to
+     * block when needed.
      *
-     * Recording Workers.  Workers are recorded in the "workers" array
-     * that is created upon pool construction and expanded if (rarely)
-     * necessary.  This is an array as opposed to some other data
-     * structure to support index-based random steals by workers.
-     * Updates to the array recording new workers and unrecording
-     * terminated ones are protected from each other by a seqLock
-     * (scanGuard) but the array is otherwise concurrently readable,
-     * and accessed directly by workers. To simplify index-based
-     * operations, the array size is always a power of two, and all
-     * readers must tolerate null slots. To avoid flailing during
-     * start-up, the array is presized to hold twice #parallelism
-     * workers (which is unlikely to need further resizing during
-     * execution). But to avoid dealing with so many null slots,
-     * variable scanGuard includes a mask for the nearest power of two
-     * that contains all current workers.  All worker thread creation
-     * is on-demand, triggered by task submissions, replacement of
-     * terminated workers, and/or compensation for blocked
-     * workers. However, all other support code is set up to work with
-     * other policies.  To ensure that we do not hold on to worker
-     * references that would prevent GC, ALL accesses to workers are
-     * via indices into the workers array (which is one source of some
-     * of the messy code constructions here). In essence, the workers
-     * array serves as a weak reference mechanism. Thus for example
-     * the wait queue field of ctl stores worker indices, not worker
-     * references.  Access to the workers in associated methods (for
-     * example signalWork) must both index-check and null-check the
-     * IDs. All such accesses ignore bad IDs by returning out early
-     * from what they are doing, since this can only be associated
-     * with termination, in which case it is OK to give up.
+     * Recording WorkQueues.  WorkQueues are recorded in the
+     * "workQueues" array that is created upon first use and expanded
+     * if necessary.  Updates to the array while recording new workers
+     * and unrecording terminated ones are protected from each other
+     * by a lock but the array is otherwise concurrently readable, and
+     * accessed directly.  To simplify index-based operations, the
+     * array size is always a power of two, and all readers must
+     * tolerate null slots. Worker queues are at odd indices. Shared
+     * (submission) queues are at even indices, up to a maximum of 64
+     * slots, to limit growth even if array needs to expand to add
+     * more workers. Grouping them together in this way simplifies and
+     * speeds up task scanning.
      *
-     * All uses of the workers array, as well as queue arrays, check
-     * that the array is non-null (even if previously non-null). This
-     * allows nulling during termination, which is currently not
-     * necessary, but remains an option for resource-revocation-based
-     * shutdown schemes.
+     * All worker thread creation is on-demand, triggered by task
+     * submissions, replacement of terminated workers, and/or
+     * compensation for blocked workers. However, all other support
+     * code is set up to work with other policies.  To ensure that we
+     * do not hold on to worker references that would prevent GC, ALL
+     * accesses to workQueues are via indices into the workQueues
+     * array (which is one source of some of the messy code
+     * constructions here). In essence, the workQueues array serves as
+     * a weak reference mechanism. Thus for example the wait queue
+     * field of ctl stores indices, not references.  Access to the
+     * workQueues in associated methods (for example signalWork) must
+     * both index-check and null-check the IDs. All such accesses
+     * ignore bad IDs by returning out early from what they are doing,
+     * since this can only be associated with termination, in which
+     * case it is OK to give up.  All uses of the workQueues array
+     * also check that it is non-null (even if previously
+     * non-null). This allows nulling during termination, which is
+     * currently not necessary, but remains an option for
+     * resource-revocation-based shutdown schemes. It also helps
+     * reduce JIT issuance of uncommon-trap code, which tends to
+     * unnecessarily complicate control flow in some methods.
      *
-     * Wait Queuing. Unlike HPC work-stealing frameworks, we cannot
+     * Event Queuing. Unlike HPC work-stealing frameworks, we cannot
      * let workers spin indefinitely scanning for tasks when none can
      * be found immediately, and we cannot start/resume workers unless
      * there appear to be tasks available.  On the other hand, we must
      * quickly prod them into action when new tasks are submitted or
-     * generated.  We park/unpark workers after placing in an event
-     * wait queue when they cannot find work. This "queue" is actually
-     * a simple Treiber stack, headed by the "id" field of ctl, plus a
-     * 15bit counter value to both wake up waiters (by advancing their
-     * count) and avoid ABA effects. Successors are held in worker
-     * field "nextWait".  Queuing deals with several intrinsic races,
-     * mainly that a task-producing thread can miss seeing (and
+     * generated. In many usages, ramp-up time to activate workers is
+     * the main limiting factor in overall performance (this is
+     * compounded at program start-up by JIT compilation and
+     * allocation). So we try to streamline this as much as possible.
+     * We park/unpark workers after placing in an event wait queue
+     * when they cannot find work. This "queue" is actually a simple
+     * Treiber stack, headed by the "id" field of ctl, plus a 15bit
+     * counter value (that reflects the number of times a worker has
+     * been inactivated) to avoid ABA effects (we need only as many
+     * version numbers as worker threads). Successors are held in
+     * field WorkQueue.nextWait.  Queuing deals with several intrinsic
+     * races, mainly that a task-producing thread can miss seeing (and
      * signalling) another thread that gave up looking for work but
      * has not yet entered the wait queue. We solve this by requiring
-     * a full sweep of all workers both before (in scan()) and after
-     * (in tryAwaitWork()) a newly waiting worker is added to the wait
-     * queue. During a rescan, the worker might release some other
-     * queued worker rather than itself, which has the same net
-     * effect. Because enqueued workers may actually be rescanning
-     * rather than waiting, we set and clear the "parked" field of
-     * ForkJoinWorkerThread to reduce unnecessary calls to unpark.
-     * (Use of the parked field requires a secondary recheck to avoid
-     * missed signals.)
+     * a full sweep of all workers (via repeated calls to method
+     * scan()) both before and after a newly waiting worker is added
+     * to the wait queue. During a rescan, the worker might release
+     * some other queued worker rather than itself, which has the same
+     * net effect. Because enqueued workers may actually be rescanning
+     * rather than waiting, we set and clear the "parker" field of
+     * WorkQueues to reduce unnecessary calls to unpark.  (This
+     * requires a secondary recheck to avoid missed signals.)  Note
+     * the unusual conventions about Thread.interrupts surrounding
+     * parking and other blocking: Because interrupts are used solely
+     * to alert threads to check termination, which is checked anyway
+     * upon blocking, we clear status (using Thread.interrupted)
+     * before any call to park, so that park does not immediately
+     * return due to status being set via some other unrelated call to
+     * interrupt in user code.
      *
      * Signalling.  We create or wake up workers only when there
      * appears to be at least one task they might be able to find and
-     * execute.  When a submission is added or another worker adds a
-     * task to a queue that previously had two or fewer tasks, they
-     * signal waiting workers (or trigger creation of new ones if
-     * fewer than the given parallelism level -- see signalWork).
-     * These primary signals are buttressed by signals during rescans
-     * as well as those performed when a worker steals a task and
-     * notices that there are more tasks too; together these cover the
-     * signals needed in cases when more than two tasks are pushed
-     * but untaken.
+     * execute. However, many other threads may notice the same task
+     * and each signal to wake up a thread that might take it. So in
+     * general, pools will be over-signalled.  When a submission is
+     * added or another worker adds a task to a queue that has fewer
+     * than two tasks, they signal waiting workers (or trigger
+     * creation of new ones if fewer than the given parallelism level
+     * -- signalWork), and may leave a hint to the unparked worker to
+     * help signal others upon wakeup).  These primary signals are
+     * buttressed by others (see method helpSignal) whenever other
+     * threads scan for work or do not have a task to process.  On
+     * most platforms, signalling (unpark) overhead time is noticeably
+     * long, and the time between signalling a thread and it actually
+     * making progress can be very noticeably long, so it is worth
+     * offloading these delays from critical paths as much as
+     * possible.
      *
      * Trimming workers. To release resources after periods of lack of
      * use, a worker starting to wait when the pool is quiescent will
-     * time out and terminate if the pool has remained quiescent for
-     * SHRINK_RATE nanosecs. This will slowly propagate, eventually
-     * terminating all workers after long periods of non-use.
-     *
-     * Submissions. External submissions are maintained in an
-     * array-based queue that is structured identically to
-     * ForkJoinWorkerThread queues except for the use of
-     * submissionLock in method addSubmission. Unlike the case for
-     * worker queues, multiple external threads can add new
-     * submissions, so adding requires a lock.
+     * time out and terminate if the pool has remained quiescent for a
+     * given period -- a short period if there are more threads than
+     * parallelism, longer as the number of threads decreases. This
+     * will slowly propagate, eventually terminating all workers after
+     * periods of non-use.
      *
-     * Compensation. Beyond work-stealing support and lifecycle
-     * control, the main responsibility of this framework is to take
-     * actions when one worker is waiting to join a task stolen (or
-     * always held by) another.  Because we are multiplexing many
-     * tasks on to a pool of workers, we can't just let them block (as
-     * in Thread.join).  We also cannot just reassign the joiner's
-     * run-time stack with another and replace it later, which would
-     * be a form of "continuation", that even if possible is not
-     * necessarily a good idea since we sometimes need both an
-     * unblocked task and its continuation to progress. Instead we
-     * combine two tactics:
+     * Shutdown and Termination. A call to shutdownNow atomically sets
+     * a plock bit and then (non-atomically) sets each worker's
+     * qlock status, cancels all unprocessed tasks, and wakes up
+     * all waiting workers.  Detecting whether termination should
+     * commence after a non-abrupt shutdown() call requires more work
+     * and bookkeeping. We need consensus about quiescence (i.e., that
+     * there is no more work). The active count provides a primary
+     * indication but non-abrupt shutdown still requires a rechecking
+     * scan for any workers that are inactive but not queued.
+     *
+     * Joining Tasks
+     * =============
+     *
+     * Any of several actions may be taken when one worker is waiting
+     * to join a task stolen (or always held) by another.  Because we
+     * are multiplexing many tasks on to a pool of workers, we can't
+     * just let them block (as in Thread.join).  We also cannot just
+     * reassign the joiner's run-time stack with another and replace
+     * it later, which would be a form of "continuation", that even if
+     * possible is not necessarily a good idea since we sometimes need
+     * both an unblocked task and its continuation to progress.
+     * Instead we combine two tactics:
      *
      *   Helping: Arranging for the joiner to execute some task that it
-     *      would be running if the steal had not occurred.  Method
-     *      ForkJoinWorkerThread.joinTask tracks joining->stealing
-     *      links to try to find such a task.
+     *      would be running if the steal had not occurred.
      *
      *   Compensating: Unless there are already enough live threads,
-     *      method tryPreBlock() may create or re-activate a spare
-     *      thread to compensate for blocked joiners until they
-     *      unblock.
+     *      method tryCompensate() may create or re-activate a spare
+     *      thread to compensate for blocked joiners until they unblock.
+     *
+     * A third form (implemented in tryRemoveAndExec) amounts to
+     * helping a hypothetical compensator: If we can readily tell that
+     * a possible action of a compensator is to steal and execute the
+     * task being joined, the joining thread can do so directly,
+     * without the need for a compensation thread (although at the
+     * expense of larger run-time stacks, but the tradeoff is
+     * typically worthwhile).
      *
      * The ManagedBlocker extension API can't use helping so relies
      * only on compensation in method awaitBlocker.
      *
+     * The algorithm in tryHelpStealer entails a form of "linear"
+     * helping: Each worker records (in field currentSteal) the most
+     * recent task it stole from some other worker. Plus, it records
+     * (in field currentJoin) the task it is currently actively
+     * joining. Method tryHelpStealer uses these markers to try to
+     * find a worker to help (i.e., steal back a task from and execute
+     * it) that could hasten completion of the actively joined task.
+     * In essence, the joiner executes a task that would be on its own
+     * local deque had the to-be-joined task not been stolen. This may
+     * be seen as a conservative variant of the approach in Wagner &
+     * Calder "Leapfrogging: a portable technique for implementing
+     * efficient futures" SIGPLAN Notices, 1993
+     * (http://portal.acm.org/citation.cfm?id=155354). It differs in
+     * that: (1) We only maintain dependency links across workers upon
+     * steals, rather than use per-task bookkeeping.  This sometimes
+     * requires a linear scan of workQueues array to locate stealers,
+     * but often doesn't because stealers leave hints (that may become
+     * stale/wrong) of where to locate them.  It is only a hint
+     * because a worker might have had multiple steals and the hint
+     * records only one of them (usually the most current).  Hinting
+     * isolates cost to when it is needed, rather than adding to
+     * per-task overhead.  (2) It is "shallow", ignoring nesting and
+     * potentially cyclic mutual steals.  (3) It is intentionally
+     * racy: field currentJoin is updated only while actively joining,
+     * which means that we miss links in the chain during long-lived
+     * tasks, GC stalls etc (which is OK since blocking in such cases
+     * is usually a good idea).  (4) We bound the number of attempts
+     * to find work (see MAX_HELP) and fall back to suspending the
+     * worker and if necessary replacing it with another.
+     *
+     * Helping actions for CountedCompleters are much simpler: Method
+     * helpComplete can take and execute any task with the same root
+     * as the task being waited on. However, this still entails some
+     * traversal of completer chains, so is less efficient than using
+     * CountedCompleters without explicit joins.
+     *
      * It is impossible to keep exactly the target parallelism number
      * of threads running at any given time.  Determining the
      * existence of conservatively safe helping targets, the
      * availability of already-created spares, and the apparent need
-     * to create new spares are all racy and require heuristic
-     * guidance, so we rely on multiple retries of each.  Currently,
-     * in keeping with on-demand signalling policy, we compensate only
-     * if blocking would leave less than one active (non-waiting,
-     * non-blocked) worker. Additionally, to avoid some false alarms
-     * due to GC, lagging counters, system activity, etc, compensated
-     * blocking for joins is only attempted after rechecks stabilize
-     * (retries are interspersed with Thread.yield, for good
-     * citizenship).  The variable blockedCount, incremented before
-     * blocking and decremented after, is sometimes needed to
-     * distinguish cases of waiting for work vs blocking on joins or
-     * other managed sync. Both cases are equivalent for most pool
-     * control, so we can update non-atomically. (Additionally,
-     * contention on blockedCount alleviates some contention on ctl).
+     * to create new spares are all racy, so we rely on multiple
+     * retries of each.  Compensation in the apparent absence of
+     * helping opportunities is challenging to control on JVMs, where
+     * GC and other activities can stall progress of tasks that in
+     * turn stall out many other dependent tasks, without us being
+     * able to determine whether they will ever require compensation.
+     * Even though work-stealing otherwise encounters little
+     * degradation in the presence of more threads than cores,
+     * aggressively adding new threads in such cases entails risk of
+     * unwanted positive feedback control loops in which more threads
+     * cause more dependent stalls (as well as delayed progress of
+     * unblocked threads to the point that we know they are available)
+     * leading to more situations requiring more threads, and so
+     * on. This aspect of control can be seen as an (analytically
+     * intractable) game with an opponent that may choose the worst
+     * (for us) active thread to stall at any time.  We take several
+     * precautions to bound losses (and thus bound gains), mainly in
+     * methods tryCompensate and awaitJoin.
+     *
+     * Common Pool
+     * ===========
      *
-     * Shutdown and Termination. A call to shutdownNow atomically sets
-     * the ctl stop bit and then (non-atomically) sets each workers
-     * "terminate" status, cancels all unprocessed tasks, and wakes up
-     * all waiting workers.  Detecting whether termination should
-     * commence after a non-abrupt shutdown() call requires more work
-     * and bookkeeping. We need consensus about quiesence (i.e., that
-     * there is no more work) which is reflected in active counts so
-     * long as there are no current blockers, as well as possible
-     * re-evaluations during independent changes in blocking or
-     * quiescing workers.
+     * The static commonPool always exists after static
+     * initialization.  Since it (or any other created pool) need
+     * never be used, we minimize initial construction overhead and
+     * footprint to the setup of about a dozen fields, with no nested
+     * allocation. Most bootstrapping occurs within method
+     * fullExternalPush during the first submission to the pool.
      *
-     * Style notes: There is a lot of representation-level coupling
-     * among classes ForkJoinPool, ForkJoinWorkerThread, and
-     * ForkJoinTask.  Most fields of ForkJoinWorkerThread maintain
-     * data structures managed by ForkJoinPool, so are directly
-     * accessed.  Conversely we allow access to "workers" array by
-     * workers, and direct access to ForkJoinTask.status by both
-     * ForkJoinPool and ForkJoinWorkerThread.  There is little point
+     * When external threads submit to the common pool, they can
+     * perform some subtask processing (see externalHelpJoin and
+     * related methods).  We do not need to record whether these
+     * submissions are to the common pool -- if not, externalHelpJoin
+     * returns quickly (at the most helping to signal some common pool
+     * workers). These submitters would otherwise be blocked waiting
+     * for completion, so the extra effort (with liberally sprinkled
+     * task status checks) in inapplicable cases amounts to an odd
+     * form of limited spin-wait before blocking in ForkJoinTask.join.
+     *
+     * Style notes
+     * ===========
+     *
+     * There is a lot of representation-level coupling among classes
+     * ForkJoinPool, ForkJoinWorkerThread, and ForkJoinTask.  The
+     * fields of WorkQueue maintain data structures managed by
+     * ForkJoinPool, so are directly accessed.  There is little point
      * trying to reduce this, since any associated future changes in
      * representations will need to be accompanied by algorithmic
-     * changes anyway. All together, these low-level implementation
-     * choices produce as much as a factor of 4 performance
-     * improvement compared to naive implementations, and enable the
-     * processing of billions of tasks per second, at the expense of
-     * some ugliness.
+     * changes anyway. Several methods intrinsically sprawl because
+     * they must accumulate sets of consistent reads of volatiles held
+     * in local variables.  Methods signalWork() and scan() are the
+     * main bottlenecks, so are especially heavily
+     * micro-optimized/mangled.  There are lots of inline assignments
+     * (of form "while ((local = field) != 0)") which are usually the
+     * simplest way to ensure the required read orderings (which are
+     * sometimes critical). This leads to a "C"-like style of listing
+     * declarations of these locals at the heads of methods or blocks.
+     * There are several occurrences of the unusual "do {} while
+     * (!cas...)"  which is the simplest way to force an update of a
+     * CAS'ed variable. There are also other coding oddities (including
+     * several unnecessary-looking hoisted null checks) that help
+     * some methods perform reasonably even when interpreted (not
+     * compiled).
      *
-     * Methods signalWork() and scan() are the main bottlenecks so are
-     * especially heavily micro-optimized/mangled.  There are lots of
-     * inline assignments (of form "while ((local = field) != 0)")
-     * which are usually the simplest way to ensure the required read
-     * orderings (which are sometimes critical). This leads to a
-     * "C"-like style of listing declarations of these locals at the
-     * heads of methods or blocks.  There are several occurrences of
-     * the unusual "do {} while (!cas...)"  which is the simplest way
-     * to force an update of a CAS'ed variable. There are also other
-     * coding oddities that help some methods perform reasonably even
-     * when interpreted (not compiled).
-     *
-     * The order of declarations in this file is: (1) declarations of
-     * statics (2) fields (along with constants used when unpacking
-     * some of them), listed in an order that tends to reduce
-     * contention among them a bit under most JVMs.  (3) internal
-     * control methods (4) callbacks and other support for
-     * ForkJoinTask and ForkJoinWorkerThread classes, (5) exported
-     * methods (plus a few little helpers). (6) static block
-     * initializing all statics in a minimally dependent order.
+     * The order of declarations in this file is:
+     * (1) Static utility functions
+     * (2) Nested (static) classes
+     * (3) Static fields
+     * (4) Fields, along with constants used when unpacking some of them
+     * (5) Internal control methods
+     * (6) Callbacks and other support for ForkJoinTask methods
+     * (7) Exported methods
+     * (8) Static block initializing statics in minimally dependent order
      */
 
+    // Static utilities
+
+    /**
+     * If there is a security manager, makes sure caller has
+     * permission to modify threads.
+     */
+    private static void checkPermission() {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null)
+            security.checkPermission(modifyThreadPermission);
+    }
+
+    // Nested classes
+
     /**
      * Factory for creating new {@link ForkJoinWorkerThread}s.
      * A {@code ForkJoinWorkerThreadFactory} must be defined and used
@@ -384,14 +556,526 @@
      * Default ForkJoinWorkerThreadFactory implementation; creates a
      * new ForkJoinWorkerThread.
      */
-    static class DefaultForkJoinWorkerThreadFactory
+    static final class DefaultForkJoinWorkerThreadFactory
         implements ForkJoinWorkerThreadFactory {
-        public ForkJoinWorkerThread newThread(ForkJoinPool pool) {
+        public final ForkJoinWorkerThread newThread(ForkJoinPool pool) {
             return new ForkJoinWorkerThread(pool);
         }
     }
 
     /**
+     * Per-thread records for threads that submit to pools. Currently
+     * holds only pseudo-random seed / index that is used to choose
+     * submission queues in method externalPush. In the future, this may
+     * also incorporate a means to implement different task rejection
+     * and resubmission policies.
+     *
+     * Seeds for submitters and workers/workQueues work in basically
+     * the same way but are initialized and updated using slightly
+     * different mechanics. Both are initialized using the same
+     * approach as in class ThreadLocal, where successive values are
+     * unlikely to collide with previous values. Seeds are then
+     * randomly modified upon collisions using xorshifts, which
+     * requires a non-zero seed.
+     */
+    static final class Submitter {
+        int seed;
+        Submitter(int s) { seed = s; }
+    }
+
+    /**
+     * Class for artificial tasks that are used to replace the target
+     * of local joins if they are removed from an interior queue slot
+     * in WorkQueue.tryRemoveAndExec. We don't need the proxy to
+     * actually do anything beyond having a unique identity.
+     */
+    static final class EmptyTask extends ForkJoinTask<Void> {
+        private static final long serialVersionUID = -7721805057305804111L;
+        EmptyTask() { status = ForkJoinTask.NORMAL; } // force done
+        public final Void getRawResult() { return null; }
+        public final void setRawResult(Void x) {}
+        public final boolean exec() { return true; }
+    }
+
+    /**
+     * Queues supporting work-stealing as well as external task
+     * submission. See above for main rationale and algorithms.
+     * Implementation relies heavily on "Unsafe" intrinsics
+     * and selective use of "volatile":
+     *
+     * Field "base" is the index (mod array.length) of the least valid
+     * queue slot, which is always the next position to steal (poll)
+     * from if nonempty. Reads and writes require volatile orderings
+     * but not CAS, because updates are only performed after slot
+     * CASes.
+     *
+     * Field "top" is the index (mod array.length) of the next queue
+     * slot to push to or pop from. It is written only by owner thread
+     * for push, or under lock for external/shared push, and accessed
+     * by other threads only after reading (volatile) base.  Both top
+     * and base are allowed to wrap around on overflow, but (top -
+     * base) (or more commonly -(base - top) to force volatile read of
+     * base before top) still estimates size. The lock ("qlock") is
+     * forced to -1 on termination, causing all further lock attempts
+     * to fail. (Note: we don't need CAS for termination state because
+     * upon pool shutdown, all shared-queues will stop being used
+     * anyway.)  Nearly all lock bodies are set up so that exceptions
+     * within lock bodies are "impossible" (modulo JVM errors that
+     * would cause failure anyway.)
+     *
+     * The array slots are read and written using the emulation of
+     * volatiles/atomics provided by Unsafe. Insertions must in
+     * general use putOrderedObject as a form of releasing store to
+     * ensure that all writes to the task object are ordered before
+     * its publication in the queue.  All removals entail a CAS to
+     * null.  The array is always a power of two. To ensure safety of
+     * Unsafe array operations, all accesses perform explicit null
+     * checks and implicit bounds checks via power-of-two masking.
+     *
+     * In addition to basic queuing support, this class contains
+     * fields described elsewhere to control execution. It turns out
+     * to work better memory-layout-wise to include them in this class
+     * rather than a separate class.
+     *
+     * Performance on most platforms is very sensitive to placement of
+     * instances of both WorkQueues and their arrays -- we absolutely
+     * do not want multiple WorkQueue instances or multiple queue
+     * arrays sharing cache lines. (It would be best for queue objects
+     * and their arrays to share, but there is nothing available to
+     * help arrange that).  Unfortunately, because they are recorded
+     * in a common array, WorkQueue instances are often moved to be
+     * adjacent by garbage collectors. To reduce impact, we use field
+     * padding that works OK on common platforms; this effectively
+     * trades off slightly slower average field access for the sake of
+     * avoiding really bad worst-case access. (Until better JVM
+     * support is in place, this padding is dependent on transient
+     * properties of JVM field layout rules.) We also take care in
+     * allocating, sizing and resizing the array. Non-shared queue
+     * arrays are initialized by workers before use. Others are
+     * allocated on first use.
+     */
+    static final class WorkQueue {
+        /**
+         * Capacity of work-stealing queue array upon initialization.
+         * Must be a power of two; at least 4, but should be larger to
+         * reduce or eliminate cacheline sharing among queues.
+         * Currently, it is much larger, as a partial workaround for
+         * the fact that JVMs often place arrays in locations that
+         * share GC bookkeeping (especially cardmarks) such that
+         * per-write accesses encounter serious memory contention.
+         */
+        static final int INITIAL_QUEUE_CAPACITY = 1 << 13;
+
+        /**
+         * Maximum size for queue arrays. Must be a power of two less
+         * than or equal to 1 << (31 - width of array entry) to ensure
+         * lack of wraparound of index calculations, but defined to a
+         * value a bit less than this to help users trap runaway
+         * programs before saturating systems.
+         */
+        static final int MAXIMUM_QUEUE_CAPACITY = 1 << 26; // 64M
+
+        // Heuristic padding to ameliorate unfortunate memory placements
+        volatile long pad00, pad01, pad02, pad03, pad04, pad05, pad06;
+
+        int seed;                  // for random scanning; initialize nonzero
+        volatile int eventCount;   // encoded inactivation count; < 0 if inactive
+        int nextWait;              // encoded record of next event waiter
+        int hint;                  // steal or signal hint (index)
+        int poolIndex;             // index of this queue in pool (or 0)
+        final int mode;            // 0: lifo, > 0: fifo, < 0: shared
+        int nsteals;               // number of steals
+        volatile int qlock;        // 1: locked, -1: terminate; else 0
+        volatile int base;         // index of next slot for poll
+        int top;                   // index of next slot for push
+        ForkJoinTask<?>[] array;   // the elements (initially unallocated)
+        final ForkJoinPool pool;   // the containing pool (may be null)
+        final ForkJoinWorkerThread owner; // owning thread or null if shared
+        volatile Thread parker;    // == owner during call to park; else null
+        volatile ForkJoinTask<?> currentJoin;  // task being joined in awaitJoin
+        ForkJoinTask<?> currentSteal; // current non-local task being executed
+
+        volatile Object pad10, pad11, pad12, pad13, pad14, pad15, pad16, pad17;
+        volatile Object pad18, pad19, pad1a, pad1b, pad1c, pad1d;
+
+        WorkQueue(ForkJoinPool pool, ForkJoinWorkerThread owner, int mode,
+                  int seed) {
+            this.pool = pool;
+            this.owner = owner;
+            this.mode = mode;
+            this.seed = seed;
+            // Place indices in the center of array (that is not yet allocated)
+            base = top = INITIAL_QUEUE_CAPACITY >>> 1;
+        }
+
+        /**
+         * Returns the approximate number of tasks in the queue.
+         */
+        final int queueSize() {
+            int n = base - top;       // non-owner callers must read base first
+            return (n >= 0) ? 0 : -n; // ignore transient negative
+        }
+
+       /**
+         * Provides a more accurate estimate of whether this queue has
+         * any tasks than does queueSize, by checking whether a
+         * near-empty queue has at least one unclaimed task.
+         */
+        final boolean isEmpty() {
+            ForkJoinTask<?>[] a; int m, s;
+            int n = base - (s = top);
+            return (n >= 0 ||
+                    (n == -1 &&
+                     ((a = array) == null ||
+                      (m = a.length - 1) < 0 ||
+                      U.getObject
+                      (a, (long)((m & (s - 1)) << ASHIFT) + ABASE) == null)));
+        }
+
+        /**
+         * Pushes a task. Call only by owner in unshared queues.  (The
+         * shared-queue version is embedded in method externalPush.)
+         *
+         * @param task the task. Caller must ensure non-null.
+         * @throw RejectedExecutionException if array cannot be resized
+         */
+        final void push(ForkJoinTask<?> task) {
+            ForkJoinTask<?>[] a; ForkJoinPool p;
+            int s = top, m, n;
+            if ((a = array) != null) {    // ignore if queue removed
+                int j = (((m = a.length - 1) & s) << ASHIFT) + ABASE;
+                U.putOrderedObject(a, j, task);
+                if ((n = (top = s + 1) - base) <= 2) {
+                    if ((p = pool) != null)
+                        p.signalWork(this);
+                }
+                else if (n >= m)
+                    growArray();
+            }
+        }
+
+       /**
+         * Initializes or doubles the capacity of array. Call either
+         * by owner or with lock held -- it is OK for base, but not
+         * top, to move while resizings are in progress.
+         */
+        final ForkJoinTask<?>[] growArray() {
+            ForkJoinTask<?>[] oldA = array;
+            int size = oldA != null ? oldA.length << 1 : INITIAL_QUEUE_CAPACITY;
+            if (size > MAXIMUM_QUEUE_CAPACITY)
+                throw new RejectedExecutionException("Queue capacity exceeded");
+            int oldMask, t, b;
+            ForkJoinTask<?>[] a = array = new ForkJoinTask<?>[size];
+            if (oldA != null && (oldMask = oldA.length - 1) >= 0 &&
+                (t = top) - (b = base) > 0) {
+                int mask = size - 1;
+                do {
+                    ForkJoinTask<?> x;
+                    int oldj = ((b & oldMask) << ASHIFT) + ABASE;
+                    int j    = ((b &    mask) << ASHIFT) + ABASE;
+                    x = (ForkJoinTask<?>)U.getObjectVolatile(oldA, oldj);
+                    if (x != null &&
+                        U.compareAndSwapObject(oldA, oldj, x, null))
+                        U.putObjectVolatile(a, j, x);
+                } while (++b != t);
+            }
+            return a;
+        }
+
+        /**
+         * Takes next task, if one exists, in LIFO order.  Call only
+         * by owner in unshared queues.
+         */
+        final ForkJoinTask<?> pop() {
+            ForkJoinTask<?>[] a; ForkJoinTask<?> t; int m;
+            if ((a = array) != null && (m = a.length - 1) >= 0) {
+                for (int s; (s = top - 1) - base >= 0;) {
+                    long j = ((m & s) << ASHIFT) + ABASE;
+                    if ((t = (ForkJoinTask<?>)U.getObject(a, j)) == null)
+                        break;
+                    if (U.compareAndSwapObject(a, j, t, null)) {
+                        top = s;
+                        return t;
+                    }
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Takes a task in FIFO order if b is base of queue and a task
+         * can be claimed without contention. Specialized versions
+         * appear in ForkJoinPool methods scan and tryHelpStealer.
+         */
+        final ForkJoinTask<?> pollAt(int b) {
+            ForkJoinTask<?> t; ForkJoinTask<?>[] a;
+            if ((a = array) != null) {
+                int j = (((a.length - 1) & b) << ASHIFT) + ABASE;
+                if ((t = (ForkJoinTask<?>)U.getObjectVolatile(a, j)) != null &&
+                    base == b &&
+                    U.compareAndSwapObject(a, j, t, null)) {
+                    base = b + 1;
+                    return t;
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Takes next task, if one exists, in FIFO order.
+         */
+        final ForkJoinTask<?> poll() {
+            ForkJoinTask<?>[] a; int b; ForkJoinTask<?> t;
+            while ((b = base) - top < 0 && (a = array) != null) {
+                int j = (((a.length - 1) & b) << ASHIFT) + ABASE;
+                t = (ForkJoinTask<?>)U.getObjectVolatile(a, j);
+                if (t != null) {
+                    if (base == b &&
+                        U.compareAndSwapObject(a, j, t, null)) {
+                        base = b + 1;
+                        return t;
+                    }
+                }
+                else if (base == b) {
+                    if (b + 1 == top)
+                        break;
+                    Thread.yield(); // wait for lagging update (very rare)
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Takes next task, if one exists, in order specified by mode.
+         */
+        final ForkJoinTask<?> nextLocalTask() {
+            return mode == 0 ? pop() : poll();
+        }
+
+        /**
+         * Returns next task, if one exists, in order specified by mode.
+         */
+        final ForkJoinTask<?> peek() {
+            ForkJoinTask<?>[] a = array; int m;
+            if (a == null || (m = a.length - 1) < 0)
+                return null;
+            int i = mode == 0 ? top - 1 : base;
+            int j = ((i & m) << ASHIFT) + ABASE;
+            return (ForkJoinTask<?>)U.getObjectVolatile(a, j);
+        }
+
+        /**
+         * Pops the given task only if it is at the current top.
+         * (A shared version is available only via FJP.tryExternalUnpush)
+         */
+        final boolean tryUnpush(ForkJoinTask<?> t) {
+            ForkJoinTask<?>[] a; int s;
+            if ((a = array) != null && (s = top) != base &&
+                U.compareAndSwapObject
+                (a, (((a.length - 1) & --s) << ASHIFT) + ABASE, t, null)) {
+                top = s;
+                return true;
+            }
+            return false;
+        }
+
+        /**
+         * Removes and cancels all known tasks, ignoring any exceptions.
+         */
+        final void cancelAll() {
+            ForkJoinTask.cancelIgnoringExceptions(currentJoin);
+            ForkJoinTask.cancelIgnoringExceptions(currentSteal);
+            for (ForkJoinTask<?> t; (t = poll()) != null; )
+                ForkJoinTask.cancelIgnoringExceptions(t);
+        }
+
+        /**
+         * Computes next value for random probes.  Scans don't require
+         * a very high quality generator, but also not a crummy one.
+         * Marsaglia xor-shift is cheap and works well enough.  Note:
+         * This is manually inlined in its usages in ForkJoinPool to
+         * avoid writes inside busy scan loops.
+         */
+        final int nextSeed() {
+            int r = seed;
+            r ^= r << 13;
+            r ^= r >>> 17;
+            return seed = r ^= r << 5;
+        }
+
+        // Specialized execution methods
+
+        /**
+         * Pops and runs tasks until empty.
+         */
+        private void popAndExecAll() {
+            // A bit faster than repeated pop calls
+            ForkJoinTask<?>[] a; int m, s; long j; ForkJoinTask<?> t;
+            while ((a = array) != null && (m = a.length - 1) >= 0 &&
+                   (s = top - 1) - base >= 0 &&
+                   (t = ((ForkJoinTask<?>)
+                         U.getObject(a, j = ((m & s) << ASHIFT) + ABASE)))
+                   != null) {
+                if (U.compareAndSwapObject(a, j, t, null)) {
+                    top = s;
+                    t.doExec();
+                }
+            }
+        }
+
+        /**
+         * Polls and runs tasks until empty.
+         */
+        private void pollAndExecAll() {
+            for (ForkJoinTask<?> t; (t = poll()) != null;)
+                t.doExec();
+        }
+
+        /**
+         * If present, removes from queue and executes the given task,
+         * or any other cancelled task. Returns (true) on any CAS
+         * or consistency check failure so caller can retry.
+         *
+         * @return false if no progress can be made, else true;
+         */
+        final boolean tryRemoveAndExec(ForkJoinTask<?> task) {
+            boolean stat = true, removed = false, empty = true;
+            ForkJoinTask<?>[] a; int m, s, b, n;
+            if ((a = array) != null && (m = a.length - 1) >= 0 &&
+                (n = (s = top) - (b = base)) > 0) {
+                for (ForkJoinTask<?> t;;) {           // traverse from s to b
+                    int j = ((--s & m) << ASHIFT) + ABASE;
+                    t = (ForkJoinTask<?>)U.getObjectVolatile(a, j);
+                    if (t == null)                    // inconsistent length
+                        break;
+                    else if (t == task) {
+                        if (s + 1 == top) {           // pop
+                            if (!U.compareAndSwapObject(a, j, task, null))
+                                break;
+                            top = s;
+                            removed = true;
+                        }
+                        else if (base == b)           // replace with proxy
+                            removed = U.compareAndSwapObject(a, j, task,
+                                                             new EmptyTask());
+                        break;
+                    }
+                    else if (t.status >= 0)
+                        empty = false;
+                    else if (s + 1 == top) {          // pop and throw away
+                        if (U.compareAndSwapObject(a, j, t, null))
+                            top = s;
+                        break;
+                    }
+                    if (--n == 0) {
+                        if (!empty && base == b)
+                            stat = false;
+                        break;
+                    }
+                }
+            }
+            if (removed)
+                task.doExec();
+            return stat;
+        }
+
+        /**
+         * Polls for and executes the given task or any other task in
+         * its CountedCompleter computation
+         */
+        final boolean pollAndExecCC(ForkJoinTask<?> root) {
+            ForkJoinTask<?>[] a; int b; Object o;
+            outer: while ((b = base) - top < 0 && (a = array) != null) {
+                long j = (((a.length - 1) & b) << ASHIFT) + ABASE;
+                if ((o = U.getObject(a, j)) == null ||
+                    !(o instanceof CountedCompleter))
+                    break;
+                for (CountedCompleter<?> t = (CountedCompleter<?>)o, r = t;;) {
+                    if (r == root) {
+                        if (base == b &&
+                            U.compareAndSwapObject(a, j, t, null)) {
+                            base = b + 1;
+                            t.doExec();
+                            return true;
+                        }
+                        else
+                            break; // restart
+                    }
+                    if ((r = r.completer) == null)
+                        break outer; // not part of root computation
+                }
+            }
+            return false;
+        }
+
+        /**
+         * Executes a top-level task and any local tasks remaining
+         * after execution.
+         */
+        final void runTask(ForkJoinTask<?> t) {
+            if (t != null) {
+                (currentSteal = t).doExec();
+                currentSteal = null;
+                ++nsteals;
+                if (base - top < 0) {       // process remaining local tasks
+                    if (mode == 0)
+                        popAndExecAll();
+                    else
+                        pollAndExecAll();
+                }
+            }
+        }
+
+        /**
+         * Executes a non-top-level (stolen) task.
+         */
+        final void runSubtask(ForkJoinTask<?> t) {
+            if (t != null) {
+                ForkJoinTask<?> ps = currentSteal;
+                (currentSteal = t).doExec();
+                currentSteal = ps;
+            }
+        }
+
+        /**
+         * Returns true if owned and not known to be blocked.
+         */
+        final boolean isApparentlyUnblocked() {
+            Thread wt; Thread.State s;
+            return (eventCount >= 0 &&
+                    (wt = owner) != null &&
+                    (s = wt.getState()) != Thread.State.BLOCKED &&
+                    s != Thread.State.WAITING &&
+                    s != Thread.State.TIMED_WAITING);
+        }
+
+        // Unsafe mechanics
+        private static final sun.misc.Unsafe U;
+        private static final long QLOCK;
+        private static final int ABASE;
+        private static final int ASHIFT;
+        static {
+            int s;
+            try {
+                U = sun.misc.Unsafe.getUnsafe();
+                Class<?> k = WorkQueue.class;
+                Class<?> ak = ForkJoinTask[].class;
+                QLOCK = U.objectFieldOffset
+                    (k.getDeclaredField("qlock"));
+                ABASE = U.arrayBaseOffset(ak);
+                s = U.arrayIndexScale(ak);
+            } catch (Exception e) {
+                throw new Error(e);
+            }
+            if ((s & (s-1)) != 0)
+                throw new Error("data type scale not a power of two");
+            ASHIFT = 31 - Integer.numberOfLeadingZeros(s);
+        }
+    }
+
+    // static fields (initialized in static initializer below)
+
+    /**
      * Creates a new ForkJoinWorkerThread. This factory is used unless
      * overridden in ForkJoinPool constructors.
      */
@@ -399,107 +1083,93 @@
         defaultForkJoinWorkerThreadFactory;
 
     /**
+     * Per-thread submission bookkeeping. Shared across all pools
+     * to reduce ThreadLocal pollution and because random motion
+     * to avoid contention in one pool is likely to hold for others.
+     * Lazily initialized on first submission (but null-checked
+     * in other contexts to avoid unnecessary initialization).
+     */
+    static final ThreadLocal<Submitter> submitters;
+
+    /**
      * Permission required for callers of methods that may start or
      * kill threads.
      */
     private static final RuntimePermission modifyThreadPermission;
 
     /**
-     * If there is a security manager, makes sure caller has
-     * permission to modify threads.
+     * Common (static) pool. Non-null for public use unless a static
+     * construction exception, but internal usages null-check on use
+     * to paranoically avoid potential initialization circularities
+     * as well as to simplify generated code.
      */
-    private static void checkPermission() {
-        SecurityManager security = System.getSecurityManager();
-        if (security != null)
-            security.checkPermission(modifyThreadPermission);
-    }
+    static final ForkJoinPool commonPool;
 
     /**
-     * Generator for assigning sequence numbers as pool names.
+     * Common pool parallelism. Must equal commonPool.parallelism.
      */
-    private static final AtomicInteger poolNumberGenerator;
+    static final int commonPoolParallelism;
 
     /**
-     * Generator for initial random seeds for worker victim
-     * selection. This is used only to create initial seeds. Random
-     * steals use a cheaper xorshift generator per steal attempt. We
-     * don't expect much contention on seedGenerator, so just use a
-     * plain Random.
+     * Sequence number for creating workerNamePrefix.
      */
-    static final Random workerSeedGenerator;
+    private static int poolNumberSequence;
 
     /**
-     * Array holding all worker threads in the pool.  Initialized upon
-     * construction. Array size must be a power of two.  Updates and
-     * replacements are protected by scanGuard, but the array is
-     * always kept in a consistent enough state to be randomly
-     * accessed without locking by workers performing work-stealing,
-     * as well as other traversal-based methods in this class, so long
-     * as reads memory-acquire by first reading ctl. All readers must
-     * tolerate that some array slots may be null.
+     * Return the next sequence number. We don't expect this to
+     * ever contend so use simple builtin sync.
      */
-    ForkJoinWorkerThread[] workers;
+    private static final synchronized int nextPoolId() {
+        return ++poolNumberSequence;
+    }
 
-    /**
-     * Initial size for submission queue array. Must be a power of
-     * two.  In many applications, these always stay small so we use a
-     * small initial cap.
-     */
-    private static final int INITIAL_QUEUE_CAPACITY = 8;
+    // static constants
 
     /**
-     * Maximum size for submission queue array. Must be a power of two
-     * less than or equal to 1 << (31 - width of array entry) to
-     * ensure lack of index wraparound, but is capped at a lower
-     * value to help users trap runaway computations.
+     * Initial timeout value (in nanoseconds) for the thread
+     * triggering quiescence to park waiting for new work. On timeout,
+     * the thread will instead try to shrink the number of
+     * workers. The value should be large enough to avoid overly
+     * aggressive shrinkage during most transient stalls (long GCs
+     * etc).
      */
-    private static final int MAXIMUM_QUEUE_CAPACITY = 1 << 24; // 16M
+    private static final long IDLE_TIMEOUT      = 2000L * 1000L * 1000L; // 2sec
 
     /**
-     * Array serving as submission queue. Initialized upon construction.
+     * Timeout value when there are more threads than parallelism level
      */
-    private ForkJoinTask<?>[] submissionQueue;
+    private static final long FAST_IDLE_TIMEOUT =  200L * 1000L * 1000L;
 
     /**
-     * Lock protecting submissions array for addSubmission
+     * Tolerance for idle timeouts, to cope with timer undershoots
      */
-    private final ReentrantLock submissionLock;
-
-    /**
-     * Condition for awaitTermination, using submissionLock for
-     * convenience.
-     */
-    private final Condition termination;
+    private static final long TIMEOUT_SLOP = 2000000L;
 
     /**
-     * Creation factory for worker threads.
+     * The maximum stolen->joining link depth allowed in method
+     * tryHelpStealer.  Must be a power of two.  Depths for legitimate
+     * chains are unbounded, but we use a fixed constant to avoid
+     * (otherwise unchecked) cycles and to bound staleness of
+     * traversal parameters at the expense of sometimes blocking when
+     * we could be helping.
      */
-    private final ForkJoinWorkerThreadFactory factory;
-
-    /**
-     * The uncaught exception handler used when any worker abruptly
-     * terminates.
-     */
-    final Thread.UncaughtExceptionHandler ueh;
+    private static final int MAX_HELP = 64;
 
     /**
-     * Prefix for assigning names to worker threads
+     * Increment for seed generators. See class ThreadLocal for
+     * explanation.
      */
-    private final String workerNamePrefix;
+    private static final int SEED_INCREMENT = 0x61c88647;
 
     /**
-     * Sum of per-thread steal counts, updated only when threads are
-     * idle or terminating.
-     */
-    private volatile long stealCount;
-
-    /**
-     * Main pool control -- a long packed with:
+     * Bits and masks for control variables
+     *
+     * Field ctl is a long packed with:
      * AC: Number of active running workers minus target parallelism (16 bits)
-     * TC: Number of total workers minus target parallelism (16bits)
+     * TC: Number of total workers minus target parallelism (16 bits)
      * ST: true if pool is terminating (1 bit)
      * EC: the wait count of top waiting thread (15 bits)
-     * ID: ~poolIndex of top of Treiber stack of waiting threads (16 bits)
+     * ID: poolIndex of top of Treiber stack of waiters (16 bits)
      *
      * When convenient, we can extract the upper 32 bits of counts and
      * the lower 32 bits of queue state, u = (int)(ctl >>> 32) and e =
@@ -508,13 +1178,26 @@
      * parallelism and the positionings of fields makes it possible to
      * perform the most common checks via sign tests of fields: When
      * ac is negative, there are not enough active workers, when tc is
-     * negative, there are not enough total workers, when id is
-     * negative, there is at least one waiting worker, and when e is
+     * negative, there are not enough total workers, and when e is
      * negative, the pool is terminating.  To deal with these possibly
      * negative fields, we use casts in and out of "short" and/or
      * signed shifts to maintain signedness.
+     *
+     * When a thread is queued (inactivated), its eventCount field is
+     * set negative, which is the only way to tell if a worker is
+     * prevented from executing tasks, even though it must continue to
+     * scan for them to avoid queuing races. Note however that
+     * eventCount updates lag releases so usage requires care.
+     *
+     * Field plock is an int packed with:
+     * SHUTDOWN: true if shutdown is enabled (1 bit)
+     * SEQ:  a sequence lock, with PL_LOCK bit set if locked (30 bits)
+     * SIGNAL: set when threads may be waiting on the lock (1 bit)
+     *
+     * The sequence number enables simple consistency checks:
+     * Staleness of read-only operations on the workQueues array can
+     * be checked by comparing plock before vs after the reads.
      */
-    volatile long ctl;
 
     // bit positions/shifts for fields
     private static final int  AC_SHIFT   = 48;
@@ -523,8 +1206,10 @@
     private static final int  EC_SHIFT   = 16;
 
     // bounds
-    private static final int  MAX_ID     = 0x7fff;  // max poolIndex
-    private static final int  SMASK      = 0xffff;  // mask short bits
+    private static final int  SMASK      = 0xffff;  // short bits
+    private static final int  MAX_CAP    = 0x7fff;  // max #workers - 1
+    private static final int  EVENMASK   = 0xfffe;  // even short bits
+    private static final int  SQMASK     = 0x007e;  // max 64 (even) slots
     private static final int  SHORT_SIGN = 1 << 15;
     private static final int  INT_SIGN   = 1 << 31;
 
@@ -546,649 +1231,648 @@
     private static final int  UTC_UNIT   = 1 << UTC_SHIFT;
 
     // masks and units for dealing with e = (int)ctl
-    private static final int  E_MASK     = 0x7fffffff; // no STOP_BIT
-    private static final int  EC_UNIT    = 1 << EC_SHIFT;
-
-    /**
-     * The target parallelism level.
-     */
-    final int parallelism;
+    private static final int E_MASK      = 0x7fffffff; // no STOP_BIT
+    private static final int E_SEQ       = 1 << EC_SHIFT;
 
-    /**
-     * Index (mod submission queue length) of next element to take
-     * from submission queue. Usage is identical to that for
-     * per-worker queues -- see ForkJoinWorkerThread internal
-     * documentation.
-     */
-    volatile int queueBase;
-
-    /**
-     * Index (mod submission queue length) of next element to add
-     * in submission queue. Usage is identical to that for
-     * per-worker queues -- see ForkJoinWorkerThread internal
-     * documentation.
-     */
-    int queueTop;
+    // plock bits
+    private static final int SHUTDOWN    = 1 << 31;
+    private static final int PL_LOCK     = 2;
+    private static final int PL_SIGNAL   = 1;
+    private static final int PL_SPINS    = 1 << 8;
 
-    /**
-     * True when shutdown() has been called.
-     */
-    volatile boolean shutdown;
-
-    /**
-     * True if use local fifo, not default lifo, for local polling
-     * Read by, and replicated by ForkJoinWorkerThreads
-     */
-    final boolean locallyFifo;
+    // access mode for WorkQueue
+    static final int LIFO_QUEUE          =  0;
+    static final int FIFO_QUEUE          =  1;
+    static final int SHARED_QUEUE        = -1;
 
-    /**
-     * The number of threads in ForkJoinWorkerThreads.helpQuiescePool.
-     * When non-zero, suppresses automatic shutdown when active
-     * counts become zero.
-     */
-    volatile int quiescerCount;
+    // bounds for #steps in scan loop -- must be power 2 minus 1
+    private static final int MIN_SCAN    = 0x1ff;   // cover estimation slop
+    private static final int MAX_SCAN    = 0x1ffff; // 4 * max workers
+
+    // Instance fields
 
-    /**
-     * The number of threads blocked in join.
-     */
-    volatile int blockedCount;
-
-    /**
-     * Counter for worker Thread names (unrelated to their poolIndex)
+    /*
+     * Field layout of this class tends to matter more than one would
+     * like. Runtime layout order is only loosely related to
+     * declaration order and may differ across JVMs, but the following
+     * empirically works OK on current JVMs.
      */
-    private volatile int nextWorkerNumber;
 
-    /**
-     * The index for the next created worker. Accessed under scanGuard.
-     */
-    private int nextWorkerIndex;
+    // Heuristic padding to ameliorate unfortunate memory placements
+    volatile long pad00, pad01, pad02, pad03, pad04, pad05, pad06;
 
-    /**
-     * SeqLock and index masking for updates to workers array.  Locked
-     * when SG_UNIT is set. Unlocking clears bit by adding
-     * SG_UNIT. Staleness of read-only operations can be checked by
-     * comparing scanGuard to value before the reads. The low 16 bits
-     * (i.e, anding with SMASK) hold (the smallest power of two
-     * covering all worker indices, minus one, and is used to avoid
-     * dealing with large numbers of null slots when the workers array
-     * is overallocated.
-     */
-    volatile int scanGuard;
+    volatile long stealCount;                  // collects worker counts
+    volatile long ctl;                         // main pool control
+    volatile int plock;                        // shutdown status and seqLock
+    volatile int indexSeed;                    // worker/submitter index seed
+    final int config;                          // mode and parallelism level
+    WorkQueue[] workQueues;                    // main registry
+    final ForkJoinWorkerThreadFactory factory;
+    final Thread.UncaughtExceptionHandler ueh; // per-worker UEH
+    final String workerNamePrefix;             // to create worker name string
 
-    private static final int SG_UNIT = 1 << 16;
+    volatile Object pad10, pad11, pad12, pad13, pad14, pad15, pad16, pad17;
+    volatile Object pad18, pad19, pad1a, pad1b;
 
-    /**
-     * The wakeup interval (in nanoseconds) for a worker waiting for a
-     * task when the pool is quiescent to instead try to shrink the
-     * number of workers.  The exact value does not matter too
-     * much. It must be short enough to release resources during
-     * sustained periods of idleness, but not so short that threads
-     * are continually re-created.
+    /*
+     * Acquires the plock lock to protect worker array and related
+     * updates. This method is called only if an initial CAS on plock
+     * fails. This acts as a spinLock for normal cases, but falls back
+     * to builtin monitor to block when (rarely) needed. This would be
+     * a terrible idea for a highly contended lock, but works fine as
+     * a more conservative alternative to a pure spinlock.
      */
-    private static final long SHRINK_RATE =
-        4L * 1000L * 1000L * 1000L; // 4 seconds
-
-    /**
-     * Top-level loop for worker threads: On each step: if the
-     * previous step swept through all queues and found no tasks, or
-     * there are excess threads, then possibly blocks. Otherwise,
-     * scans for and, if found, executes a task. Returns when pool
-     * and/or worker terminate.
-     *
-     * @param w the worker
-     */
-    final void work(ForkJoinWorkerThread w) {
-        boolean swept = false;                // true on empty scans
-        long c;
-        while (!w.terminate && (int)(c = ctl) >= 0) {
-            int a;                            // active count
-            if (!swept && (a = (int)(c >> AC_SHIFT)) <= 0)
-                swept = scan(w, a);
-            else if (tryAwaitWork(w, c))
-                swept = false;
+    private int acquirePlock() {
+        int spins = PL_SPINS, r = 0, ps, nps;
+        for (;;) {
+            if (((ps = plock) & PL_LOCK) == 0 &&
+                U.compareAndSwapInt(this, PLOCK, ps, nps = ps + PL_LOCK))
+                return nps;
+            else if (r == 0) { // randomize spins if possible
+                Thread t = Thread.currentThread(); WorkQueue w; Submitter z;
+                if ((t instanceof ForkJoinWorkerThread) &&
+                    (w = ((ForkJoinWorkerThread)t).workQueue) != null)
+                    r = w.seed;
+                else if ((z = submitters.get()) != null)
+                    r = z.seed;
+                else
+                    r = 1;
+            }
+            else if (spins >= 0) {
+                r ^= r << 1; r ^= r >>> 3; r ^= r << 10; // xorshift
+                if (r >= 0)
+                    --spins;
+            }
+            else if (U.compareAndSwapInt(this, PLOCK, ps, ps | PL_SIGNAL)) {
+                synchronized (this) {
+                    if ((plock & PL_SIGNAL) != 0) {
+                        try {
+                            wait();
+                        } catch (InterruptedException ie) {
+                            try {
+                                Thread.currentThread().interrupt();
+                            } catch (SecurityException ignore) {
+                            }
+                        }
+                    }
+                    else
+                        notifyAll();
+                }
+            }
         }
     }
 
-    // Signalling
+    /**
+     * Unlocks and signals any thread waiting for plock. Called only
+     * when CAS of seq value for unlock fails.
+     */
+    private void releasePlock(int ps) {
+        plock = ps;
+        synchronized (this) { notifyAll(); }
+    }
 
     /**
-     * Wakes up or creates a worker.
+     * Performs secondary initialization, called when plock is zero.
+     * Creates workQueue array and sets plock to a valid value.  The
+     * lock body must be exception-free (so no try/finally) so we
+     * optimistically allocate new array outside the lock and throw
+     * away if (very rarely) not needed. (A similar tactic is used in
+     * fullExternalPush.)  Because the plock seq value can eventually
+     * wrap around zero, this method harmlessly fails to reinitialize
+     * if workQueues exists, while still advancing plock.
+     *
+     * Additionally tries to create the first worker.
      */
-    final void signalWork() {
-        /*
-         * The while condition is true if: (there is are too few total
-         * workers OR there is at least one waiter) AND (there are too
-         * few active workers OR the pool is terminating).  The value
-         * of e distinguishes the remaining cases: zero (no waiters)
-         * for create, negative if terminating (in which case do
-         * nothing), else release a waiter. The secondary checks for
-         * release (non-null array etc) can fail if the pool begins
-         * terminating after the test, and don't impose any added cost
-         * because JVMs must perform null and bounds checks anyway.
-         */
-        long c; int e, u;
-        while ((((e = (int)(c = ctl)) | (u = (int)(c >>> 32))) &
-                (INT_SIGN|SHORT_SIGN)) == (INT_SIGN|SHORT_SIGN) && e >= 0) {
-            if (e > 0) {                         // release a waiting worker
-                int i; ForkJoinWorkerThread w; ForkJoinWorkerThread[] ws;
-                if ((ws = workers) == null ||
-                    (i = ~e & SMASK) >= ws.length ||
-                    (w = ws[i]) == null)
-                    break;
-                long nc = (((long)(w.nextWait & E_MASK)) |
-                           ((long)(u + UAC_UNIT) << 32));
-                if (w.eventCount == e &&
-                    UNSAFE.compareAndSwapLong(this, ctlOffset, c, nc)) {
-                    w.eventCount = (e + EC_UNIT) & E_MASK;
-                    if (w.parked)
-                        UNSAFE.unpark(w);
-                    break;
+    private void initWorkers() {
+        WorkQueue[] ws, nws; int ps;
+        int p = config & SMASK;        // find power of two table size
+        int n = (p > 1) ? p - 1 : 1;   // ensure at least 2 slots
+        n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16;
+        n = (n + 1) << 1;
+        if ((ws = workQueues) == null || ws.length == 0)
+            nws = new WorkQueue[n];
+        else
+            nws = null;
+        if (((ps = plock) & PL_LOCK) != 0 ||
+            !U.compareAndSwapInt(this, PLOCK, ps, ps += PL_LOCK))
+            ps = acquirePlock();
+        if (((ws = workQueues) == null || ws.length == 0) && nws != null)
+            workQueues = nws;
+        int nps = (ps & SHUTDOWN) | ((ps + PL_LOCK) & ~SHUTDOWN);
+        if (!U.compareAndSwapInt(this, PLOCK, ps, nps))
+            releasePlock(nps);
+        tryAddWorker();
+    }
+
+    /**
+     * Tries to create and start one worker if fewer than target
+     * parallelism level exist. Adjusts counts etc on failure.
+     */
+    private void tryAddWorker() {
+        long c; int u;
+        while ((u = (int)((c = ctl) >>> 32)) < 0 &&
+               (u & SHORT_SIGN) != 0 && (int)c == 0) {
+            long nc = (long)(((u + UTC_UNIT) & UTC_MASK) |
+                             ((u + UAC_UNIT) & UAC_MASK)) << 32;
+            if (U.compareAndSwapLong(this, CTL, c, nc)) {
+                ForkJoinWorkerThreadFactory fac;
+                Throwable ex = null;
+                ForkJoinWorkerThread wt = null;
+                try {
+                    if ((fac = factory) != null &&
+                        (wt = fac.newThread(this)) != null) {
+                        wt.start();
+                        break;
+                    }
+                } catch (Throwable e) {
+                    ex = e;
                 }
-            }
-            else if (UNSAFE.compareAndSwapLong
-                     (this, ctlOffset, c,
-                      (long)(((u + UTC_UNIT) & UTC_MASK) |
-                             ((u + UAC_UNIT) & UAC_MASK)) << 32)) {
-                addWorker();
+                deregisterWorker(wt, ex);
                 break;
             }
         }
     }
 
+    //  Registering and deregistering workers
+
     /**
-     * Variant of signalWork to help release waiters on rescans.
-     * Tries once to release a waiter if active count < 0.
+     * Callback from ForkJoinWorkerThread to establish and record its
+     * WorkQueue. To avoid scanning bias due to packing entries in
+     * front of the workQueues array, we treat the array as a simple
+     * power-of-two hash table using per-thread seed as hash,
+     * expanding as needed.
+     *
+     * @param wt the worker thread
+     * @return the worker's queue
+     */
+    final WorkQueue registerWorker(ForkJoinWorkerThread wt) {
+        Thread.UncaughtExceptionHandler handler; WorkQueue[] ws; int s, ps;
+        wt.setDaemon(true);
+        if ((handler = ueh) != null)
+            wt.setUncaughtExceptionHandler(handler);
+        do {} while (!U.compareAndSwapInt(this, INDEXSEED, s = indexSeed,
+                                          s += SEED_INCREMENT) ||
+                     s == 0); // skip 0
+        WorkQueue w = new WorkQueue(this, wt, config >>> 16, s);
+        if (((ps = plock) & PL_LOCK) != 0 ||
+            !U.compareAndSwapInt(this, PLOCK, ps, ps += PL_LOCK))
+            ps = acquirePlock();
+        int nps = (ps & SHUTDOWN) | ((ps + PL_LOCK) & ~SHUTDOWN);
+        try {
+            if ((ws = workQueues) != null) {    // skip if shutting down
+                int n = ws.length, m = n - 1;
+                int r = (s << 1) | 1;           // use odd-numbered indices
+                if (ws[r &= m] != null) {       // collision
+                    int probes = 0;             // step by approx half size
+                    int step = (n <= 4) ? 2 : ((n >>> 1) & EVENMASK) + 2;
+                    while (ws[r = (r + step) & m] != null) {
+                        if (++probes >= n) {
+                            workQueues = ws = Arrays.copyOf(ws, n <<= 1);
+                            m = n - 1;
+                            probes = 0;
+                        }
+                    }
+                }
+                w.eventCount = w.poolIndex = r; // volatile write orders
+                ws[r] = w;
+            }
+        } finally {
+            if (!U.compareAndSwapInt(this, PLOCK, ps, nps))
+                releasePlock(nps);
+        }
+        wt.setName(workerNamePrefix.concat(Integer.toString(w.poolIndex)));
+        return w;
+    }
+
+    /**
+     * Final callback from terminating worker, as well as upon failure
+     * to construct or start a worker.  Removes record of worker from
+     * array, and adjusts counts. If pool is shutting down, tries to
+     * complete termination.
      *
-     * @return false if failed due to contention, else true
+     * @param wt the worker thread or null if construction failed
+     * @param ex the exception causing failure, or null if none
+     */
+    final void deregisterWorker(ForkJoinWorkerThread wt, Throwable ex) {
+        WorkQueue w = null;
+        if (wt != null && (w = wt.workQueue) != null) {
+            int ps;
+            w.qlock = -1;                // ensure set
+            long ns = w.nsteals, sc;     // collect steal count
+            do {} while (!U.compareAndSwapLong(this, STEALCOUNT,
+                                               sc = stealCount, sc + ns));
+            if (((ps = plock) & PL_LOCK) != 0 ||
+                !U.compareAndSwapInt(this, PLOCK, ps, ps += PL_LOCK))
+                ps = acquirePlock();
+            int nps = (ps & SHUTDOWN) | ((ps + PL_LOCK) & ~SHUTDOWN);
+            try {
+                int idx = w.poolIndex;
+                WorkQueue[] ws = workQueues;
+                if (ws != null && idx >= 0 && idx < ws.length && ws[idx] == w)
+                    ws[idx] = null;
+            } finally {
+                if (!U.compareAndSwapInt(this, PLOCK, ps, nps))
+                    releasePlock(nps);
+            }
+        }
+
+        long c;                          // adjust ctl counts
+        do {} while (!U.compareAndSwapLong
+                     (this, CTL, c = ctl, (((c - AC_UNIT) & AC_MASK) |
+                                           ((c - TC_UNIT) & TC_MASK) |
+                                           (c & ~(AC_MASK|TC_MASK)))));
+
+        if (!tryTerminate(false, false) && w != null && w.array != null) {
+            w.cancelAll();               // cancel remaining tasks
+            WorkQueue[] ws; WorkQueue v; Thread p; int u, i, e;
+            while ((u = (int)((c = ctl) >>> 32)) < 0 && (e = (int)c) >= 0) {
+                if (e > 0) {             // activate or create replacement
+                    if ((ws = workQueues) == null ||
+                        (i = e & SMASK) >= ws.length ||
+                        (v = ws[i]) != null)
+                        break;
+                    long nc = (((long)(v.nextWait & E_MASK)) |
+                               ((long)(u + UAC_UNIT) << 32));
+                    if (v.eventCount != (e | INT_SIGN))
+                        break;
+                    if (U.compareAndSwapLong(this, CTL, c, nc)) {
+                        v.eventCount = (e + E_SEQ) & E_MASK;
+                        if ((p = v.parker) != null)
+                            U.unpark(p);
+                        break;
+                    }
+                }
+                else {
+                    if ((short)u < 0)
+                        tryAddWorker();
+                    break;
+                }
+            }
+        }
+        if (ex == null)                     // help clean refs on way out
+            ForkJoinTask.helpExpungeStaleExceptions();
+        else                                // rethrow
+            ForkJoinTask.rethrow(ex);
+    }
+
+    // Submissions
+
+    /**
+     * Unless shutting down, adds the given task to a submission queue
+     * at submitter's current queue index (modulo submission
+     * range). Only the most common path is directly handled in this
+     * method. All others are relayed to fullExternalPush.
+     *
+     * @param task the task. Caller must ensure non-null.
      */
-    private boolean tryReleaseWaiter() {
-        long c; int e, i; ForkJoinWorkerThread w; ForkJoinWorkerThread[] ws;
-        if ((e = (int)(c = ctl)) > 0 &&
-            (int)(c >> AC_SHIFT) < 0 &&
-            (ws = workers) != null &&
-            (i = ~e & SMASK) < ws.length &&
-            (w = ws[i]) != null) {
-            long nc = ((long)(w.nextWait & E_MASK) |
-                       ((c + AC_UNIT) & (AC_MASK|TC_MASK)));
-            if (w.eventCount != e ||
-                !UNSAFE.compareAndSwapLong(this, ctlOffset, c, nc))
-                return false;
-            w.eventCount = (e + EC_UNIT) & E_MASK;
-            if (w.parked)
-                UNSAFE.unpark(w);
+    final void externalPush(ForkJoinTask<?> task) {
+        WorkQueue[] ws; WorkQueue q; Submitter z; int m; ForkJoinTask<?>[] a;
+        if ((z = submitters.get()) != null && plock > 0 &&
+            (ws = workQueues) != null && (m = (ws.length - 1)) >= 0 &&
+            (q = ws[m & z.seed & SQMASK]) != null &&
+            U.compareAndSwapInt(q, QLOCK, 0, 1)) { // lock
+            int b = q.base, s = q.top, n, an;
+            if ((a = q.array) != null && (an = a.length) > (n = s + 1 - b)) {
+                int j = (((an - 1) & s) << ASHIFT) + ABASE;
+                U.putOrderedObject(a, j, task);
+                q.top = s + 1;                     // push on to deque
+                q.qlock = 0;
+                if (n <= 2)
+                    signalWork(q);
+                return;
+            }
+            q.qlock = 0;
         }
-        return true;
+        fullExternalPush(task);
+    }
+
+    /**
+     * Full version of externalPush. This method is called, among
+     * other times, upon the first submission of the first task to the
+     * pool, so must perform secondary initialization (via
+     * initWorkers). It also detects first submission by an external
+     * thread by looking up its ThreadLocal, and creates a new shared
+     * queue if the one at index if empty or contended. The plock lock
+     * body must be exception-free (so no try/finally) so we
+     * optimistically allocate new queues outside the lock and throw
+     * them away if (very rarely) not needed.
+     */
+    private void fullExternalPush(ForkJoinTask<?> task) {
+        int r = 0; // random index seed
+        for (Submitter z = submitters.get();;) {
+            WorkQueue[] ws; WorkQueue q; int ps, m, k;
+            if (z == null) {
+                if (U.compareAndSwapInt(this, INDEXSEED, r = indexSeed,
+                                        r += SEED_INCREMENT) && r != 0)
+                    submitters.set(z = new Submitter(r));
+            }
+            else if (r == 0) {               // move to a different index
+                r = z.seed;
+                r ^= r << 13;                // same xorshift as WorkQueues
+                r ^= r >>> 17;
+                z.seed = r ^ (r << 5);
+            }
+            else if ((ps = plock) < 0)
+                throw new RejectedExecutionException();
+            else if (ps == 0 || (ws = workQueues) == null ||
+                     (m = ws.length - 1) < 0)
+                initWorkers();
+            else if ((q = ws[k = r & m & SQMASK]) != null) {
+                if (q.qlock == 0 && U.compareAndSwapInt(q, QLOCK, 0, 1)) {
+                    ForkJoinTask<?>[] a = q.array;
+                    int s = q.top;
+                    boolean submitted = false;
+                    try {                      // locked version of push
+                        if ((a != null && a.length > s + 1 - q.base) ||
+                            (a = q.growArray()) != null) {   // must presize
+                            int j = (((a.length - 1) & s) << ASHIFT) + ABASE;
+                            U.putOrderedObject(a, j, task);
+                            q.top = s + 1;
+                            submitted = true;
+                        }
+                    } finally {
+                        q.qlock = 0;  // unlock
+                    }
+                    if (submitted) {
+                        signalWork(q);
+                        return;
+                    }
+                }
+                r = 0; // move on failure
+            }
+            else if (((ps = plock) & PL_LOCK) == 0) { // create new queue
+                q = new WorkQueue(this, null, SHARED_QUEUE, r);
+                if (((ps = plock) & PL_LOCK) != 0 ||
+                    !U.compareAndSwapInt(this, PLOCK, ps, ps += PL_LOCK))
+                    ps = acquirePlock();
+                if ((ws = workQueues) != null && k < ws.length && ws[k] == null)
+                    ws[k] = q;
+                int nps = (ps & SHUTDOWN) | ((ps + PL_LOCK) & ~SHUTDOWN);
+                if (!U.compareAndSwapInt(this, PLOCK, ps, nps))
+                    releasePlock(nps);
+            }
+            else
+                r = 0; // try elsewhere while lock held
+        }
+    }
+
+    // Maintaining ctl counts
+
+    /**
+     * Increments active count; mainly called upon return from blocking.
+     */
+    final void incrementActiveCount() {
+        long c;
+        do {} while (!U.compareAndSwapLong(this, CTL, c = ctl, c + AC_UNIT));
+    }
+
+    /**
+     * Tries to create or activate a worker if too few are active.
+     *
+     * @param q the (non-null) queue holding tasks to be signalled
+     */
+    final void signalWork(WorkQueue q) {
+        int hint = q.poolIndex;
+        long c; int e, u, i, n; WorkQueue[] ws; WorkQueue w; Thread p;
+        while ((u = (int)((c = ctl) >>> 32)) < 0) {
+            if ((e = (int)c) > 0) {
+                if ((ws = workQueues) != null && ws.length > (i = e & SMASK) &&
+                    (w = ws[i]) != null && w.eventCount == (e | INT_SIGN)) {
+                    long nc = (((long)(w.nextWait & E_MASK)) |
+                               ((long)(u + UAC_UNIT) << 32));
+                    if (U.compareAndSwapLong(this, CTL, c, nc)) {
+                        w.hint = hint;
+                        w.eventCount = (e + E_SEQ) & E_MASK;
+                        if ((p = w.parker) != null)
+                            U.unpark(p);
+                        break;
+                    }
+                    if (q.top - q.base <= 0)
+                        break;
+                }
+                else
+                    break;
+            }
+            else {
+                if ((short)u < 0)
+                    tryAddWorker();
+                break;
+            }
+        }
     }
 
     // Scanning for tasks
 
     /**
-     * Scans for and, if found, executes one task. Scans start at a
-     * random index of workers array, and randomly select the first
-     * (2*#workers)-1 probes, and then, if all empty, resort to 2
-     * circular sweeps, which is necessary to check quiescence. and
-     * taking a submission only if no stealable tasks were found.  The
-     * steal code inside the loop is a specialized form of
-     * ForkJoinWorkerThread.deqTask, followed bookkeeping to support
-     * helpJoinTask and signal propagation. The code for submission
-     * queues is almost identical. On each steal, the worker completes
-     * not only the task, but also all local tasks that this task may
-     * have generated. On detecting staleness or contention when
-     * trying to take a task, this method returns without finishing
-     * sweep, which allows global state rechecks before retry.
-     *
-     * @param w the worker
-     * @param a the number of active workers
-     * @return true if swept all queues without finding a task
+     * Top-level runloop for workers, called by ForkJoinWorkerThread.run.
      */
-    private boolean scan(ForkJoinWorkerThread w, int a) {
-        int g = scanGuard; // mask 0 avoids useless scans if only one active
-        int m = (parallelism == 1 - a && blockedCount == 0) ? 0 : g & SMASK;
-        ForkJoinWorkerThread[] ws = workers;
-        if (ws == null || ws.length <= m)         // staleness check
-            return false;
-        for (int r = w.seed, k = r, j = -(m + m); j <= m + m; ++j) {
-            ForkJoinTask<?> t; ForkJoinTask<?>[] q; int b, i;
-            ForkJoinWorkerThread v = ws[k & m];
-            if (v != null && (b = v.queueBase) != v.queueTop &&
-                (q = v.queue) != null && (i = (q.length - 1) & b) >= 0) {
-                long u = (i << ASHIFT) + ABASE;
-                if ((t = q[i]) != null && v.queueBase == b &&
-                    UNSAFE.compareAndSwapObject(q, u, t, null)) {
-                    int d = (v.queueBase = b + 1) - v.queueTop;
-                    v.stealHint = w.poolIndex;
-                    if (d != 0)
-                        signalWork();             // propagate if nonempty
-                    w.execTask(t);
-                }
-                r ^= r << 13; r ^= r >>> 17; w.seed = r ^ (r << 5);
-                return false;                     // store next seed
-            }
-            else if (j < 0) {                     // xorshift
-                r ^= r << 13; r ^= r >>> 17; k = r ^= r << 5;
-            }
-            else
-                ++k;
-        }
-        if (scanGuard != g)                       // staleness check
-            return false;
-        else {                                    // try to take submission
-            ForkJoinTask<?> t; ForkJoinTask<?>[] q; int b, i;
-            if ((b = queueBase) != queueTop &&
-                (q = submissionQueue) != null &&
-                (i = (q.length - 1) & b) >= 0) {
-                long u = (i << ASHIFT) + ABASE;
-                if ((t = q[i]) != null && queueBase == b &&
-                    UNSAFE.compareAndSwapObject(q, u, t, null)) {
-                    queueBase = b + 1;
-                    w.execTask(t);
-                }
-                return false;
-            }
-            return true;                         // all queues empty
-        }
+    final void runWorker(WorkQueue w) {
+        w.growArray(); // allocate queue
+        do { w.runTask(scan(w)); } while (w.qlock >= 0);
     }
 
     /**
-     * Tries to enqueue worker w in wait queue and await change in
-     * worker's eventCount.  If the pool is quiescent and there is
-     * more than one worker, possibly terminates worker upon exit.
-     * Otherwise, before blocking, rescans queues to avoid missed
-     * signals.  Upon finding work, releases at least one worker
-     * (which may be the current worker). Rescans restart upon
-     * detected staleness or failure to release due to
-     * contention. Note the unusual conventions about Thread.interrupt
-     * here and elsewhere: Because interrupts are used solely to alert
-     * threads to check termination, which is checked here anyway, we
-     * clear status (using Thread.interrupted) before any call to
-     * park, so that park does not immediately return due to status
-     * being set via some other unrelated call to interrupt in user
-     * code.
+     * Scans for and, if found, returns one task, else possibly
+     * inactivates the worker. This method operates on single reads of
+     * volatile state and is designed to be re-invoked continuously,
+     * in part because it returns upon detecting inconsistencies,
+     * contention, or state changes that indicate possible success on
+     * re-invocation.
      *
-     * @param w the calling worker
-     * @param c the ctl value on entry
-     * @return true if waited or another thread was released upon enq
+     * The scan searches for tasks across queues (starting at a random
+     * index, and relying on registerWorker to irregularly scatter
+     * them within array to avoid bias), checking each at least twice.
+     * The scan terminates upon either finding a non-empty queue, or
+     * completing the sweep. If the worker is not inactivated, it
+     * takes and returns a task from this queue. Otherwise, if not
+     * activated, it signals workers (that may include itself) and
+     * returns so caller can retry. Also returns for true if the
+     * worker array may have changed during an empty scan.  On failure
+     * to find a task, we take one of the following actions, after
+     * which the caller will retry calling this method unless
+     * terminated.
+     *
+     * * If pool is terminating, terminate the worker.
+     *
+     * * If not already enqueued, try to inactivate and enqueue the
+     * worker on wait queue. Or, if inactivating has caused the pool
+     * to be quiescent, relay to idleAwaitWork to possibly shrink
+     * pool.
+     *
+     * * If already enqueued and none of the above apply, possibly
+     * park awaiting signal, else lingering to help scan and signal.
+     *
+     * * If a non-empty queue discovered or left as a hint,
+     * help wake up other workers before return
+     *
+     * @param w the worker (via its WorkQueue)
+     * @return a task or null if none found
      */
-    private boolean tryAwaitWork(ForkJoinWorkerThread w, long c) {
-        int v = w.eventCount;
-        w.nextWait = (int)c;                      // w's successor record
-        long nc = (long)(v & E_MASK) | ((c - AC_UNIT) & (AC_MASK|TC_MASK));
-        if (ctl != c || !UNSAFE.compareAndSwapLong(this, ctlOffset, c, nc)) {
-            long d = ctl; // return true if lost to a deq, to force scan
-            return (int)d != (int)c && ((d - c) & AC_MASK) >= 0L;
-        }
-        for (int sc = w.stealCount; sc != 0;) {   // accumulate stealCount
-            long s = stealCount;
-            if (UNSAFE.compareAndSwapLong(this, stealCountOffset, s, s + sc))
-                sc = w.stealCount = 0;
-            else if (w.eventCount != v)
-                return true;                      // update next time
-        }
-        if ((!shutdown || !tryTerminate(false)) &&
-            (int)c != 0 && parallelism + (int)(nc >> AC_SHIFT) == 0 &&
-            blockedCount == 0 && quiescerCount == 0)
-            idleAwaitWork(w, nc, c, v);           // quiescent
-        for (boolean rescanned = false;;) {
-            if (w.eventCount != v)
-                return true;
-            if (!rescanned) {
-                int g = scanGuard, m = g & SMASK;
-                ForkJoinWorkerThread[] ws = workers;
-                if (ws != null && m < ws.length) {
-                    rescanned = true;
-                    for (int i = 0; i <= m; ++i) {
-                        ForkJoinWorkerThread u = ws[i];
-                        if (u != null) {
-                            if (u.queueBase != u.queueTop &&
-                                !tryReleaseWaiter())
-                                rescanned = false; // contended
-                            if (w.eventCount != v)
-                                return true;
-                        }
+    private final ForkJoinTask<?> scan(WorkQueue w) {
+        WorkQueue[] ws; int m;
+        int ps = plock;                          // read plock before ws
+        if (w != null && (ws = workQueues) != null && (m = ws.length - 1) >= 0) {
+            int ec = w.eventCount;               // ec is negative if inactive
+            int r = w.seed; r ^= r << 13; r ^= r >>> 17; w.seed = r ^= r << 5;
+            w.hint = -1;                         // update seed and clear hint
+            int j = ((m + m + 1) | MIN_SCAN) & MAX_SCAN;
+            do {
+                WorkQueue q; ForkJoinTask<?>[] a; int b;
+                if ((q = ws[(r + j) & m]) != null && (b = q.base) - q.top < 0 &&
+                    (a = q.array) != null) {     // probably nonempty
+                    int i = (((a.length - 1) & b) << ASHIFT) + ABASE;
+                    ForkJoinTask<?> t = (ForkJoinTask<?>)
+                        U.getObjectVolatile(a, i);
+                    if (q.base == b && ec >= 0 && t != null &&
+                        U.compareAndSwapObject(a, i, t, null)) {
+                        if ((q.base = b + 1) - q.top < 0)
+                            signalWork(q);
+                        return t;                // taken
+                    }
+                    else if ((ec < 0 || j < m) && (int)(ctl >> AC_SHIFT) <= 0) {
+                        w.hint = (r + j) & m;    // help signal below
+                        break;                   // cannot take
                     }
                 }
-                if (scanGuard != g ||              // stale
-                    (queueBase != queueTop && !tryReleaseWaiter()))
-                    rescanned = false;
-                if (!rescanned)
-                    Thread.yield();                // reduce contention
-                else
-                    Thread.interrupted();          // clear before park
+            } while (--j >= 0);
+
+            int h, e, ns; long c, sc; WorkQueue q;
+            if ((ns = w.nsteals) != 0) {
+                if (U.compareAndSwapLong(this, STEALCOUNT,
+                                         sc = stealCount, sc + ns))
+                    w.nsteals = 0;               // collect steals and rescan
             }
+            else if (plock != ps)                // consistency check
+                ;                                // skip
+            else if ((e = (int)(c = ctl)) < 0)
+                w.qlock = -1;                    // pool is terminating
             else {
-                w.parked = true;                   // must recheck
-                if (w.eventCount != v) {
-                    w.parked = false;
-                    return true;
+                if ((h = w.hint) < 0) {
+                    if (ec >= 0) {               // try to enqueue/inactivate
+                        long nc = (((long)ec |
+                                    ((c - AC_UNIT) & (AC_MASK|TC_MASK))));
+                        w.nextWait = e;          // link and mark inactive
+                        w.eventCount = ec | INT_SIGN;
+                        if (ctl != c || !U.compareAndSwapLong(this, CTL, c, nc))
+                            w.eventCount = ec;   // unmark on CAS failure
+                        else if ((int)(c >> AC_SHIFT) == 1 - (config & SMASK))
+                            idleAwaitWork(w, nc, c);
+                    }
+                    else if (w.eventCount < 0 && !tryTerminate(false, false) &&
+                             ctl == c) {         // block
+                        Thread wt = Thread.currentThread();
+                        Thread.interrupted();    // clear status
+                        U.putObject(wt, PARKBLOCKER, this);
+                        w.parker = wt;           // emulate LockSupport.park
+                        if (w.eventCount < 0)    // recheck
+                            U.park(false, 0L);
+                        w.parker = null;
+                        U.putObject(wt, PARKBLOCKER, null);
+                    }
                 }
-                LockSupport.park(this);
-                rescanned = w.parked = false;
+                if ((h >= 0 || (h = w.hint) >= 0) &&
+                    (ws = workQueues) != null && h < ws.length &&
+                    (q = ws[h]) != null) {      // signal others before retry
+                    WorkQueue v; Thread p; int u, i, s;
+                    for (int n = (config & SMASK) >>> 1;;) {
+                        int idleCount = (w.eventCount < 0) ? 0 : -1;
+                        if (((s = idleCount - q.base + q.top) <= n &&
+                             (n = s) <= 0) ||
+                            (u = (int)((c = ctl) >>> 32)) >= 0 ||
+                            (e = (int)c) <= 0 || m < (i = e & SMASK) ||
+                            (v = ws[i]) == null)
+                            break;
+                        long nc = (((long)(v.nextWait & E_MASK)) |
+                                   ((long)(u + UAC_UNIT) << 32));
+                        if (v.eventCount != (e | INT_SIGN) ||
+                            !U.compareAndSwapLong(this, CTL, c, nc))
+                            break;
+                        v.hint = h;
+                        v.eventCount = (e + E_SEQ) & E_MASK;
+                        if ((p = v.parker) != null)
+                            U.unpark(p);
+                        if (--n <= 0)
+                            break;
+                    }
+                }
             }
         }
+        return null;
     }
 
     /**
-     * If inactivating worker w has caused pool to become
-     * quiescent, check for pool termination, and wait for event
-     * for up to SHRINK_RATE nanosecs (rescans are unnecessary in
-     * this case because quiescence reflects consensus about lack
-     * of work). On timeout, if ctl has not changed, terminate the
-     * worker. Upon its termination (see deregisterWorker), it may
-     * wake up another worker to possibly repeat this process.
+     * If inactivating worker w has caused the pool to become
+     * quiescent, checks for pool termination, and, so long as this is
+     * not the only worker, waits for event for up to a given
+     * duration.  On timeout, if ctl has not changed, terminates the
+     * worker, which will in turn wake up another worker to possibly
+     * repeat this process.
      *
      * @param w the calling worker
-     * @param currentCtl the ctl value after enqueuing w
-     * @param prevCtl the ctl value if w terminated
-     * @param v the eventCount w awaits change
+     * @param currentCtl the ctl value triggering possible quiescence
+     * @param prevCtl the ctl value to restore if thread is terminated
      */
-    private void idleAwaitWork(ForkJoinWorkerThread w, long currentCtl,
-                               long prevCtl, int v) {
-        if (w.eventCount == v) {
-            if (shutdown)
-                tryTerminate(false);
-            ForkJoinTask.helpExpungeStaleExceptions(); // help clean weak refs
+    private void idleAwaitWork(WorkQueue w, long currentCtl, long prevCtl) {
+        if (w != null && w.eventCount < 0 &&
+            !tryTerminate(false, false) && (int)prevCtl != 0) {
+            int dc = -(short)(currentCtl >>> TC_SHIFT);
+            long parkTime = dc < 0 ? FAST_IDLE_TIMEOUT: (dc + 1) * IDLE_TIMEOUT;
+            long deadline = System.nanoTime() + parkTime - TIMEOUT_SLOP;
+            Thread wt = Thread.currentThread();
             while (ctl == currentCtl) {
-                long startTime = System.nanoTime();
-                w.parked = true;
-                if (w.eventCount == v)             // must recheck
-                    LockSupport.parkNanos(this, SHRINK_RATE);
-                w.parked = false;
-                if (w.eventCount != v)
+                Thread.interrupted();  // timed variant of version in scan()
+                U.putObject(wt, PARKBLOCKER, this);
+                w.parker = wt;
+                if (ctl == currentCtl)
+                    U.park(false, parkTime);
+                w.parker = null;
+                U.putObject(wt, PARKBLOCKER, null);
+                if (ctl != currentCtl)
                     break;
-                else if (System.nanoTime() - startTime <
-                         SHRINK_RATE - (SHRINK_RATE / 10)) // timing slop
-                    Thread.interrupted();          // spurious wakeup
-                else if (UNSAFE.compareAndSwapLong(this, ctlOffset,
-                                                   currentCtl, prevCtl)) {
-                    w.terminate = true;            // restore previous
-                    w.eventCount = ((int)currentCtl + EC_UNIT) & E_MASK;
+                if (deadline - System.nanoTime() <= 0L &&
+                    U.compareAndSwapLong(this, CTL, currentCtl, prevCtl)) {
+                    w.eventCount = (w.eventCount + E_SEQ) | E_MASK;
+                    w.qlock = -1;   // shrink
                     break;
                 }
             }
         }
     }
 
-    // Submissions
-
     /**
-     * Enqueues the given task in the submissionQueue.  Same idea as
-     * ForkJoinWorkerThread.pushTask except for use of submissionLock.
-     *
-     * @param t the task
-     */
-    private void addSubmission(ForkJoinTask<?> t) {
-        final ReentrantLock lock = this.submissionLock;
-        lock.lock();
-        try {
-            ForkJoinTask<?>[] q; int s, m;
-            if ((q = submissionQueue) != null) {    // ignore if queue removed
-                long u = (((s = queueTop) & (m = q.length-1)) << ASHIFT)+ABASE;
-                UNSAFE.putOrderedObject(q, u, t);
-                queueTop = s + 1;
-                if (s - queueBase == m)
-                    growSubmissionQueue();
-            }
-        } finally {
-            lock.unlock();
-        }
-        signalWork();
-    }
-
-    //  (pollSubmission is defined below with exported methods)
-
-    /**
-     * Creates or doubles submissionQueue array.
-     * Basically identical to ForkJoinWorkerThread version.
-     */
-    private void growSubmissionQueue() {
-        ForkJoinTask<?>[] oldQ = submissionQueue;
-        int size = oldQ != null ? oldQ.length << 1 : INITIAL_QUEUE_CAPACITY;
-        if (size > MAXIMUM_QUEUE_CAPACITY)
-            throw new RejectedExecutionException("Queue capacity exceeded");
-        if (size < INITIAL_QUEUE_CAPACITY)
-            size = INITIAL_QUEUE_CAPACITY;
-        ForkJoinTask<?>[] q = submissionQueue = new ForkJoinTask<?>[size];
-        int mask = size - 1;
-        int top = queueTop;
-        int oldMask;
-        if (oldQ != null && (oldMask = oldQ.length - 1) >= 0) {
-            for (int b = queueBase; b != top; ++b) {
-                long u = ((b & oldMask) << ASHIFT) + ABASE;
-                Object x = UNSAFE.getObjectVolatile(oldQ, u);
-                if (x != null && UNSAFE.compareAndSwapObject(oldQ, u, x, null))
-                    UNSAFE.putObjectVolatile
-                        (q, ((b & mask) << ASHIFT) + ABASE, x);
-            }
-        }
-    }
-
-    // Blocking support
-
-    /**
-     * Tries to increment blockedCount, decrement active count
-     * (sometimes implicitly) and possibly release or create a
-     * compensating worker in preparation for blocking. Fails
-     * on contention or termination.
+     * Scans through queues looking for work while joining a task; if
+     * any present, signals. May return early if more signalling is
+     * detectably unneeded.
      *
-     * @return true if the caller can block, else should recheck and retry
-     */
-    private boolean tryPreBlock() {
-        int b = blockedCount;
-        if (UNSAFE.compareAndSwapInt(this, blockedCountOffset, b, b + 1)) {
-            int pc = parallelism;
-            do {
-                ForkJoinWorkerThread[] ws; ForkJoinWorkerThread w;
-                int e, ac, tc, rc, i;
-                long c = ctl;
-                int u = (int)(c >>> 32);
-                if ((e = (int)c) < 0) {
-                                                 // skip -- terminating
-                }
-                else if ((ac = (u >> UAC_SHIFT)) <= 0 && e != 0 &&
-                         (ws = workers) != null &&
-                         (i = ~e & SMASK) < ws.length &&
-                         (w = ws[i]) != null) {
-                    long nc = ((long)(w.nextWait & E_MASK) |
-                               (c & (AC_MASK|TC_MASK)));
-                    if (w.eventCount == e &&
-                        UNSAFE.compareAndSwapLong(this, ctlOffset, c, nc)) {
-                        w.eventCount = (e + EC_UNIT) & E_MASK;
-                        if (w.parked)
-                            UNSAFE.unpark(w);
-                        return true;             // release an idle worker
-                    }
-                }
-                else if ((tc = (short)(u >>> UTC_SHIFT)) >= 0 && ac + pc > 1) {
-                    long nc = ((c - AC_UNIT) & AC_MASK) | (c & ~AC_MASK);
-                    if (UNSAFE.compareAndSwapLong(this, ctlOffset, c, nc))
-                        return true;             // no compensation needed
-                }
-                else if (tc + pc < MAX_ID) {
-                    long nc = ((c + TC_UNIT) & TC_MASK) | (c & ~TC_MASK);
-                    if (UNSAFE.compareAndSwapLong(this, ctlOffset, c, nc)) {
-                        addWorker();
-                        return true;            // create a replacement
-                    }
-                }
-                // try to back out on any failure and let caller retry
-            } while (!UNSAFE.compareAndSwapInt(this, blockedCountOffset,
-                                               b = blockedCount, b - 1));
-        }
-        return false;
-    }
-
-    /**
-     * Decrements blockedCount and increments active count
-     */
-    private void postBlock() {
-        long c;
-        do {} while (!UNSAFE.compareAndSwapLong(this, ctlOffset,  // no mask
-                                                c = ctl, c + AC_UNIT));
-        int b;
-        do {} while (!UNSAFE.compareAndSwapInt(this, blockedCountOffset,
-                                               b = blockedCount, b - 1));
-    }
-
-    /**
-     * Possibly blocks waiting for the given task to complete, or
-     * cancels the task if terminating.  Fails to wait if contended.
-     *
-     * @param joinMe the task
+     * @param task return early if done
+     * @param origin an index to start scan
      */
-    final void tryAwaitJoin(ForkJoinTask<?> joinMe) {
-        int s;
-        Thread.interrupted(); // clear interrupts before checking termination
-        if (joinMe.status >= 0) {
-            if (tryPreBlock()) {
-                joinMe.tryAwaitDone(0L);
-                postBlock();
-            }
-            else if ((ctl & STOP_BIT) != 0L)
-                joinMe.cancelIgnoringExceptions();
-        }
-    }
-
-    /**
-     * Possibly blocks the given worker waiting for joinMe to
-     * complete or timeout
-     *
-     * @param joinMe the task
-     * @param millis the wait time for underlying Object.wait
-     */
-    final void timedAwaitJoin(ForkJoinTask<?> joinMe, long nanos) {
-        while (joinMe.status >= 0) {
-            Thread.interrupted();
-            if ((ctl & STOP_BIT) != 0L) {
-                joinMe.cancelIgnoringExceptions();
-                break;
-            }
-            if (tryPreBlock()) {
-                long last = System.nanoTime();
-                while (joinMe.status >= 0) {
-                    long millis = TimeUnit.NANOSECONDS.toMillis(nanos);
-                    if (millis <= 0)
-                        break;
-                    joinMe.tryAwaitDone(millis);
-                    if (joinMe.status < 0)
-                        break;
-                    if ((ctl & STOP_BIT) != 0L) {
-                        joinMe.cancelIgnoringExceptions();
+    private void helpSignal(ForkJoinTask<?> task, int origin) {
+        WorkQueue[] ws; WorkQueue w; Thread p; long c; int m, u, e, i, s;
+        if (task != null && task.status >= 0 &&
+            (u = (int)(ctl >>> 32)) < 0 && (u >> UAC_SHIFT) < 0 &&
+            (ws = workQueues) != null && (m = ws.length - 1) >= 0) {
+            outer: for (int k = origin, j = m; j >= 0; --j) {
+                WorkQueue q = ws[k++ & m];
+                for (int n = m;;) { // limit to at most m signals
+                    if (task.status < 0)
+                        break outer;
+                    if (q == null ||
+                        ((s = -q.base + q.top) <= n && (n = s) <= 0))
                         break;
-                    }
-                    long now = System.nanoTime();
-                    nanos -= now - last;
-                    last = now;
-                }
-                postBlock();
-                break;
-            }
-        }
-    }
-
-    /**
-     * If necessary, compensates for blocker, and blocks
-     */
-    private void awaitBlocker(ManagedBlocker blocker)
-        throws InterruptedException {
-        while (!blocker.isReleasable()) {
-            if (tryPreBlock()) {
-                try {
-                    do {} while (!blocker.isReleasable() && !blocker.block());
-                } finally {
-                    postBlock();
-                }
-                break;
-            }
-        }
-    }
-
-    // Creating, registering and deregistring workers
-
-    /**
-     * Tries to create and start a worker; minimally rolls back counts
-     * on failure.
-     */
-    private void addWorker() {
-        Throwable ex = null;
-        ForkJoinWorkerThread t = null;
-        try {
-            t = factory.newThread(this);
-        } catch (Throwable e) {
-            ex = e;
-        }
-        if (t == null) {  // null or exceptional factory return
-            long c;       // adjust counts
-            do {} while (!UNSAFE.compareAndSwapLong
-                         (this, ctlOffset, c = ctl,
-                          (((c - AC_UNIT) & AC_MASK) |
-                           ((c - TC_UNIT) & TC_MASK) |
-                           (c & ~(AC_MASK|TC_MASK)))));
-            // Propagate exception if originating from an external caller
-            if (!tryTerminate(false) && ex != null &&
-                !(Thread.currentThread() instanceof ForkJoinWorkerThread))
-                UNSAFE.throwException(ex);
-        }
-        else
-            t.start();
-    }
-
-    /**
-     * Callback from ForkJoinWorkerThread constructor to assign a
-     * public name
-     */
-    final String nextWorkerName() {
-        for (int n;;) {
-            if (UNSAFE.compareAndSwapInt(this, nextWorkerNumberOffset,
-                                         n = nextWorkerNumber, ++n))
-                return workerNamePrefix + n;
-        }
-    }
-
-    /**
-     * Callback from ForkJoinWorkerThread constructor to
-     * determine its poolIndex and record in workers array.
-     *
-     * @param w the worker
-     * @return the worker's pool index
-     */
-    final int registerWorker(ForkJoinWorkerThread w) {
-        /*
-         * In the typical case, a new worker acquires the lock, uses
-         * next available index and returns quickly.  Since we should
-         * not block callers (ultimately from signalWork or
-         * tryPreBlock) waiting for the lock needed to do this, we
-         * instead help release other workers while waiting for the
-         * lock.
-         */
-        for (int g;;) {
-            ForkJoinWorkerThread[] ws;
-            if (((g = scanGuard) & SG_UNIT) == 0 &&
-                UNSAFE.compareAndSwapInt(this, scanGuardOffset,
-                                         g, g | SG_UNIT)) {
-                int k = nextWorkerIndex;
-                try {
-                    if ((ws = workers) != null) { // ignore on shutdown
-                        int n = ws.length;
-                        if (k < 0 || k >= n || ws[k] != null) {
-                            for (k = 0; k < n && ws[k] != null; ++k)
-                                ;
-                            if (k == n)
-                                ws = workers = Arrays.copyOf(ws, n << 1);
-                        }
-                        ws[k] = w;
-                        nextWorkerIndex = k + 1;
-                        int m = g & SMASK;
-                        g = (k > m) ? ((m << 1) + 1) & SMASK : g + (SG_UNIT<<1);
-                    }
-                } finally {
-                    scanGuard = g;
-                }
-                return k;
-            }
-            else if ((ws = workers) != null) { // help release others
-                for (ForkJoinWorkerThread u : ws) {
-                    if (u != null && u.queueBase != u.queueTop) {
-                        if (tryReleaseWaiter())
+                    if ((u = (int)((c = ctl) >>> 32)) >= 0 ||
+                        (e = (int)c) <= 0 || m < (i = e & SMASK) ||
+                        (w = ws[i]) == null)
+                        break outer;
+                    long nc = (((long)(w.nextWait & E_MASK)) |
+                               ((long)(u + UAC_UNIT) << 32));
+                    if (w.eventCount != (e | INT_SIGN))
+                        break outer;
+                    if (U.compareAndSwapLong(this, CTL, c, nc)) {
+                        w.eventCount = (e + E_SEQ) & E_MASK;
+                        if ((p = w.parker) != null)
+                            U.unpark(p);
+                        if (--n <= 0)
                             break;
                     }
                 }
@@ -1197,202 +1881,631 @@
     }
 
     /**
-     * Final callback from terminating worker.  Removes record of
-     * worker from array, and adjusts counts. If pool is shutting
-     * down, tries to complete termination.
-     *
-     * @param w the worker
-     */
-    final void deregisterWorker(ForkJoinWorkerThread w, Throwable ex) {
-        int idx = w.poolIndex;
-        int sc = w.stealCount;
-        int steps = 0;
-        // Remove from array, adjust worker counts and collect steal count.
-        // We can intermix failed removes or adjusts with steal updates
-        do {
-            long s, c;
-            int g;
-            if (steps == 0 && ((g = scanGuard) & SG_UNIT) == 0 &&
-                UNSAFE.compareAndSwapInt(this, scanGuardOffset,
-                                         g, g |= SG_UNIT)) {
-                ForkJoinWorkerThread[] ws = workers;
-                if (ws != null && idx >= 0 &&
-                    idx < ws.length && ws[idx] == w)
-                    ws[idx] = null;    // verify
-                nextWorkerIndex = idx;
-                scanGuard = g + SG_UNIT;
-                steps = 1;
-            }
-            if (steps == 1 &&
-                UNSAFE.compareAndSwapLong(this, ctlOffset, c = ctl,
-                                          (((c - AC_UNIT) & AC_MASK) |
-                                           ((c - TC_UNIT) & TC_MASK) |
-                                           (c & ~(AC_MASK|TC_MASK)))))
-                steps = 2;
-            if (sc != 0 &&
-                UNSAFE.compareAndSwapLong(this, stealCountOffset,
-                                          s = stealCount, s + sc))
-                sc = 0;
-        } while (steps != 2 || sc != 0);
-        if (!tryTerminate(false)) {
-            if (ex != null)   // possibly replace if died abnormally
-                signalWork();
-            else
-                tryReleaseWaiter();
-        }
-    }
-
-    // Shutdown and termination
-
-    /**
-     * Possibly initiates and/or completes termination.
+     * Tries to locate and execute tasks for a stealer of the given
+     * task, or in turn one of its stealers, Traces currentSteal ->
+     * currentJoin links looking for a thread working on a descendant
+     * of the given task and with a non-empty queue to steal back and
+     * execute tasks from. The first call to this method upon a
+     * waiting join will often entail scanning/search, (which is OK
+     * because the joiner has nothing better to do), but this method
+     * leaves hints in workers to speed up subsequent calls. The
+     * implementation is very branchy to cope with potential
+     * inconsistencies or loops encountering chains that are stale,
+     * unknown, or so long that they are likely cyclic.
      *
-     * @param now if true, unconditionally terminate, else only
-     * if shutdown and empty queue and no active workers
-     * @return true if now terminating or terminated
+     * @param joiner the joining worker
+     * @param task the task to join
+     * @return 0 if no progress can be made, negative if task
+     * known complete, else positive
      */
-    private boolean tryTerminate(boolean now) {
-        long c;
-        while (((c = ctl) & STOP_BIT) == 0) {
-            if (!now) {
-                if ((int)(c >> AC_SHIFT) != -parallelism)
-                    return false;
-                if (!shutdown || blockedCount != 0 || quiescerCount != 0 ||
-                    queueBase != queueTop) {
-                    if (ctl == c) // staleness check
-                        return false;
-                    continue;
-                }
-            }
-            if (UNSAFE.compareAndSwapLong(this, ctlOffset, c, c | STOP_BIT))
-                startTerminating();
-        }
-        if ((short)(c >>> TC_SHIFT) == -parallelism) { // signal when 0 workers
-            final ReentrantLock lock = this.submissionLock;
-            lock.lock();
-            try {
-                termination.signalAll();
-            } finally {
-                lock.unlock();
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Runs up to three passes through workers: (0) Setting
-     * termination status for each worker, followed by wakeups up to
-     * queued workers; (1) helping cancel tasks; (2) interrupting
-     * lagging threads (likely in external tasks, but possibly also
-     * blocked in joins).  Each pass repeats previous steps because of
-     * potential lagging thread creation.
-     */
-    private void startTerminating() {
-        cancelSubmissions();
-        for (int pass = 0; pass < 3; ++pass) {
-            ForkJoinWorkerThread[] ws = workers;
-            if (ws != null) {
-                for (ForkJoinWorkerThread w : ws) {
-                    if (w != null) {
-                        w.terminate = true;
-                        if (pass > 0) {
-                            w.cancelTasks();
-                            if (pass > 1 && !w.isInterrupted()) {
-                                try {
-                                    w.interrupt();
-                                } catch (SecurityException ignore) {
-                                }
+    private int tryHelpStealer(WorkQueue joiner, ForkJoinTask<?> task) {
+        int stat = 0, steps = 0;                    // bound to avoid cycles
+        if (joiner != null && task != null) {       // hoist null checks
+            restart: for (;;) {
+                ForkJoinTask<?> subtask = task;     // current target
+                for (WorkQueue j = joiner, v;;) {   // v is stealer of subtask
+                    WorkQueue[] ws; int m, s, h;
+                    if ((s = task.status) < 0) {
+                        stat = s;
+                        break restart;
+                    }
+                    if ((ws = workQueues) == null || (m = ws.length - 1) <= 0)
+                        break restart;              // shutting down
+                    if ((v = ws[h = (j.hint | 1) & m]) == null ||
+                        v.currentSteal != subtask) {
+                        for (int origin = h;;) {    // find stealer
+                            if (((h = (h + 2) & m) & 15) == 1 &&
+                                (subtask.status < 0 || j.currentJoin != subtask))
+                                continue restart;   // occasional staleness check
+                            if ((v = ws[h]) != null &&
+                                v.currentSteal == subtask) {
+                                j.hint = h;        // save hint
+                                break;
+                            }
+                            if (h == origin)
+                                break restart;      // cannot find stealer
+                        }
+                    }
+                    for (;;) { // help stealer or descend to its stealer
+                        ForkJoinTask[] a;  int b;
+                        if (subtask.status < 0)     // surround probes with
+                            continue restart;       //   consistency checks
+                        if ((b = v.base) - v.top < 0 && (a = v.array) != null) {
+                            int i = (((a.length - 1) & b) << ASHIFT) + ABASE;
+                            ForkJoinTask<?> t =
+                                (ForkJoinTask<?>)U.getObjectVolatile(a, i);
+                            if (subtask.status < 0 || j.currentJoin != subtask ||
+                                v.currentSteal != subtask)
+                                continue restart;   // stale
+                            stat = 1;               // apparent progress
+                            if (t != null && v.base == b &&
+                                U.compareAndSwapObject(a, i, t, null)) {
+                                v.base = b + 1;     // help stealer
+                                joiner.runSubtask(t);
+                            }
+                            else if (v.base == b && ++steps == MAX_HELP)
+                                break restart;      // v apparently stalled
+                        }
+                        else {                      // empty -- try to descend
+                            ForkJoinTask<?> next = v.currentJoin;
+                            if (subtask.status < 0 || j.currentJoin != subtask ||
+                                v.currentSteal != subtask)
+                                continue restart;   // stale
+                            else if (next == null || ++steps == MAX_HELP)
+                                break restart;      // dead-end or maybe cyclic
+                            else {
+                                subtask = next;
+                                j = v;
+                                break;
                             }
                         }
                     }
                 }
-                terminateWaiters();
+            }
+        }
+        return stat;
+    }
+
+    /**
+     * Analog of tryHelpStealer for CountedCompleters. Tries to steal
+     * and run tasks within the target's computation.
+     *
+     * @param task the task to join
+     * @param mode if shared, exit upon completing any task
+     * if all workers are active
+     *
+     */
+    private int helpComplete(ForkJoinTask<?> task, int mode) {
+        WorkQueue[] ws; WorkQueue q; int m, n, s, u;
+        if (task != null && (ws = workQueues) != null &&
+            (m = ws.length - 1) >= 0) {
+            for (int j = 1, origin = j;;) {
+                if ((s = task.status) < 0)
+                    return s;
+                if ((q = ws[j & m]) != null && q.pollAndExecCC(task)) {
+                    origin = j;
+                    if (mode == SHARED_QUEUE &&
+                        ((u = (int)(ctl >>> 32)) >= 0 || (u >> UAC_SHIFT) >= 0))
+                        break;
+                }
+                else if ((j = (j + 2) & m) == origin)
+                    break;
+            }
+        }
+        return 0;
+    }
+
+    /**
+     * Tries to decrement active count (sometimes implicitly) and
+     * possibly release or create a compensating worker in preparation
+     * for blocking. Fails on contention or termination. Otherwise,
+     * adds a new thread if no idle workers are available and pool
+     * may become starved.
+     */
+    final boolean tryCompensate() {
+        int pc = config & SMASK, e, i, tc; long c;
+        WorkQueue[] ws; WorkQueue w; Thread p;
+        if ((ws = workQueues) != null && (e = (int)(c = ctl)) >= 0) {
+            if (e != 0 && (i = e & SMASK) < ws.length &&
+                (w = ws[i]) != null && w.eventCount == (e | INT_SIGN)) {
+                long nc = ((long)(w.nextWait & E_MASK) |
+                           (c & (AC_MASK|TC_MASK)));
+                if (U.compareAndSwapLong(this, CTL, c, nc)) {
+                    w.eventCount = (e + E_SEQ) & E_MASK;
+                    if ((p = w.parker) != null)
+                        U.unpark(p);
+                    return true;   // replace with idle worker
+                }
+            }
+            else if ((tc = (short)(c >>> TC_SHIFT)) >= 0 &&
+                     (int)(c >> AC_SHIFT) + pc > 1) {
+                long nc = ((c - AC_UNIT) & AC_MASK) | (c & ~AC_MASK);
+                if (U.compareAndSwapLong(this, CTL, c, nc))
+                    return true;   // no compensation
+            }
+            else if (tc + pc < MAX_CAP) {
+                long nc = ((c + TC_UNIT) & TC_MASK) | (c & ~TC_MASK);
+                if (U.compareAndSwapLong(this, CTL, c, nc)) {
+                    ForkJoinWorkerThreadFactory fac;
+                    Throwable ex = null;
+                    ForkJoinWorkerThread wt = null;
+                    try {
+                        if ((fac = factory) != null &&
+                            (wt = fac.newThread(this)) != null) {
+                            wt.start();
+                            return true;
+                        }
+                    } catch (Throwable rex) {
+                        ex = rex;
+                    }
+                    deregisterWorker(wt, ex); // clean up and return false
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Helps and/or blocks until the given task is done.
+     *
+     * @param joiner the joining worker
+     * @param task the task
+     * @return task status on exit
+     */
+    final int awaitJoin(WorkQueue joiner, ForkJoinTask<?> task) {
+        int s = 0;
+        if (joiner != null && task != null && (s = task.status) >= 0) {
+            ForkJoinTask<?> prevJoin = joiner.currentJoin;
+            joiner.currentJoin = task;
+            do {} while ((s = task.status) >= 0 && !joiner.isEmpty() &&
+                         joiner.tryRemoveAndExec(task)); // process local tasks
+            if (s >= 0 && (s = task.status) >= 0) {
+                helpSignal(task, joiner.poolIndex);
+                if ((s = task.status) >= 0 &&
+                    (task instanceof CountedCompleter))
+                    s = helpComplete(task, LIFO_QUEUE);
+            }
+            while (s >= 0 && (s = task.status) >= 0) {
+                if ((!joiner.isEmpty() ||           // try helping
+                     (s = tryHelpStealer(joiner, task)) == 0) &&
+                    (s = task.status) >= 0) {
+                    helpSignal(task, joiner.poolIndex);
+                    if ((s = task.status) >= 0 && tryCompensate()) {
+                        if (task.trySetSignal() && (s = task.status) >= 0) {
+                            synchronized (task) {
+                                if (task.status >= 0) {
+                                    try {                // see ForkJoinTask
+                                        task.wait();     //  for explanation
+                                    } catch (InterruptedException ie) {
+                                    }
+                                }
+                                else
+                                    task.notifyAll();
+                            }
+                        }
+                        long c;                          // re-activate
+                        do {} while (!U.compareAndSwapLong
+                                     (this, CTL, c = ctl, c + AC_UNIT));
+                    }
+                }
+            }
+            joiner.currentJoin = prevJoin;
+        }
+        return s;
+    }
+
+    /**
+     * Stripped-down variant of awaitJoin used by timed joins. Tries
+     * to help join only while there is continuous progress. (Caller
+     * will then enter a timed wait.)
+     *
+     * @param joiner the joining worker
+     * @param task the task
+     */
+    final void helpJoinOnce(WorkQueue joiner, ForkJoinTask<?> task) {
+        int s;
+        if (joiner != null && task != null && (s = task.status) >= 0) {
+            ForkJoinTask<?> prevJoin = joiner.currentJoin;
+            joiner.currentJoin = task;
+            do {} while ((s = task.status) >= 0 && !joiner.isEmpty() &&
+                         joiner.tryRemoveAndExec(task));
+            if (s >= 0 && (s = task.status) >= 0) {
+                helpSignal(task, joiner.poolIndex);
+                if ((s = task.status) >= 0 &&
+                    (task instanceof CountedCompleter))
+                    s = helpComplete(task, LIFO_QUEUE);
+            }
+            if (s >= 0 && joiner.isEmpty()) {
+                do {} while (task.status >= 0 &&
+                             tryHelpStealer(joiner, task) > 0);
+            }
+            joiner.currentJoin = prevJoin;
+        }
+    }
+
+    /**
+     * Returns a (probably) non-empty steal queue, if one is found
+     * during a random, then cyclic scan, else null.  This method must
+     * be retried by caller if, by the time it tries to use the queue,
+     * it is empty.
+     * @param r a (random) seed for scanning
+     */
+    private WorkQueue findNonEmptyStealQueue(int r) {
+        for (WorkQueue[] ws;;) {
+            int ps = plock, m, n;
+            if ((ws = workQueues) == null || (m = ws.length - 1) < 1)
+                return null;
+            for (int j = (m + 1) << 2; ;) {
+                WorkQueue q = ws[(((r + j) << 1) | 1) & m];
+                if (q != null && (n = q.base - q.top) < 0) {
+                    if (n < -1)
+                        signalWork(q);
+                    return q;
+                }
+                else if (--j < 0) {
+                    if (plock == ps)
+                        return null;
+                    break;
+                }
             }
         }
     }
 
     /**
-     * Polls and cancels all submissions. Called only during termination.
+     * Runs tasks until {@code isQuiescent()}. We piggyback on
+     * active count ctl maintenance, but rather than blocking
+     * when tasks cannot be found, we rescan until all others cannot
+     * find tasks either.
      */
-    private void cancelSubmissions() {
-        while (queueBase != queueTop) {
-            ForkJoinTask<?> task = pollSubmission();
-            if (task != null) {
-                try {
-                    task.cancel(false);
-                } catch (Throwable ignore) {
+    final void helpQuiescePool(WorkQueue w) {
+        for (boolean active = true;;) {
+            ForkJoinTask<?> localTask; // exhaust local queue
+            while ((localTask = w.nextLocalTask()) != null)
+                localTask.doExec();
+            // Similar to loop in scan(), but ignoring submissions
+            WorkQueue q = findNonEmptyStealQueue(w.nextSeed());
+            if (q != null) {
+                ForkJoinTask<?> t; int b;
+                if (!active) {      // re-establish active count
+                    long c;
+                    active = true;
+                    do {} while (!U.compareAndSwapLong
+                                 (this, CTL, c = ctl, c + AC_UNIT));
+                }
+                if ((b = q.base) - q.top < 0 && (t = q.pollAt(b)) != null)
+                    w.runSubtask(t);
+            }
+            else {
+                long c;
+                if (active) {       // decrement active count without queuing
+                    active = false;
+                    do {} while (!U.compareAndSwapLong
+                                 (this, CTL, c = ctl, c -= AC_UNIT));
+                }
+                else
+                    c = ctl;        // re-increment on exit
+                if ((int)(c >> AC_SHIFT) + (config & SMASK) == 0) {
+                    do {} while (!U.compareAndSwapLong
+                                 (this, CTL, c = ctl, c + AC_UNIT));
+                    break;
                 }
             }
         }
     }
 
     /**
-     * Tries to set the termination status of waiting workers, and
-     * then wakes them up (after which they will terminate).
+     * Gets and removes a local or stolen task for the given worker.
+     *
+     * @return a task, if available
+     */
+    final ForkJoinTask<?> nextTaskFor(WorkQueue w) {
+        for (ForkJoinTask<?> t;;) {
+            WorkQueue q; int b;
+            if ((t = w.nextLocalTask()) != null)
+                return t;
+            if ((q = findNonEmptyStealQueue(w.nextSeed())) == null)
+                return null;
+            if ((b = q.base) - q.top < 0 && (t = q.pollAt(b)) != null)
+                return t;
+        }
+    }
+
+    /**
+     * Returns a cheap heuristic guide for task partitioning when
+     * programmers, frameworks, tools, or languages have little or no
+     * idea about task granularity.  In essence by offering this
+     * method, we ask users only about tradeoffs in overhead vs
+     * expected throughput and its variance, rather than how finely to
+     * partition tasks.
+     *
+     * In a steady state strict (tree-structured) computation, each
+     * thread makes available for stealing enough tasks for other
+     * threads to remain active. Inductively, if all threads play by
+     * the same rules, each thread should make available only a
+     * constant number of tasks.
+     *
+     * The minimum useful constant is just 1. But using a value of 1
+     * would require immediate replenishment upon each steal to
+     * maintain enough tasks, which is infeasible.  Further,
+     * partitionings/granularities of offered tasks should minimize
+     * steal rates, which in general means that threads nearer the top
+     * of computation tree should generate more than those nearer the
+     * bottom. In perfect steady state, each thread is at
+     * approximately the same level of computation tree. However,
+     * producing extra tasks amortizes the uncertainty of progress and
+     * diffusion assumptions.
+     *
+     * So, users will want to use values larger, but not much larger
+     * than 1 to both smooth over transient shortages and hedge
+     * against uneven progress; as traded off against the cost of
+     * extra task overhead. We leave the user to pick a threshold
+     * value to compare with the results of this call to guide
+     * decisions, but recommend values such as 3.
+     *
+     * When all threads are active, it is on average OK to estimate
+     * surplus strictly locally. In steady-state, if one thread is
+     * maintaining say 2 surplus tasks, then so are others. So we can
+     * just use estimated queue length.  However, this strategy alone
+     * leads to serious mis-estimates in some non-steady-state
+     * conditions (ramp-up, ramp-down, other stalls). We can detect
+     * many of these by further considering the number of "idle"
+     * threads, that are known to have zero queued tasks, so
+     * compensate by a factor of (#idle/#active) threads.
+     *
+     * Note: The approximation of #busy workers as #active workers is
+     * not very good under current signalling scheme, and should be
+     * improved.
      */
-    private void terminateWaiters() {
-        ForkJoinWorkerThread[] ws = workers;
-        if (ws != null) {
-            ForkJoinWorkerThread w; long c; int i, e;
-            int n = ws.length;
-            while ((i = ~(e = (int)(c = ctl)) & SMASK) < n &&
-                   (w = ws[i]) != null && w.eventCount == (e & E_MASK)) {
-                if (UNSAFE.compareAndSwapLong(this, ctlOffset, c,
-                                              (long)(w.nextWait & E_MASK) |
-                                              ((c + AC_UNIT) & AC_MASK) |
-                                              (c & (TC_MASK|STOP_BIT)))) {
-                    w.terminate = true;
-                    w.eventCount = e + EC_UNIT;
-                    if (w.parked)
-                        UNSAFE.unpark(w);
+    static int getSurplusQueuedTaskCount() {
+        Thread t; ForkJoinWorkerThread wt; ForkJoinPool pool; WorkQueue q;
+        if (((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)) {
+            int p = (pool = (wt = (ForkJoinWorkerThread)t).pool).config & SMASK;
+            int n = (q = wt.workQueue).top - q.base;
+            int a = (int)(pool.ctl >> AC_SHIFT) + p;
+            return n - (a > (p >>>= 1) ? 0 :
+                        a > (p >>>= 1) ? 1 :
+                        a > (p >>>= 1) ? 2 :
+                        a > (p >>>= 1) ? 4 :
+                        8);
+        }
+        return 0;
+    }
+
+    //  Termination
+
+    /**
+     * Possibly initiates and/or completes termination.  The caller
+     * triggering termination runs three passes through workQueues:
+     * (0) Setting termination status, followed by wakeups of queued
+     * workers; (1) cancelling all tasks; (2) interrupting lagging
+     * threads (likely in external tasks, but possibly also blocked in
+     * joins).  Each pass repeats previous steps because of potential
+     * lagging thread creation.
+     *
+     * @param now if true, unconditionally terminate, else only
+     * if no work and no active workers
+     * @param enable if true, enable shutdown when next possible
+     * @return true if now terminating or terminated
+     */
+    private boolean tryTerminate(boolean now, boolean enable) {
+        if (this == commonPool)                     // cannot shut down
+            return false;
+        for (long c;;) {
+            if (((c = ctl) & STOP_BIT) != 0) {      // already terminating
+                if ((short)(c >>> TC_SHIFT) == -(config & SMASK)) {
+                    synchronized (this) {
+                        notifyAll();                // signal when 0 workers
+                    }
+                }
+                return true;
+            }
+            if (plock >= 0) {                       // not yet enabled
+                int ps;
+                if (!enable)
+                    return false;
+                if (((ps = plock) & PL_LOCK) != 0 ||
+                    !U.compareAndSwapInt(this, PLOCK, ps, ps += PL_LOCK))
+                    ps = acquirePlock();
+                if (!U.compareAndSwapInt(this, PLOCK, ps, SHUTDOWN))
+                    releasePlock(SHUTDOWN);
+            }
+            if (!now) {                             // check if idle & no tasks
+                if ((int)(c >> AC_SHIFT) != -(config & SMASK) ||
+                    hasQueuedSubmissions())
+                    return false;
+                // Check for unqueued inactive workers. One pass suffices.
+                WorkQueue[] ws = workQueues; WorkQueue w;
+                if (ws != null) {
+                    for (int i = 1; i < ws.length; i += 2) {
+                        if ((w = ws[i]) != null && w.eventCount >= 0)
+                            return false;
+                    }
+                }
+            }
+            if (U.compareAndSwapLong(this, CTL, c, c | STOP_BIT)) {
+                for (int pass = 0; pass < 3; ++pass) {
+                    WorkQueue[] ws = workQueues;
+                    if (ws != null) {
+                        WorkQueue w; Thread wt;
+                        int n = ws.length;
+                        for (int i = 0; i < n; ++i) {
+                            if ((w = ws[i]) != null) {
+                                w.qlock = -1;
+                                if (pass > 0) {
+                                    w.cancelAll();
+                                    if (pass > 1 && (wt = w.owner) != null) {
+                                        if (!wt.isInterrupted()) {
+                                            try {
+                                                wt.interrupt();
+                                            } catch (SecurityException ignore) {
+                                            }
+                                        }
+                                        U.unpark(wt);
+                                    }
+                                }
+                            }
+                        }
+                        // Wake up workers parked on event queue
+                        int i, e; long cc; Thread p;
+                        while ((e = (int)(cc = ctl) & E_MASK) != 0 &&
+                               (i = e & SMASK) < n &&
+                               (w = ws[i]) != null) {
+                            long nc = ((long)(w.nextWait & E_MASK) |
+                                       ((cc + AC_UNIT) & AC_MASK) |
+                                       (cc & (TC_MASK|STOP_BIT)));
+                            if (w.eventCount == (e | INT_SIGN) &&
+                                U.compareAndSwapLong(this, CTL, cc, nc)) {
+                                w.eventCount = (e + E_SEQ) & E_MASK;
+                                w.qlock = -1;
+                                if ((p = w.parker) != null)
+                                    U.unpark(p);
+                            }
+                        }
+                    }
                 }
             }
         }
     }
 
-    // misc ForkJoinWorkerThread support
+    // external operations on common pool
+
+    /**
+     * Returns common pool queue for a thread that has submitted at
+     * least one task.
+     */
+    static WorkQueue commonSubmitterQueue() {
+        ForkJoinPool p; WorkQueue[] ws; int m; Submitter z;
+        return ((z = submitters.get()) != null &&
+                (p = commonPool) != null &&
+                (ws = p.workQueues) != null &&
+                (m = ws.length - 1) >= 0) ?
+            ws[m & z.seed & SQMASK] : null;
+    }
 
     /**
-     * Increment or decrement quiescerCount. Needed only to prevent
-     * triggering shutdown if a worker is transiently inactive while
-     * checking quiescence.
-     *
-     * @param delta 1 for increment, -1 for decrement
+     * Tries to pop the given task from submitter's queue in common pool.
      */
-    final void addQuiescerCount(int delta) {
-        int c;
-        do {} while (!UNSAFE.compareAndSwapInt(this, quiescerCountOffset,
-                                               c = quiescerCount, c + delta));
+    static boolean tryExternalUnpush(ForkJoinTask<?> t) {
+        ForkJoinPool p; WorkQueue[] ws; WorkQueue q; Submitter z;
+        ForkJoinTask<?>[] a;  int m, s;
+        if (t != null &&
+            (z = submitters.get()) != null &&
+            (p = commonPool) != null &&
+            (ws = p.workQueues) != null &&
+            (m = ws.length - 1) >= 0 &&
+            (q = ws[m & z.seed & SQMASK]) != null &&
+            (s = q.top) != q.base &&
+            (a = q.array) != null) {
+            long j = (((a.length - 1) & (s - 1)) << ASHIFT) + ABASE;
+            if (U.getObject(a, j) == t &&
+                U.compareAndSwapInt(q, QLOCK, 0, 1)) {
+                if (q.array == a && q.top == s && // recheck
+                    U.compareAndSwapObject(a, j, t, null)) {
+                    q.top = s - 1;
+                    q.qlock = 0;
+                    return true;
+                }
+                q.qlock = 0;
+            }
+        }
+        return false;
     }
 
     /**
-     * Directly increment or decrement active count without
-     * queuing. This method is used to transiently assert inactivation
-     * while checking quiescence.
-     *
-     * @param delta 1 for increment, -1 for decrement
+     * Tries to pop and run local tasks within the same computation
+     * as the given root. On failure, tries to help complete from
+     * other queues via helpComplete.
      */
-    final void addActiveCount(int delta) {
-        long d = delta < 0 ? -AC_UNIT : AC_UNIT;
-        long c;
-        do {} while (!UNSAFE.compareAndSwapLong(this, ctlOffset, c = ctl,
-                                                ((c + d) & AC_MASK) |
-                                                (c & ~AC_MASK)));
+    private void externalHelpComplete(WorkQueue q, ForkJoinTask<?> root) {
+        ForkJoinTask<?>[] a; int m;
+        if (q != null && (a = q.array) != null && (m = (a.length - 1)) >= 0 &&
+            root != null && root.status >= 0) {
+            for (;;) {
+                int s, u; Object o; CountedCompleter<?> task = null;
+                if ((s = q.top) - q.base > 0) {
+                    long j = ((m & (s - 1)) << ASHIFT) + ABASE;
+                    if ((o = U.getObject(a, j)) != null &&
+                        (o instanceof CountedCompleter)) {
+                        CountedCompleter<?> t = (CountedCompleter<?>)o, r = t;
+                        do {
+                            if (r == root) {
+                                if (U.compareAndSwapInt(q, QLOCK, 0, 1)) {
+                                    if (q.array == a && q.top == s &&
+                                        U.compareAndSwapObject(a, j, t, null)) {
+                                        q.top = s - 1;
+                                        task = t;
+                                    }
+                                    q.qlock = 0;
+                                }
+                                break;
+                            }
+                        } while ((r = r.completer) != null);
+                    }
+                }
+                if (task != null)
+                    task.doExec();
+                if (root.status < 0 ||
+                    (u = (int)(ctl >>> 32)) >= 0 || (u >> UAC_SHIFT) >= 0)
+                    break;
+                if (task == null) {
+                    helpSignal(root, q.poolIndex);
+                    if (root.status >= 0)
+                        helpComplete(root, SHARED_QUEUE);
+                    break;
+                }
+            }
+        }
     }
 
     /**
-     * Returns the approximate (non-atomic) number of idle threads per
-     * active thread.
+     * Tries to help execute or signal availability of the given task
+     * from submitter's queue in common pool.
      */
-    final int idlePerActive() {
-        // Approximate at powers of two for small values, saturate past 4
-        int p = parallelism;
-        int a = p + (int)(ctl >> AC_SHIFT);
-        return (a > (p >>>= 1) ? 0 :
-                a > (p >>>= 1) ? 1 :
-                a > (p >>>= 1) ? 2 :
-                a > (p >>>= 1) ? 4 :
-                8);
+    static void externalHelpJoin(ForkJoinTask<?> t) {
+        // Some hard-to-avoid overlap with tryExternalUnpush
+        ForkJoinPool p; WorkQueue[] ws; WorkQueue q, w; Submitter z;
+        ForkJoinTask<?>[] a;  int m, s, n;
+        if (t != null &&
+            (z = submitters.get()) != null &&
+            (p = commonPool) != null &&
+            (ws = p.workQueues) != null &&
+            (m = ws.length - 1) >= 0 &&
+            (q = ws[m & z.seed & SQMASK]) != null &&
+            (a = q.array) != null) {
+            int am = a.length - 1;
+            if ((s = q.top) != q.base) {
+                long j = ((am & (s - 1)) << ASHIFT) + ABASE;
+                if (U.getObject(a, j) == t &&
+                    U.compareAndSwapInt(q, QLOCK, 0, 1)) {
+                    if (q.array == a && q.top == s &&
+                        U.compareAndSwapObject(a, j, t, null)) {
+                        q.top = s - 1;
+                        q.qlock = 0;
+                        t.doExec();
+                    }
+                    else
+                        q.qlock = 0;
+                }
+            }
+            if (t.status >= 0) {
+                if (t instanceof CountedCompleter)
+                    p.externalHelpComplete(q, t);
+                else
+                    p.helpSignal(t, q.poolIndex);
+            }
+        }
+    }
+
+    /**
+     * Restricted version of helpQuiescePool for external callers
+     */
+    static void externalHelpQuiescePool() {
+        ForkJoinPool p; ForkJoinTask<?> t; WorkQueue q; int b;
+        if ((p = commonPool) != null &&
+            (q = p.findNonEmptyStealQueue(1)) != null &&
+            (b = q.base) - q.top < 0 &&
+            (t = q.pollAt(b)) != null)
+            t.doExec();
     }
 
     // Exported methods
@@ -1464,31 +2577,46 @@
         checkPermission();
         if (factory == null)
             throw new NullPointerException();
-        if (parallelism <= 0 || parallelism > MAX_ID)
+        if (parallelism <= 0 || parallelism > MAX_CAP)
             throw new IllegalArgumentException();
-        this.parallelism = parallelism;
         this.factory = factory;
         this.ueh = handler;
-        this.locallyFifo = asyncMode;
+        this.config = parallelism | (asyncMode ? (FIFO_QUEUE << 16) : 0);
         long np = (long)(-parallelism); // offset ctl counts
         this.ctl = ((np << AC_SHIFT) & AC_MASK) | ((np << TC_SHIFT) & TC_MASK);
-        this.submissionQueue = new ForkJoinTask<?>[INITIAL_QUEUE_CAPACITY];
-        // initialize workers array with room for 2*parallelism if possible
-        int n = parallelism << 1;
-        if (n >= MAX_ID)
-            n = MAX_ID;
-        else { // See Hackers Delight, sec 3.2, where n < (1 << 16)
-            n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8;
-        }
-        workers = new ForkJoinWorkerThread[n + 1];
-        this.submissionLock = new ReentrantLock();
-        this.termination = submissionLock.newCondition();
+        int pn = nextPoolId();
         StringBuilder sb = new StringBuilder("ForkJoinPool-");
-        sb.append(poolNumberGenerator.incrementAndGet());
+        sb.append(Integer.toString(pn));
         sb.append("-worker-");
         this.workerNamePrefix = sb.toString();
     }
 
+    /**
+     * Constructor for common pool, suitable only for static initialization.
+     * Basically the same as above, but uses smallest possible initial footprint.
+     */
+    ForkJoinPool(int parallelism, long ctl,
+                 ForkJoinWorkerThreadFactory factory,
+                 Thread.UncaughtExceptionHandler handler) {
+        this.config = parallelism;
+        this.ctl = ctl;
+        this.factory = factory;
+        this.ueh = handler;
+        this.workerNamePrefix = "ForkJoinPool.commonPool-worker-";
+    }
+
+    /**
+     * Returns the common pool instance. This pool is statically
+     * constructed; its run state is unaffected by attempts to
+     * {@link #shutdown} or {@link #shutdownNow}.
+     *
+     * @return the common pool instance
+     */
+    public static ForkJoinPool commonPool() {
+        // assert commonPool != null : "static init error";
+        return commonPool;
+    }
+
     // Execution methods
 
     /**
@@ -1508,34 +2636,10 @@
      *         scheduled for execution
      */
     public <T> T invoke(ForkJoinTask<T> task) {
-        Thread t = Thread.currentThread();
         if (task == null)
             throw new NullPointerException();
-        if (shutdown)
-            throw new RejectedExecutionException();
-        if ((t instanceof ForkJoinWorkerThread) &&
-            ((ForkJoinWorkerThread)t).pool == this)
-            return task.invoke();  // bypass submit if in same pool
-        else {
-            addSubmission(task);
-            return task.join();
-        }
-    }
-
-    /**
-     * Unless terminating, forks task if within an ongoing FJ
-     * computation in the current pool, else submits as external task.
-     */
-    private <T> void forkOrSubmit(ForkJoinTask<T> task) {
-        ForkJoinWorkerThread w;
-        Thread t = Thread.currentThread();
-        if (shutdown)
-            throw new RejectedExecutionException();
-        if ((t instanceof ForkJoinWorkerThread) &&
-            (w = (ForkJoinWorkerThread)t).pool == this)
-            w.pushTask(task);
-        else
-            addSubmission(task);
+        externalPush(task);
+        return task.join();
     }
 
     /**
@@ -1549,7 +2653,7 @@
     public void execute(ForkJoinTask<?> task) {
         if (task == null)
             throw new NullPointerException();
-        forkOrSubmit(task);
+        externalPush(task);
     }
 
     // AbstractExecutorService methods
@@ -1566,8 +2670,8 @@
         if (task instanceof ForkJoinTask<?>) // avoid re-wrap
             job = (ForkJoinTask<?>) task;
         else
-            job = ForkJoinTask.adapt(task, null);
-        forkOrSubmit(job);
+            job = new ForkJoinTask.AdaptedRunnableAction(task);
+        externalPush(job);
     }
 
     /**
@@ -1582,7 +2686,7 @@
     public <T> ForkJoinTask<T> submit(ForkJoinTask<T> task) {
         if (task == null)
             throw new NullPointerException();
-        forkOrSubmit(task);
+        externalPush(task);
         return task;
     }
 
@@ -1592,10 +2696,8 @@
      *         scheduled for execution
      */
     public <T> ForkJoinTask<T> submit(Callable<T> task) {
-        if (task == null)
-            throw new NullPointerException();
-        ForkJoinTask<T> job = ForkJoinTask.adapt(task);
-        forkOrSubmit(job);
+        ForkJoinTask<T> job = new ForkJoinTask.AdaptedCallable<T>(task);
+        externalPush(job);
         return job;
     }
 
@@ -1605,10 +2707,8 @@
      *         scheduled for execution
      */
     public <T> ForkJoinTask<T> submit(Runnable task, T result) {
-        if (task == null)
-            throw new NullPointerException();
-        ForkJoinTask<T> job = ForkJoinTask.adapt(task, result);
-        forkOrSubmit(job);
+        ForkJoinTask<T> job = new ForkJoinTask.AdaptedRunnable<T>(task, result);
+        externalPush(job);
         return job;
     }
 
@@ -1624,8 +2724,8 @@
         if (task instanceof ForkJoinTask<?>) // avoid re-wrap
             job = (ForkJoinTask<?>) task;
         else
-            job = ForkJoinTask.adapt(task, null);
-        forkOrSubmit(job);
+            job = new ForkJoinTask.AdaptedRunnableAction(task);
+        externalPush(job);
         return job;
     }
 
@@ -1634,25 +2734,31 @@
      * @throws RejectedExecutionException {@inheritDoc}
      */
     public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) {
-        ArrayList<ForkJoinTask<T>> forkJoinTasks =
-            new ArrayList<ForkJoinTask<T>>(tasks.size());
-        for (Callable<T> task : tasks)
-            forkJoinTasks.add(ForkJoinTask.adapt(task));
-        invoke(new InvokeAll<T>(forkJoinTasks));
-
+        // In previous versions of this class, this method constructed
+        // a task to run ForkJoinTask.invokeAll, but now external
+        // invocation of multiple tasks is at least as efficient.
+        List<ForkJoinTask<T>> fs = new ArrayList<ForkJoinTask<T>>(tasks.size());
+        // Workaround needed because method wasn't declared with
+        // wildcards in return type but should have been.
         @SuppressWarnings({"unchecked", "rawtypes"})
-            List<Future<T>> futures = (List<Future<T>>) (List) forkJoinTasks;
-        return futures;
-    }
+            List<Future<T>> futures = (List<Future<T>>) (List) fs;
 
-    static final class InvokeAll<T> extends RecursiveAction {
-        final ArrayList<ForkJoinTask<T>> tasks;
-        InvokeAll(ArrayList<ForkJoinTask<T>> tasks) { this.tasks = tasks; }
-        public void compute() {
-            try { invokeAll(tasks); }
-            catch (Exception ignore) {}
+        boolean done = false;
+        try {
+            for (Callable<T> t : tasks) {
+                ForkJoinTask<T> f = new ForkJoinTask.AdaptedCallable<T>(t);
+                externalPush(f);
+                fs.add(f);
+            }
+            for (ForkJoinTask<T> f : fs)
+                f.quietlyJoin();
+            done = true;
+            return futures;
+        } finally {
+            if (!done)
+                for (ForkJoinTask<T> f : fs)
+                    f.cancel(false);
         }
-        private static final long serialVersionUID = -7914297376763021607L;
     }
 
     /**
@@ -1680,7 +2786,16 @@
      * @return the targeted parallelism level of this pool
      */
     public int getParallelism() {
-        return parallelism;
+        return config & SMASK;
+    }
+
+    /**
+     * Returns the targeted parallelism level of the common pool.
+     *
+     * @return the targeted parallelism level of the common pool
+     */
+    public static int getCommonPoolParallelism() {
+        return commonPoolParallelism;
     }
 
     /**
@@ -1692,7 +2807,7 @@
      * @return the number of worker threads
      */
     public int getPoolSize() {
-        return parallelism + (short)(ctl >>> TC_SHIFT);
+        return (config & SMASK) + (short)(ctl >>> TC_SHIFT);
     }
 
     /**
@@ -1702,7 +2817,7 @@
      * @return {@code true} if this pool uses async mode
      */
     public boolean getAsyncMode() {
-        return locallyFifo;
+        return (config >>> 16) == FIFO_QUEUE;
     }
 
     /**
@@ -1714,8 +2829,15 @@
      * @return the number of worker threads
      */
     public int getRunningThreadCount() {
-        int r = parallelism + (int)(ctl >> AC_SHIFT);
-        return (r <= 0) ? 0 : r; // suppress momentarily negative values
+        int rc = 0;
+        WorkQueue[] ws; WorkQueue w;
+        if ((ws = workQueues) != null) {
+            for (int i = 1; i < ws.length; i += 2) {
+                if ((w = ws[i]) != null && w.isApparentlyUnblocked())
+                    ++rc;
+            }
+        }
+        return rc;
     }
 
     /**
@@ -1726,7 +2848,7 @@
      * @return the number of active threads
      */
     public int getActiveThreadCount() {
-        int r = parallelism + (int)(ctl >> AC_SHIFT) + blockedCount;
+        int r = (config & SMASK) + (int)(ctl >> AC_SHIFT);
         return (r <= 0) ? 0 : r; // suppress momentarily negative values
     }
 
@@ -1742,7 +2864,7 @@
      * @return {@code true} if all threads are currently idle
      */
     public boolean isQuiescent() {
-        return parallelism + (int)(ctl >> AC_SHIFT) + blockedCount == 0;
+        return (int)(ctl >> AC_SHIFT) + (config & SMASK) == 0;
     }
 
     /**
@@ -1757,7 +2879,15 @@
      * @return the number of steals
      */
     public long getStealCount() {
-        return stealCount;
+        long count = stealCount;
+        WorkQueue[] ws; WorkQueue w;
+        if ((ws = workQueues) != null) {
+            for (int i = 1; i < ws.length; i += 2) {
+                if ((w = ws[i]) != null)
+                    count += w.nsteals;
+            }
+        }
+        return count;
     }
 
     /**
@@ -1772,12 +2902,12 @@
      */
     public long getQueuedTaskCount() {
         long count = 0;
-        ForkJoinWorkerThread[] ws;
-        if ((short)(ctl >>> TC_SHIFT) > -parallelism &&
-            (ws = workers) != null) {
-            for (ForkJoinWorkerThread w : ws)
-                if (w != null)
-                    count -= w.queueBase - w.queueTop; // must read base first
+        WorkQueue[] ws; WorkQueue w;
+        if ((ws = workQueues) != null) {
+            for (int i = 1; i < ws.length; i += 2) {
+                if ((w = ws[i]) != null)
+                    count += w.queueSize();
+            }
         }
         return count;
     }
@@ -1790,7 +2920,15 @@
      * @return the number of queued submissions
      */
     public int getQueuedSubmissionCount() {
-        return -queueBase + queueTop;
+        int count = 0;
+        WorkQueue[] ws; WorkQueue w;
+        if ((ws = workQueues) != null) {
+            for (int i = 0; i < ws.length; i += 2) {
+                if ((w = ws[i]) != null)
+                    count += w.queueSize();
+            }
+        }
+        return count;
     }
 
     /**
@@ -1800,7 +2938,14 @@
      * @return {@code true} if there are any queued submissions
      */
     public boolean hasQueuedSubmissions() {
-        return queueBase != queueTop;
+        WorkQueue[] ws; WorkQueue w;
+        if ((ws = workQueues) != null) {
+            for (int i = 0; i < ws.length; i += 2) {
+                if ((w = ws[i]) != null && !w.isEmpty())
+                    return true;
+            }
+        }
+        return false;
     }
 
     /**
@@ -1811,16 +2956,11 @@
      * @return the next submission, or {@code null} if none
      */
     protected ForkJoinTask<?> pollSubmission() {
-        ForkJoinTask<?> t; ForkJoinTask<?>[] q; int b, i;
-        while ((b = queueBase) != queueTop &&
-               (q = submissionQueue) != null &&
-               (i = (q.length - 1) & b) >= 0) {
-            long u = (i << ASHIFT) + ABASE;
-            if ((t = q[i]) != null &&
-                queueBase == b &&
-                UNSAFE.compareAndSwapObject(q, u, t, null)) {
-                queueBase = b + 1;
-                return t;
+        WorkQueue[] ws; WorkQueue w; ForkJoinTask<?> t;
+        if ((ws = workQueues) != null) {
+            for (int i = 0; i < ws.length; i += 2) {
+                if ((w = ws[i]) != null && (t = w.poll()) != null)
+                    return t;
             }
         }
         return null;
@@ -1845,20 +2985,17 @@
      */
     protected int drainTasksTo(Collection<? super ForkJoinTask<?>> c) {
         int count = 0;
-        while (queueBase != queueTop) {
-            ForkJoinTask<?> t = pollSubmission();
-            if (t != null) {
-                c.add(t);
-                ++count;
+        WorkQueue[] ws; WorkQueue w; ForkJoinTask<?> t;
+        if ((ws = workQueues) != null) {
+            for (int i = 0; i < ws.length; ++i) {
+                if ((w = ws[i]) != null) {
+                    while ((t = w.poll()) != null) {
+                        c.add(t);
+                        ++count;
+                    }
+                }
             }
         }
-        ForkJoinWorkerThread[] ws;
-        if ((short)(ctl >>> TC_SHIFT) > -parallelism &&
-            (ws = workers) != null) {
-            for (ForkJoinWorkerThread w : ws)
-                if (w != null)
-                    count += w.drainTasksTo(c);
-        }
         return count;
     }
 
@@ -1870,21 +3007,36 @@
      * @return a string identifying this pool, as well as its state
      */
     public String toString() {
-        long st = getStealCount();
-        long qt = getQueuedTaskCount();
-        long qs = getQueuedSubmissionCount();
-        int pc = parallelism;
+        // Use a single pass through workQueues to collect counts
+        long qt = 0L, qs = 0L; int rc = 0;
+        long st = stealCount;
         long c = ctl;
+        WorkQueue[] ws; WorkQueue w;
+        if ((ws = workQueues) != null) {
+            for (int i = 0; i < ws.length; ++i) {
+                if ((w = ws[i]) != null) {
+                    int size = w.queueSize();
+                    if ((i & 1) == 0)
+                        qs += size;
+                    else {
+                        qt += size;
+                        st += w.nsteals;
+                        if (w.isApparentlyUnblocked())
+                            ++rc;
+                    }
+                }
+            }
+        }
+        int pc = (config & SMASK);
         int tc = pc + (short)(c >>> TC_SHIFT);
-        int rc = pc + (int)(c >> AC_SHIFT);
-        if (rc < 0) // ignore transient negative
-            rc = 0;
-        int ac = rc + blockedCount;
+        int ac = pc + (int)(c >> AC_SHIFT);
+        if (ac < 0) // ignore transient negative
+            ac = 0;
         String level;
         if ((c & STOP_BIT) != 0)
             level = (tc == 0) ? "Terminated" : "Terminating";
         else
-            level = shutdown ? "Shutting down" : "Running";
+            level = plock < 0 ? "Shutting down" : "Running";
         return super.toString() +
             "[" + level +
             ", parallelism = " + pc +
@@ -1898,11 +3050,13 @@
     }
 
     /**
-     * Initiates an orderly shutdown in which previously submitted
-     * tasks are executed, but no new tasks will be accepted.
-     * Invocation has no additional effect if already shut down.
-     * Tasks that are in the process of being submitted concurrently
-     * during the course of this method may or may not be rejected.
+     * Possibly initiates an orderly shutdown in which previously
+     * submitted tasks are executed, but no new tasks will be
+     * accepted. Invocation has no effect on execution state if this
+     * is the {@link #commonPool}, and no additional effect if
+     * already shut down.  Tasks that are in the process of being
+     * submitted concurrently during the course of this method may or
+     * may not be rejected.
      *
      * @throws SecurityException if a security manager exists and
      *         the caller is not permitted to modify threads
@@ -1911,19 +3065,20 @@
      */
     public void shutdown() {
         checkPermission();
-        shutdown = true;
-        tryTerminate(false);
+        tryTerminate(false, true);
     }
 
     /**
-     * Attempts to cancel and/or stop all tasks, and reject all
-     * subsequently submitted tasks.  Tasks that are in the process of
-     * being submitted or executed concurrently during the course of
-     * this method may or may not be rejected. This method cancels
-     * both existing and unexecuted tasks, in order to permit
-     * termination in the presence of task dependencies. So the method
-     * always returns an empty list (unlike the case for some other
-     * Executors).
+     * Possibly attempts to cancel and/or stop all tasks, and reject
+     * all subsequently submitted tasks.  Invocation has no effect on
+     * execution state if this is the {@link #commonPool}, and no
+     * additional effect if already shut down. Otherwise, tasks that
+     * are in the process of being submitted or executed concurrently
+     * during the course of this method may or may not be
+     * rejected. This method cancels both existing and unexecuted
+     * tasks, in order to permit termination in the presence of task
+     * dependencies. So the method always returns an empty list
+     * (unlike the case for some other Executors).
      *
      * @return an empty list
      * @throws SecurityException if a security manager exists and
@@ -1933,8 +3088,7 @@
      */
     public List<Runnable> shutdownNow() {
         checkPermission();
-        shutdown = true;
-        tryTerminate(true);
+        tryTerminate(true, true);
         return Collections.emptyList();
     }
 
@@ -1946,7 +3100,7 @@
     public boolean isTerminated() {
         long c = ctl;
         return ((c & STOP_BIT) != 0L &&
-                (short)(c >>> TC_SHIFT) == -parallelism);
+                (short)(c >>> TC_SHIFT) == -(config & SMASK));
     }
 
     /**
@@ -1954,7 +3108,7 @@
      * commenced but not yet completed.  This method may be useful for
      * debugging. A return of {@code true} reported a sufficient
      * period after shutdown may indicate that submitted tasks have
-     * ignored or suppressed interruption, or are waiting for IO,
+     * ignored or suppressed interruption, or are waiting for I/O,
      * causing this executor not to properly terminate. (See the
      * advisory notes for class {@link ForkJoinTask} stating that
      * tasks should not normally entail blocking operations.  But if
@@ -1965,14 +3119,7 @@
     public boolean isTerminating() {
         long c = ctl;
         return ((c & STOP_BIT) != 0L &&
-                (short)(c >>> TC_SHIFT) != -parallelism);
-    }
-
-    /**
-     * Returns true if terminating or terminated. Used by ForkJoinWorkerThread.
-     */
-    final boolean isAtLeastTerminating() {
-        return (ctl & STOP_BIT) != 0L;
+                (short)(c >>> TC_SHIFT) != -(config & SMASK));
     }
 
     /**
@@ -1981,13 +3128,15 @@
      * @return {@code true} if this pool has been shut down
      */
     public boolean isShutdown() {
-        return shutdown;
+        return plock < 0;
     }
 
     /**
-     * Blocks until all tasks have completed execution after a shutdown
-     * request, or the timeout occurs, or the current thread is
-     * interrupted, whichever happens first.
+     * Blocks until all tasks have completed execution after a
+     * shutdown request, or the timeout occurs, or the current thread
+     * is interrupted, whichever happens first. Note that the {@link
+     * #commonPool()} never terminates until program shutdown so
+     * this method will always time out.
      *
      * @param timeout the maximum time to wait
      * @param unit the time unit of the timeout argument
@@ -1998,19 +3147,21 @@
     public boolean awaitTermination(long timeout, TimeUnit unit)
         throws InterruptedException {
         long nanos = unit.toNanos(timeout);
-        final ReentrantLock lock = this.submissionLock;
-        lock.lock();
-        try {
-            for (;;) {
-                if (isTerminated())
-                    return true;
-                if (nanos <= 0)
-                    return false;
-                nanos = termination.awaitNanos(nanos);
+        if (isTerminated())
+            return true;
+        long startTime = System.nanoTime();
+        boolean terminated = false;
+        synchronized (this) {
+            for (long waitTime = nanos, millis = 0L;;) {
+                if (terminated = isTerminated() ||
+                    waitTime <= 0L ||
+                    (millis = unit.toMillis(waitTime)) <= 0L)
+                    break;
+                wait(millis);
+                waitTime = nanos - (System.nanoTime() - startTime);
             }
-        } finally {
-            lock.unlock();
         }
+        return terminated;
     }
 
     /**
@@ -2110,11 +3261,35 @@
         throws InterruptedException {
         Thread t = Thread.currentThread();
         if (t instanceof ForkJoinWorkerThread) {
-            ForkJoinWorkerThread w = (ForkJoinWorkerThread) t;
-            w.pool.awaitBlocker(blocker);
+            ForkJoinPool p = ((ForkJoinWorkerThread)t).pool;
+            while (!blocker.isReleasable()) { // variant of helpSignal
+                WorkQueue[] ws; WorkQueue q; int m, u;
+                if ((ws = p.workQueues) != null && (m = ws.length - 1) >= 0) {
+                    for (int i = 0; i <= m; ++i) {
+                        if (blocker.isReleasable())
+                            return;
+                        if ((q = ws[i]) != null && q.base - q.top < 0) {
+                            p.signalWork(q);
+                            if ((u = (int)(p.ctl >>> 32)) >= 0 ||
+                                (u >> UAC_SHIFT) >= 0)
+                                break;
+                        }
+                    }
+                }
+                if (p.tryCompensate()) {
+                    try {
+                        do {} while (!blocker.isReleasable() &&
+                                     !blocker.block());
+                    } finally {
+                        p.incrementActiveCount();
+                    }
+                    break;
+                }
+            }
         }
         else {
-            do {} while (!blocker.isReleasable() && !blocker.block());
+            do {} while (!blocker.isReleasable() &&
+                         !blocker.block());
         }
     }
 
@@ -2123,55 +3298,93 @@
     // implement RunnableFuture.
 
     protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
-        return (RunnableFuture<T>) ForkJoinTask.adapt(runnable, value);
+        return new ForkJoinTask.AdaptedRunnable<T>(runnable, value);
     }
 
     protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
-        return (RunnableFuture<T>) ForkJoinTask.adapt(callable);
+        return new ForkJoinTask.AdaptedCallable<T>(callable);
     }
 
     // Unsafe mechanics
-    private static final sun.misc.Unsafe UNSAFE;
-    private static final long ctlOffset;
-    private static final long stealCountOffset;
-    private static final long blockedCountOffset;
-    private static final long quiescerCountOffset;
-    private static final long scanGuardOffset;
-    private static final long nextWorkerNumberOffset;
-    private static final long ABASE;
+    private static final sun.misc.Unsafe U;
+    private static final long CTL;
+    private static final long PARKBLOCKER;
+    private static final int ABASE;
     private static final int ASHIFT;
+    private static final long STEALCOUNT;
+    private static final long PLOCK;
+    private static final long INDEXSEED;
+    private static final long QLOCK;
 
     static {
-        poolNumberGenerator = new AtomicInteger();
-        workerSeedGenerator = new Random();
-        modifyThreadPermission = new RuntimePermission("modifyThread");
-        defaultForkJoinWorkerThreadFactory =
-            new DefaultForkJoinWorkerThreadFactory();
-        int s;
+        int s; // initialize field offsets for CAS etc
         try {
-            UNSAFE = sun.misc.Unsafe.getUnsafe();
+            U = sun.misc.Unsafe.getUnsafe();
             Class<?> k = ForkJoinPool.class;
-            ctlOffset = UNSAFE.objectFieldOffset
+            CTL = U.objectFieldOffset
                 (k.getDeclaredField("ctl"));
-            stealCountOffset = UNSAFE.objectFieldOffset
+            STEALCOUNT = U.objectFieldOffset
                 (k.getDeclaredField("stealCount"));
-            blockedCountOffset = UNSAFE.objectFieldOffset
-                (k.getDeclaredField("blockedCount"));
-            quiescerCountOffset = UNSAFE.objectFieldOffset
-                (k.getDeclaredField("quiescerCount"));
-            scanGuardOffset = UNSAFE.objectFieldOffset
-                (k.getDeclaredField("scanGuard"));
-            nextWorkerNumberOffset = UNSAFE.objectFieldOffset
-                (k.getDeclaredField("nextWorkerNumber"));
-            Class<?> a = ForkJoinTask[].class;
-            ABASE = UNSAFE.arrayBaseOffset(a);
-            s = UNSAFE.arrayIndexScale(a);
+            PLOCK = U.objectFieldOffset
+                (k.getDeclaredField("plock"));
+            INDEXSEED = U.objectFieldOffset
+                (k.getDeclaredField("indexSeed"));
+            Class<?> tk = Thread.class;
+            PARKBLOCKER = U.objectFieldOffset
+                (tk.getDeclaredField("parkBlocker"));
+            Class<?> wk = WorkQueue.class;
+            QLOCK = U.objectFieldOffset
+                (wk.getDeclaredField("qlock"));
+            Class<?> ak = ForkJoinTask[].class;
+            ABASE = U.arrayBaseOffset(ak);
+            s = U.arrayIndexScale(ak);
+            ASHIFT = 31 - Integer.numberOfLeadingZeros(s);
         } catch (Exception e) {
             throw new Error(e);
         }
         if ((s & (s-1)) != 0)
             throw new Error("data type scale not a power of two");
-        ASHIFT = 31 - Integer.numberOfLeadingZeros(s);
+
+        submitters = new ThreadLocal<Submitter>();
+        ForkJoinWorkerThreadFactory fac = defaultForkJoinWorkerThreadFactory =
+            new DefaultForkJoinWorkerThreadFactory();
+        modifyThreadPermission = new RuntimePermission("modifyThread");
+
+        /*
+         * Establish common pool parameters.  For extra caution,
+         * computations to set up common pool state are here; the
+         * constructor just assigns these values to fields.
+         */
+
+        int par = 0;
+        Thread.UncaughtExceptionHandler handler = null;
+        try {  // TBD: limit or report ignored exceptions?
+            String pp = System.getProperty
+                ("java.util.concurrent.ForkJoinPool.common.parallelism");
+            String hp = System.getProperty
+                ("java.util.concurrent.ForkJoinPool.common.exceptionHandler");
+            String fp = System.getProperty
+                ("java.util.concurrent.ForkJoinPool.common.threadFactory");
+            if (fp != null)
+                fac = ((ForkJoinWorkerThreadFactory)ClassLoader.
+                       getSystemClassLoader().loadClass(fp).newInstance());
+            if (hp != null)
+                handler = ((Thread.UncaughtExceptionHandler)ClassLoader.
+                           getSystemClassLoader().loadClass(hp).newInstance());
+            if (pp != null)
+                par = Integer.parseInt(pp);
+        } catch (Exception ignore) {
+        }
+
+        if (par <= 0)
+            par = Runtime.getRuntime().availableProcessors();
+        if (par > MAX_CAP)
+            par = MAX_CAP;
+        commonPoolParallelism = par;
+        long np = (long)(-par); // precompute initial ctl value
+        long ct = ((np << AC_SHIFT) & AC_MASK) | ((np << TC_SHIFT) & TC_MASK);
+
+        commonPool = new ForkJoinPool(par, ct, fac, handler);
     }
 
 }
--- a/jdk/src/share/classes/java/util/concurrent/ForkJoinTask.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/java/util/concurrent/ForkJoinTask.java	Wed Jul 05 18:34:47 2017 +0200
@@ -37,17 +37,13 @@
 
 import java.io.Serializable;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.List;
 import java.util.RandomAccess;
-import java.util.Map;
 import java.lang.ref.WeakReference;
 import java.lang.ref.ReferenceQueue;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CancellationException;
 import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Executor;
-import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Future;
 import java.util.concurrent.RejectedExecutionException;
 import java.util.concurrent.RunnableFuture;
@@ -63,46 +59,59 @@
  * subtasks may be hosted by a small number of actual threads in a
  * ForkJoinPool, at the price of some usage limitations.
  *
- * <p>A "main" {@code ForkJoinTask} begins execution when submitted
- * to a {@link ForkJoinPool}.  Once started, it will usually in turn
- * start other subtasks.  As indicated by the name of this class,
- * many programs using {@code ForkJoinTask} employ only methods
- * {@link #fork} and {@link #join}, or derivatives such as {@link
+ * <p>A "main" {@code ForkJoinTask} begins execution when it is
+ * explicitly submitted to a {@link ForkJoinPool}, or, if not already
+ * engaged in a ForkJoin computation, commenced in the {@link
+ * ForkJoinPool#commonPool()} via {@link #fork}, {@link #invoke}, or
+ * related methods.  Once started, it will usually in turn start other
+ * subtasks.  As indicated by the name of this class, many programs
+ * using {@code ForkJoinTask} employ only methods {@link #fork} and
+ * {@link #join}, or derivatives such as {@link
  * #invokeAll(ForkJoinTask...) invokeAll}.  However, this class also
  * provides a number of other methods that can come into play in
- * advanced usages, as well as extension mechanics that allow
- * support of new forms of fork/join processing.
+ * advanced usages, as well as extension mechanics that allow support
+ * of new forms of fork/join processing.
  *
  * <p>A {@code ForkJoinTask} is a lightweight form of {@link Future}.
  * The efficiency of {@code ForkJoinTask}s stems from a set of
  * restrictions (that are only partially statically enforceable)
- * reflecting their intended use as computational tasks calculating
- * pure functions or operating on purely isolated objects.  The
- * primary coordination mechanisms are {@link #fork}, that arranges
+ * reflecting their main use as computational tasks calculating pure
+ * functions or operating on purely isolated objects.  The primary
+ * coordination mechanisms are {@link #fork}, that arranges
  * asynchronous execution, and {@link #join}, that doesn't proceed
  * until the task's result has been computed.  Computations should
- * avoid {@code synchronized} methods or blocks, and should minimize
- * other blocking synchronization apart from joining other tasks or
- * using synchronizers such as Phasers that are advertised to
- * cooperate with fork/join scheduling. Tasks should also not perform
- * blocking IO, and should ideally access variables that are
- * completely independent of those accessed by other running
- * tasks. Minor breaches of these restrictions, for example using
- * shared output streams, may be tolerable in practice, but frequent
- * use may result in poor performance, and the potential to
- * indefinitely stall if the number of threads not waiting for IO or
- * other external synchronization becomes exhausted. This usage
- * restriction is in part enforced by not permitting checked
- * exceptions such as {@code IOExceptions} to be thrown. However,
- * computations may still encounter unchecked exceptions, that are
- * rethrown to callers attempting to join them. These exceptions may
- * additionally include {@link RejectedExecutionException} stemming
- * from internal resource exhaustion, such as failure to allocate
- * internal task queues. Rethrown exceptions behave in the same way as
- * regular exceptions, but, when possible, contain stack traces (as
- * displayed for example using {@code ex.printStackTrace()}) of both
- * the thread that initiated the computation as well as the thread
- * actually encountering the exception; minimally only the latter.
+ * ideally avoid {@code synchronized} methods or blocks, and should
+ * minimize other blocking synchronization apart from joining other
+ * tasks or using synchronizers such as Phasers that are advertised to
+ * cooperate with fork/join scheduling. Subdividable tasks should also
+ * not perform blocking I/O, and should ideally access variables that
+ * are completely independent of those accessed by other running
+ * tasks. These guidelines are loosely enforced by not permitting
+ * checked exceptions such as {@code IOExceptions} to be
+ * thrown. However, computations may still encounter unchecked
+ * exceptions, that are rethrown to callers attempting to join
+ * them. These exceptions may additionally include {@link
+ * RejectedExecutionException} stemming from internal resource
+ * exhaustion, such as failure to allocate internal task
+ * queues. Rethrown exceptions behave in the same way as regular
+ * exceptions, but, when possible, contain stack traces (as displayed
+ * for example using {@code ex.printStackTrace()}) of both the thread
+ * that initiated the computation as well as the thread actually
+ * encountering the exception; minimally only the latter.
+ *
+ * <p>It is possible to define and use ForkJoinTasks that may block,
+ * but doing do requires three further considerations: (1) Completion
+ * of few if any <em>other</em> tasks should be dependent on a task
+ * that blocks on external synchronization or I/O. Event-style async
+ * tasks that are never joined (for example, those subclassing {@link
+ * CountedCompleter}) often fall into this category.  (2) To minimize
+ * resource impact, tasks should be small; ideally performing only the
+ * (possibly) blocking action. (3) Unless the {@link
+ * ForkJoinPool.ManagedBlocker} API is used, or the number of possibly
+ * blocked tasks is known to be less than the pool's {@link
+ * ForkJoinPool#getParallelism} level, the pool cannot guarantee that
+ * enough threads will be available to ensure progress or good
+ * performance.
  *
  * <p>The primary method for awaiting completion and extracting
  * results of a task is {@link #join}, but there are several variants:
@@ -118,6 +127,13 @@
  * performs the most common form of parallel invocation: forking a set
  * of tasks and joining them all.
  *
+ * <p>In the most typical usages, a fork-join pair act like a call
+ * (fork) and return (join) from a parallel recursive function. As is
+ * the case with other forms of recursive calls, returns (joins)
+ * should be performed innermost-first. For example, {@code a.fork();
+ * b.fork(); b.join(); a.join();} is likely to be substantially more
+ * efficient than joining {@code a} before {@code b}.
+ *
  * <p>The execution status of tasks may be queried at several levels
  * of detail: {@link #isDone} is true if a task completed in any way
  * (including the case where a task was cancelled without executing);
@@ -133,18 +149,13 @@
  * <p>The ForkJoinTask class is not usually directly subclassed.
  * Instead, you subclass one of the abstract classes that support a
  * particular style of fork/join processing, typically {@link
- * RecursiveAction} for computations that do not return results, or
- * {@link RecursiveTask} for those that do.  Normally, a concrete
- * ForkJoinTask subclass declares fields comprising its parameters,
- * established in a constructor, and then defines a {@code compute}
- * method that somehow uses the control methods supplied by this base
- * class. While these methods have {@code public} access (to allow
- * instances of different task subclasses to call each other's
- * methods), some of them may only be called from within other
- * ForkJoinTasks (as may be determined using method {@link
- * #inForkJoinPool}).  Attempts to invoke them in other contexts
- * result in exceptions or errors, possibly including
- * {@code ClassCastException}.
+ * RecursiveAction} for most computations that do not return results,
+ * {@link RecursiveTask} for those that do, and {@link
+ * CountedCompleter} for those in which completed actions trigger
+ * other actions.  Normally, a concrete ForkJoinTask subclass declares
+ * fields comprising its parameters, established in a constructor, and
+ * then defines a {@code compute} method that somehow uses the control
+ * methods supplied by this base class.
  *
  * <p>Method {@link #join} and its variants are appropriate for use
  * only when completion dependencies are acyclic; that is, the
@@ -154,7 +165,17 @@
  * supports other methods and techniques (for example the use of
  * {@link Phaser}, {@link #helpQuiesce}, and {@link #complete}) that
  * may be of use in constructing custom subclasses for problems that
- * are not statically structured as DAGs.
+ * are not statically structured as DAGs. To support such usages a
+ * ForkJoinTask may be atomically <em>tagged</em> with a {@code short}
+ * value using {@link #setForkJoinTaskTag} or {@link
+ * #compareAndSetForkJoinTaskTag} and checked using {@link
+ * #getForkJoinTaskTag}. The ForkJoinTask implementation does not use
+ * these {@code protected} methods or tags for any purpose, but they
+ * may be of use in the construction of specialized subclasses.  For
+ * example, parallel graph traversals can use the supplied methods to
+ * avoid revisiting nodes/tasks that have already been processed.
+ * (Method names for tagging are bulky in part to encourage definition
+ * of methods that reflect their usage patterns.)
  *
  * <p>Most base support methods are {@code final}, to prevent
  * overriding of implementations that are intrinsically tied to the
@@ -194,41 +215,50 @@
      * See the internal documentation of class ForkJoinPool for a
      * general implementation overview.  ForkJoinTasks are mainly
      * responsible for maintaining their "status" field amidst relays
-     * to methods in ForkJoinWorkerThread and ForkJoinPool. The
-     * methods of this class are more-or-less layered into (1) basic
-     * status maintenance (2) execution and awaiting completion (3)
-     * user-level methods that additionally report results. This is
-     * sometimes hard to see because this file orders exported methods
-     * in a way that flows well in javadocs.
+     * to methods in ForkJoinWorkerThread and ForkJoinPool.
+     *
+     * The methods of this class are more-or-less layered into
+     * (1) basic status maintenance
+     * (2) execution and awaiting completion
+     * (3) user-level methods that additionally report results.
+     * This is sometimes hard to see because this file orders exported
+     * methods in a way that flows well in javadocs.
      */
 
     /*
      * The status field holds run control status bits packed into a
      * single int to minimize footprint and to ensure atomicity (via
      * CAS).  Status is initially zero, and takes on nonnegative
-     * values until completed, upon which status holds value
-     * NORMAL, CANCELLED, or EXCEPTIONAL. Tasks undergoing blocking
-     * waits by other threads have the SIGNAL bit set.  Completion of
-     * a stolen task with SIGNAL set awakens any waiters via
-     * notifyAll. Even though suboptimal for some purposes, we use
-     * basic builtin wait/notify to take advantage of "monitor
-     * inflation" in JVMs that we would otherwise need to emulate to
-     * avoid adding further per-task bookkeeping overhead.  We want
-     * these monitors to be "fat", i.e., not use biasing or thin-lock
-     * techniques, so use some odd coding idioms that tend to avoid
-     * them.
+     * values until completed, upon which status (anded with
+     * DONE_MASK) holds value NORMAL, CANCELLED, or EXCEPTIONAL. Tasks
+     * undergoing blocking waits by other threads have the SIGNAL bit
+     * set.  Completion of a stolen task with SIGNAL set awakens any
+     * waiters via notifyAll. Even though suboptimal for some
+     * purposes, we use basic builtin wait/notify to take advantage of
+     * "monitor inflation" in JVMs that we would otherwise need to
+     * emulate to avoid adding further per-task bookkeeping overhead.
+     * We want these monitors to be "fat", i.e., not use biasing or
+     * thin-lock techniques, so use some odd coding idioms that tend
+     * to avoid them, mainly by arranging that every synchronized
+     * block performs a wait, notifyAll or both.
+     *
+     * These control bits occupy only (some of) the upper half (16
+     * bits) of status field. The lower bits are used for user-defined
+     * tags.
      */
 
     /** The run status of this task */
     volatile int status; // accessed directly by pool and workers
-    private static final int NORMAL      = -1;
-    private static final int CANCELLED   = -2;
-    private static final int EXCEPTIONAL = -3;
-    private static final int SIGNAL      =  1;
+    static final int DONE_MASK   = 0xf0000000;  // mask out non-completion bits
+    static final int NORMAL      = 0xf0000000;  // must be negative
+    static final int CANCELLED   = 0xc0000000;  // must be < NORMAL
+    static final int EXCEPTIONAL = 0x80000000;  // must be < CANCELLED
+    static final int SIGNAL      = 0x00010000;  // must be >= 1 << 16
+    static final int SMASK       = 0x0000ffff;  // short bits for tags
 
     /**
-     * Marks completion and wakes up threads waiting to join this task,
-     * also clearing signal request bits.
+     * Marks completion and wakes up threads waiting to join this
+     * task.
      *
      * @param completion one of NORMAL, CANCELLED, EXCEPTIONAL
      * @return completion status on exit
@@ -237,8 +267,8 @@
         for (int s;;) {
             if ((s = status) < 0)
                 return s;
-            if (UNSAFE.compareAndSwapInt(this, statusOffset, s, completion)) {
-                if (s != 0)
+            if (U.compareAndSwapInt(this, STATUS, s, s | completion)) {
+                if ((s >>> 16) != 0)
                     synchronized (this) { notifyAll(); }
                 return completion;
             }
@@ -246,27 +276,36 @@
     }
 
     /**
-     * Tries to block a worker thread until completed or timed out.
-     * Uses Object.wait time argument conventions.
-     * May fail on contention or interrupt.
+     * Primary execution method for stolen tasks. Unless done, calls
+     * exec and records status if completed, but doesn't wait for
+     * completion otherwise.
      *
-     * @param millis if > 0, wait time.
+     * @return status on exit from this method
      */
-    final void tryAwaitDone(long millis) {
-        int s;
-        try {
-            if (((s = status) > 0 ||
-                 (s == 0 &&
-                  UNSAFE.compareAndSwapInt(this, statusOffset, 0, SIGNAL))) &&
-                status > 0) {
-                synchronized (this) {
-                    if (status > 0)
-                        wait(millis);
-                }
+    final int doExec() {
+        int s; boolean completed;
+        if ((s = status) >= 0) {
+            try {
+                completed = exec();
+            } catch (Throwable rex) {
+                return setExceptionalCompletion(rex);
             }
-        } catch (InterruptedException ie) {
-            // caller must check termination
+            if (completed)
+                s = setCompletion(NORMAL);
         }
+        return s;
+    }
+
+    /**
+     * Tries to set SIGNAL status unless already completed. Used by
+     * ForkJoinPool. Other variants are directly incorporated into
+     * externalAwaitDone etc.
+     *
+     * @return true if successful
+     */
+    final boolean trySetSignal() {
+        int s = status;
+        return s >= 0 && U.compareAndSwapInt(this, STATUS, s, s | SIGNAL);
     }
 
     /**
@@ -275,113 +314,78 @@
      */
     private int externalAwaitDone() {
         int s;
-        if ((s = status) >= 0) {
-            boolean interrupted = false;
-            synchronized (this) {
-                while ((s = status) >= 0) {
-                    if (s == 0)
-                        UNSAFE.compareAndSwapInt(this, statusOffset,
-                                                 0, SIGNAL);
-                    else {
+        ForkJoinPool.externalHelpJoin(this);
+        boolean interrupted = false;
+        while ((s = status) >= 0) {
+            if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
+                synchronized (this) {
+                    if (status >= 0) {
                         try {
                             wait();
                         } catch (InterruptedException ie) {
                             interrupted = true;
                         }
                     }
+                    else
+                        notifyAll();
                 }
             }
-            if (interrupted)
-                Thread.currentThread().interrupt();
         }
+        if (interrupted)
+            Thread.currentThread().interrupt();
         return s;
     }
 
     /**
-     * Blocks a non-worker-thread until completion or interruption or timeout.
+     * Blocks a non-worker-thread until completion or interruption.
      */
-    private int externalInterruptibleAwaitDone(long millis)
-        throws InterruptedException {
+    private int externalInterruptibleAwaitDone() throws InterruptedException {
         int s;
         if (Thread.interrupted())
             throw new InterruptedException();
-        if ((s = status) >= 0) {
-            synchronized (this) {
-                while ((s = status) >= 0) {
-                    if (s == 0)
-                        UNSAFE.compareAndSwapInt(this, statusOffset,
-                                                 0, SIGNAL);
-                    else {
-                        wait(millis);
-                        if (millis > 0L)
-                            break;
-                    }
+        ForkJoinPool.externalHelpJoin(this);
+        while ((s = status) >= 0) {
+            if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
+                synchronized (this) {
+                    if (status >= 0)
+                        wait();
+                    else
+                        notifyAll();
                 }
             }
         }
         return s;
     }
 
-    /**
-     * Primary execution method for stolen tasks. Unless done, calls
-     * exec and records status if completed, but doesn't wait for
-     * completion otherwise.
-     */
-    final void doExec() {
-        if (status >= 0) {
-            boolean completed;
-            try {
-                completed = exec();
-            } catch (Throwable rex) {
-                setExceptionalCompletion(rex);
-                return;
-            }
-            if (completed)
-                setCompletion(NORMAL); // must be outside try block
-        }
-    }
 
     /**
-     * Primary mechanics for join, get, quietlyJoin.
+     * Implementation for join, get, quietlyJoin. Directly handles
+     * only cases of already-completed, external wait, and
+     * unfork+exec.  Others are relayed to ForkJoinPool.awaitJoin.
+     *
      * @return status upon completion
      */
     private int doJoin() {
-        Thread t; ForkJoinWorkerThread w; int s; boolean completed;
-        if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) {
-            if ((s = status) < 0)
-                return s;
-            if ((w = (ForkJoinWorkerThread)t).unpushTask(this)) {
-                try {
-                    completed = exec();
-                } catch (Throwable rex) {
-                    return setExceptionalCompletion(rex);
-                }
-                if (completed)
-                    return setCompletion(NORMAL);
-            }
-            return w.joinTask(this);
-        }
-        else
-            return externalAwaitDone();
+        int s; Thread t; ForkJoinWorkerThread wt; ForkJoinPool.WorkQueue w;
+        return (s = status) < 0 ? s :
+            ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
+            (w = (wt = (ForkJoinWorkerThread)t).workQueue).
+            tryUnpush(this) && (s = doExec()) < 0 ? s :
+            wt.pool.awaitJoin(w, this) :
+            externalAwaitDone();
     }
 
     /**
-     * Primary mechanics for invoke, quietlyInvoke.
+     * Implementation for invoke, quietlyInvoke.
+     *
      * @return status upon completion
      */
     private int doInvoke() {
-        int s; boolean completed;
-        if ((s = status) < 0)
-            return s;
-        try {
-            completed = exec();
-        } catch (Throwable rex) {
-            return setExceptionalCompletion(rex);
-        }
-        if (completed)
-            return setCompletion(NORMAL);
-        else
-            return doJoin();
+        int s; Thread t; ForkJoinWorkerThread wt;
+        return (s = doExec()) < 0 ? s :
+            ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
+            (wt = (ForkJoinWorkerThread)t).pool.awaitJoin(wt.workQueue, this) :
+            externalAwaitDone();
     }
 
     // Exception table support
@@ -416,7 +420,7 @@
      * any ForkJoinPool will call helpExpungeStaleExceptions when its
      * pool becomes isQuiescent.
      */
-    static final class ExceptionNode extends WeakReference<ForkJoinTask<?>>{
+    static final class ExceptionNode extends WeakReference<ForkJoinTask<?>> {
         final Throwable ex;
         ExceptionNode next;
         final long thrower;  // use id not ref to avoid weak cycles
@@ -429,30 +433,67 @@
     }
 
     /**
-     * Records exception and sets exceptional completion.
+     * Records exception and sets status.
+     *
+     * @return status on exit
+     */
+    final int recordExceptionalCompletion(Throwable ex) {
+        int s;
+        if ((s = status) >= 0) {
+            int h = System.identityHashCode(this);
+            final ReentrantLock lock = exceptionTableLock;
+            lock.lock();
+            try {
+                expungeStaleExceptions();
+                ExceptionNode[] t = exceptionTable;
+                int i = h & (t.length - 1);
+                for (ExceptionNode e = t[i]; ; e = e.next) {
+                    if (e == null) {
+                        t[i] = new ExceptionNode(this, ex, t[i]);
+                        break;
+                    }
+                    if (e.get() == this) // already present
+                        break;
+                }
+            } finally {
+                lock.unlock();
+            }
+            s = setCompletion(EXCEPTIONAL);
+        }
+        return s;
+    }
+
+    /**
+     * Records exception and possibly propagates
      *
      * @return status on exit
      */
     private int setExceptionalCompletion(Throwable ex) {
-        int h = System.identityHashCode(this);
-        final ReentrantLock lock = exceptionTableLock;
-        lock.lock();
-        try {
-            expungeStaleExceptions();
-            ExceptionNode[] t = exceptionTable;
-            int i = h & (t.length - 1);
-            for (ExceptionNode e = t[i]; ; e = e.next) {
-                if (e == null) {
-                    t[i] = new ExceptionNode(this, ex, t[i]);
-                    break;
-                }
-                if (e.get() == this) // already present
-                    break;
+        int s = recordExceptionalCompletion(ex);
+        if ((s & DONE_MASK) == EXCEPTIONAL)
+            internalPropagateException(ex);
+        return s;
+    }
+
+    /**
+     * Hook for exception propagation support for tasks with completers.
+     */
+    void internalPropagateException(Throwable ex) {
+    }
+
+    /**
+     * Cancels, ignoring any exceptions thrown by cancel. Used during
+     * worker and pool shutdown. Cancel is spec'ed not to throw any
+     * exceptions, but if it does anyway, we have no recourse during
+     * shutdown, so guard against this case.
+     */
+    static final void cancelIgnoringExceptions(ForkJoinTask<?> t) {
+        if (t != null && t.status >= 0) {
+            try {
+                t.cancel(false);
+            } catch (Throwable ignore) {
             }
-        } finally {
-            lock.unlock();
         }
-        return setCompletion(EXCEPTIONAL);
     }
 
     /**
@@ -501,7 +542,7 @@
      * @return the exception, or null if none
      */
     private Throwable getThrowableException() {
-        if (status != EXCEPTIONAL)
+        if ((status & DONE_MASK) != EXCEPTIONAL)
             return null;
         int h = System.identityHashCode(this);
         ExceptionNode e;
@@ -519,7 +560,7 @@
         Throwable ex;
         if (e == null || (ex = e.ex) == null)
             return null;
-        if (e.thrower != Thread.currentThread().getId()) {
+        if (false && e.thrower != Thread.currentThread().getId()) {
             Class<? extends Throwable> ec = ex.getClass();
             try {
                 Constructor<?> noArgCtor = null;
@@ -586,41 +627,61 @@
     }
 
     /**
-     * Report the result of invoke or join; called only upon
-     * non-normal return of internal versions.
+     * A version of "sneaky throw" to relay exceptions
      */
-    private V reportResult() {
-        int s; Throwable ex;
-        if ((s = status) == CANCELLED)
+    static void rethrow(final Throwable ex) {
+        if (ex != null) {
+            if (ex instanceof Error)
+                throw (Error)ex;
+            if (ex instanceof RuntimeException)
+                throw (RuntimeException)ex;
+            throw uncheckedThrowable(ex, RuntimeException.class);
+        }
+    }
+
+    /**
+     * The sneaky part of sneaky throw, relying on generics
+     * limitations to evade compiler complaints about rethrowing
+     * unchecked exceptions
+     */
+    @SuppressWarnings("unchecked") static <T extends Throwable>
+        T uncheckedThrowable(final Throwable t, final Class<T> c) {
+        return (T)t; // rely on vacuous cast
+    }
+
+    /**
+     * Throws exception, if any, associated with the given status.
+     */
+    private void reportException(int s) {
+        if (s == CANCELLED)
             throw new CancellationException();
-        if (s == EXCEPTIONAL && (ex = getThrowableException()) != null)
-            UNSAFE.throwException(ex);
-        return getRawResult();
+        if (s == EXCEPTIONAL)
+            rethrow(getThrowableException());
     }
 
     // public methods
 
     /**
-     * Arranges to asynchronously execute this task.  While it is not
-     * necessarily enforced, it is a usage error to fork a task more
-     * than once unless it has completed and been reinitialized.
-     * Subsequent modifications to the state of this task or any data
-     * it operates on are not necessarily consistently observable by
-     * any thread other than the one executing it unless preceded by a
-     * call to {@link #join} or related methods, or a call to {@link
-     * #isDone} returning {@code true}.
-     *
-     * <p>This method may be invoked only from within {@code
-     * ForkJoinPool} computations (as may be determined using method
-     * {@link #inForkJoinPool}).  Attempts to invoke in other contexts
-     * result in exceptions or errors, possibly including {@code
-     * ClassCastException}.
+     * Arranges to asynchronously execute this task in the pool the
+     * current task is running in, if applicable, or using the {@link
+     * ForkJoinPool#commonPool()} if not {@link #inForkJoinPool}.  While
+     * it is not necessarily enforced, it is a usage error to fork a
+     * task more than once unless it has completed and been
+     * reinitialized.  Subsequent modifications to the state of this
+     * task or any data it operates on are not necessarily
+     * consistently observable by any thread other than the one
+     * executing it unless preceded by a call to {@link #join} or
+     * related methods, or a call to {@link #isDone} returning {@code
+     * true}.
      *
      * @return {@code this}, to simplify usage
      */
     public final ForkJoinTask<V> fork() {
-        ((ForkJoinWorkerThread) Thread.currentThread())
-            .pushTask(this);
+        Thread t;
+        if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)
+            ((ForkJoinWorkerThread)t).workQueue.push(this);
+        else
+            ForkJoinPool.commonPool.externalPush(this);
         return this;
     }
 
@@ -636,10 +697,10 @@
      * @return the computed result
      */
     public final V join() {
-        if (doJoin() != NORMAL)
-            return reportResult();
-        else
-            return getRawResult();
+        int s;
+        if ((s = doJoin() & DONE_MASK) != NORMAL)
+            reportException(s);
+        return getRawResult();
     }
 
     /**
@@ -651,10 +712,10 @@
      * @return the computed result
      */
     public final V invoke() {
-        if (doInvoke() != NORMAL)
-            return reportResult();
-        else
-            return getRawResult();
+        int s;
+        if ((s = doInvoke() & DONE_MASK) != NORMAL)
+            reportException(s);
+        return getRawResult();
     }
 
     /**
@@ -670,20 +731,17 @@
      * cancelled, completed normally or exceptionally, or left
      * unprocessed.
      *
-     * <p>This method may be invoked only from within {@code
-     * ForkJoinPool} computations (as may be determined using method
-     * {@link #inForkJoinPool}).  Attempts to invoke in other contexts
-     * result in exceptions or errors, possibly including {@code
-     * ClassCastException}.
-     *
      * @param t1 the first task
      * @param t2 the second task
      * @throws NullPointerException if any task is null
      */
     public static void invokeAll(ForkJoinTask<?> t1, ForkJoinTask<?> t2) {
+        int s1, s2;
         t2.fork();
-        t1.invoke();
-        t2.join();
+        if ((s1 = t1.doInvoke() & DONE_MASK) != NORMAL)
+            t1.reportException(s1);
+        if ((s2 = t2.doJoin() & DONE_MASK) != NORMAL)
+            t2.reportException(s2);
     }
 
     /**
@@ -698,12 +756,6 @@
      * related methods to check if they have been cancelled, completed
      * normally or exceptionally, or left unprocessed.
      *
-     * <p>This method may be invoked only from within {@code
-     * ForkJoinPool} computations (as may be determined using method
-     * {@link #inForkJoinPool}).  Attempts to invoke in other contexts
-     * result in exceptions or errors, possibly including {@code
-     * ClassCastException}.
-     *
      * @param tasks the tasks
      * @throws NullPointerException if any task is null
      */
@@ -726,12 +778,12 @@
             if (t != null) {
                 if (ex != null)
                     t.cancel(false);
-                else if (t.doJoin() < NORMAL && ex == null)
+                else if (t.doJoin() < NORMAL)
                     ex = t.getException();
             }
         }
         if (ex != null)
-            UNSAFE.throwException(ex);
+            rethrow(ex);
     }
 
     /**
@@ -747,12 +799,6 @@
      * cancelled, completed normally or exceptionally, or left
      * unprocessed.
      *
-     * <p>This method may be invoked only from within {@code
-     * ForkJoinPool} computations (as may be determined using method
-     * {@link #inForkJoinPool}).  Attempts to invoke in other contexts
-     * result in exceptions or errors, possibly including {@code
-     * ClassCastException}.
-     *
      * @param tasks the collection of tasks
      * @return the tasks argument, to simplify usage
      * @throws NullPointerException if tasks or any element are null
@@ -783,12 +829,12 @@
             if (t != null) {
                 if (ex != null)
                     t.cancel(false);
-                else if (t.doJoin() < NORMAL && ex == null)
+                else if (t.doJoin() < NORMAL)
                     ex = t.getException();
             }
         }
         if (ex != null)
-            UNSAFE.throwException(ex);
+            rethrow(ex);
         return tasks;
     }
 
@@ -820,20 +866,7 @@
      * @return {@code true} if this task is now cancelled
      */
     public boolean cancel(boolean mayInterruptIfRunning) {
-        return setCompletion(CANCELLED) == CANCELLED;
-    }
-
-    /**
-     * Cancels, ignoring any exceptions thrown by cancel. Used during
-     * worker and pool shutdown. Cancel is spec'ed not to throw any
-     * exceptions, but if it does anyway, we have no recourse during
-     * shutdown, so guard against this case.
-     */
-    final void cancelIgnoringExceptions() {
-        try {
-            cancel(false);
-        } catch (Throwable ignore) {
-        }
+        return (setCompletion(CANCELLED) & DONE_MASK) == CANCELLED;
     }
 
     public final boolean isDone() {
@@ -841,7 +874,7 @@
     }
 
     public final boolean isCancelled() {
-        return status == CANCELLED;
+        return (status & DONE_MASK) == CANCELLED;
     }
 
     /**
@@ -861,7 +894,7 @@
      * exception and was not cancelled
      */
     public final boolean isCompletedNormally() {
-        return status == NORMAL;
+        return (status & DONE_MASK) == NORMAL;
     }
 
     /**
@@ -872,7 +905,7 @@
      * @return the exception, or {@code null} if none
      */
     public final Throwable getException() {
-        int s = status;
+        int s = status & DONE_MASK;
         return ((s >= NORMAL)    ? null :
                 (s == CANCELLED) ? new CancellationException() :
                 getThrowableException());
@@ -922,6 +955,18 @@
     }
 
     /**
+     * Completes this task normally without setting a value. The most
+     * recent value established by {@link #setRawResult} (or {@code
+     * null} by default) will be returned as the result of subsequent
+     * invocations of {@code join} and related operations.
+     *
+     * @since 1.8
+     */
+    public final void quietlyComplete() {
+        setCompletion(NORMAL);
+    }
+
+    /**
      * Waits if necessary for the computation to complete, and then
      * retrieves its result.
      *
@@ -934,9 +979,9 @@
      */
     public final V get() throws InterruptedException, ExecutionException {
         int s = (Thread.currentThread() instanceof ForkJoinWorkerThread) ?
-            doJoin() : externalInterruptibleAwaitDone(0L);
+            doJoin() : externalInterruptibleAwaitDone();
         Throwable ex;
-        if (s == CANCELLED)
+        if ((s &= DONE_MASK) == CANCELLED)
             throw new CancellationException();
         if (s == EXCEPTIONAL && (ex = getThrowableException()) != null)
             throw new ExecutionException(ex);
@@ -959,32 +1004,62 @@
      */
     public final V get(long timeout, TimeUnit unit)
         throws InterruptedException, ExecutionException, TimeoutException {
-        Thread t = Thread.currentThread();
-        if (t instanceof ForkJoinWorkerThread) {
-            ForkJoinWorkerThread w = (ForkJoinWorkerThread) t;
-            long nanos = unit.toNanos(timeout);
-            if (status >= 0) {
-                boolean completed = false;
-                if (w.unpushTask(this)) {
-                    try {
-                        completed = exec();
-                    } catch (Throwable rex) {
-                        setExceptionalCompletion(rex);
+        if (Thread.interrupted())
+            throw new InterruptedException();
+        // Messy in part because we measure in nanosecs, but wait in millisecs
+        int s; long ns, ms;
+        if ((s = status) >= 0 && (ns = unit.toNanos(timeout)) > 0L) {
+            long deadline = System.nanoTime() + ns;
+            ForkJoinPool p = null;
+            ForkJoinPool.WorkQueue w = null;
+            Thread t = Thread.currentThread();
+            if (t instanceof ForkJoinWorkerThread) {
+                ForkJoinWorkerThread wt = (ForkJoinWorkerThread)t;
+                p = wt.pool;
+                w = wt.workQueue;
+                p.helpJoinOnce(w, this); // no retries on failure
+            }
+            else
+                ForkJoinPool.externalHelpJoin(this);
+            boolean canBlock = false;
+            boolean interrupted = false;
+            try {
+                while ((s = status) >= 0) {
+                    if (w != null && w.qlock < 0)
+                        cancelIgnoringExceptions(this);
+                    else if (!canBlock) {
+                        if (p == null || p.tryCompensate())
+                            canBlock = true;
+                    }
+                    else {
+                        if ((ms = TimeUnit.NANOSECONDS.toMillis(ns)) > 0L &&
+                            U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
+                            synchronized (this) {
+                                if (status >= 0) {
+                                    try {
+                                        wait(ms);
+                                    } catch (InterruptedException ie) {
+                                        if (p == null)
+                                            interrupted = true;
+                                    }
+                                }
+                                else
+                                    notifyAll();
+                            }
+                        }
+                        if ((s = status) < 0 || interrupted ||
+                            (ns = deadline - System.nanoTime()) <= 0L)
+                            break;
                     }
                 }
-                if (completed)
-                    setCompletion(NORMAL);
-                else if (status >= 0 && nanos > 0)
-                    w.pool.timedAwaitJoin(this, nanos);
+            } finally {
+                if (p != null && canBlock)
+                    p.incrementActiveCount();
             }
+            if (interrupted)
+                throw new InterruptedException();
         }
-        else {
-            long millis = unit.toMillis(timeout);
-            if (millis > 0)
-                externalInterruptibleAwaitDone(millis);
-        }
-        int s = status;
-        if (s != NORMAL) {
+        if ((s &= DONE_MASK) != NORMAL) {
             Throwable ex;
             if (s == CANCELLED)
                 throw new CancellationException();
@@ -1021,16 +1096,15 @@
      * be of use in designs in which many tasks are forked, but none
      * are explicitly joined, instead executing them until all are
      * processed.
-     *
-     * <p>This method may be invoked only from within {@code
-     * ForkJoinPool} computations (as may be determined using method
-     * {@link #inForkJoinPool}).  Attempts to invoke in other contexts
-     * result in exceptions or errors, possibly including {@code
-     * ClassCastException}.
      */
     public static void helpQuiesce() {
-        ((ForkJoinWorkerThread) Thread.currentThread())
-            .helpQuiescePool();
+        Thread t;
+        if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) {
+            ForkJoinWorkerThread wt = (ForkJoinWorkerThread)t;
+            wt.pool.helpQuiescePool(wt.workQueue);
+        }
+        else
+            ForkJoinPool.externalHelpQuiescePool();
     }
 
     /**
@@ -1050,7 +1124,7 @@
      * setRawResult(null)}.
      */
     public void reinitialize() {
-        if (status == EXCEPTIONAL)
+        if ((status & DONE_MASK) == EXCEPTIONAL)
             clearExceptionalCompletion();
         else
             status = 0;
@@ -1083,23 +1157,19 @@
 
     /**
      * Tries to unschedule this task for execution. This method will
-     * typically succeed if this task is the most recently forked task
-     * by the current thread, and has not commenced executing in
-     * another thread.  This method may be useful when arranging
-     * alternative local processing of tasks that could have been, but
-     * were not, stolen.
-     *
-     * <p>This method may be invoked only from within {@code
-     * ForkJoinPool} computations (as may be determined using method
-     * {@link #inForkJoinPool}).  Attempts to invoke in other contexts
-     * result in exceptions or errors, possibly including {@code
-     * ClassCastException}.
+     * typically (but is not guaranteed to) succeed if this task is
+     * the most recently forked task by the current thread, and has
+     * not commenced executing in another thread.  This method may be
+     * useful when arranging alternative local processing of tasks
+     * that could have been, but were not, stolen.
      *
      * @return {@code true} if unforked
      */
     public boolean tryUnfork() {
-        return ((ForkJoinWorkerThread) Thread.currentThread())
-            .unpushTask(this);
+        Thread t;
+        return (((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
+                ((ForkJoinWorkerThread)t).workQueue.tryUnpush(this) :
+                ForkJoinPool.tryExternalUnpush(this));
     }
 
     /**
@@ -1108,40 +1178,32 @@
      * value may be useful for heuristic decisions about whether to
      * fork other tasks.
      *
-     * <p>This method may be invoked only from within {@code
-     * ForkJoinPool} computations (as may be determined using method
-     * {@link #inForkJoinPool}).  Attempts to invoke in other contexts
-     * result in exceptions or errors, possibly including {@code
-     * ClassCastException}.
-     *
      * @return the number of tasks
      */
     public static int getQueuedTaskCount() {
-        return ((ForkJoinWorkerThread) Thread.currentThread())
-            .getQueueSize();
+        Thread t; ForkJoinPool.WorkQueue q;
+        if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)
+            q = ((ForkJoinWorkerThread)t).workQueue;
+        else
+            q = ForkJoinPool.commonSubmitterQueue();
+        return (q == null) ? 0 : q.queueSize();
     }
 
     /**
      * Returns an estimate of how many more locally queued tasks are
      * held by the current worker thread than there are other worker
-     * threads that might steal them.  This value may be useful for
+     * threads that might steal them, or zero if this thread is not
+     * operating in a ForkJoinPool. This value may be useful for
      * heuristic decisions about whether to fork other tasks. In many
      * usages of ForkJoinTasks, at steady state, each worker should
      * aim to maintain a small constant surplus (for example, 3) of
      * tasks, and to process computations locally if this threshold is
      * exceeded.
      *
-     * <p>This method may be invoked only from within {@code
-     * ForkJoinPool} computations (as may be determined using method
-     * {@link #inForkJoinPool}).  Attempts to invoke in other contexts
-     * result in exceptions or errors, possibly including {@code
-     * ClassCastException}.
-     *
      * @return the surplus number of tasks, which may be negative
      */
     public static int getSurplusQueuedTaskCount() {
-        return ((ForkJoinWorkerThread) Thread.currentThread())
-            .getEstimatedSurplusTaskCount();
+        return ForkJoinPool.getSurplusQueuedTaskCount();
     }
 
     // Extension methods
@@ -1167,15 +1229,18 @@
     protected abstract void setRawResult(V value);
 
     /**
-     * Immediately performs the base action of this task.  This method
-     * is designed to support extensions, and should not in general be
-     * called otherwise. The return value controls whether this task
-     * is considered to be done normally. It may return false in
+     * Immediately performs the base action of this task and returns
+     * true if, upon return from this method, this task is guaranteed
+     * to have completed normally. This method may return false
+     * otherwise, to indicate that this task is not necessarily
+     * complete (or is not known to be complete), for example in
      * asynchronous actions that require explicit invocations of
-     * {@link #complete} to become joinable. It may also throw an
-     * (unchecked) exception to indicate abnormal exit.
+     * completion methods. This method may also throw an (unchecked)
+     * exception to indicate abnormal exit. This method is designed to
+     * support extensions, and should not in general be called
+     * otherwise.
      *
-     * @return {@code true} if completed normally
+     * @return {@code true} if this task is known to have completed normally
      */
     protected abstract boolean exec();
 
@@ -1189,59 +1254,102 @@
      * primarily to support extensions, and is unlikely to be useful
      * otherwise.
      *
-     * <p>This method may be invoked only from within {@code
-     * ForkJoinPool} computations (as may be determined using method
-     * {@link #inForkJoinPool}).  Attempts to invoke in other contexts
-     * result in exceptions or errors, possibly including {@code
-     * ClassCastException}.
-     *
      * @return the next task, or {@code null} if none are available
      */
     protected static ForkJoinTask<?> peekNextLocalTask() {
-        return ((ForkJoinWorkerThread) Thread.currentThread())
-            .peekTask();
+        Thread t; ForkJoinPool.WorkQueue q;
+        if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)
+            q = ((ForkJoinWorkerThread)t).workQueue;
+        else
+            q = ForkJoinPool.commonSubmitterQueue();
+        return (q == null) ? null : q.peek();
     }
 
     /**
      * Unschedules and returns, without executing, the next task
-     * queued by the current thread but not yet executed.  This method
-     * is designed primarily to support extensions, and is unlikely to
-     * be useful otherwise.
-     *
-     * <p>This method may be invoked only from within {@code
-     * ForkJoinPool} computations (as may be determined using method
-     * {@link #inForkJoinPool}).  Attempts to invoke in other contexts
-     * result in exceptions or errors, possibly including {@code
-     * ClassCastException}.
+     * queued by the current thread but not yet executed, if the
+     * current thread is operating in a ForkJoinPool.  This method is
+     * designed primarily to support extensions, and is unlikely to be
+     * useful otherwise.
      *
      * @return the next task, or {@code null} if none are available
      */
     protected static ForkJoinTask<?> pollNextLocalTask() {
-        return ((ForkJoinWorkerThread) Thread.currentThread())
-            .pollLocalTask();
+        Thread t;
+        return ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
+            ((ForkJoinWorkerThread)t).workQueue.nextLocalTask() :
+            null;
     }
 
     /**
-     * Unschedules and returns, without executing, the next task
+     * If the current thread is operating in a ForkJoinPool,
+     * unschedules and returns, without executing, the next task
      * queued by the current thread but not yet executed, if one is
      * available, or if not available, a task that was forked by some
      * other thread, if available. Availability may be transient, so a
-     * {@code null} result does not necessarily imply quiescence
-     * of the pool this task is operating in.  This method is designed
+     * {@code null} result does not necessarily imply quiescence of
+     * the pool this task is operating in.  This method is designed
      * primarily to support extensions, and is unlikely to be useful
      * otherwise.
      *
-     * <p>This method may be invoked only from within {@code
-     * ForkJoinPool} computations (as may be determined using method
-     * {@link #inForkJoinPool}).  Attempts to invoke in other contexts
-     * result in exceptions or errors, possibly including {@code
-     * ClassCastException}.
-     *
      * @return a task, or {@code null} if none are available
      */
     protected static ForkJoinTask<?> pollTask() {
-        return ((ForkJoinWorkerThread) Thread.currentThread())
-            .pollTask();
+        Thread t; ForkJoinWorkerThread wt;
+        return ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
+            (wt = (ForkJoinWorkerThread)t).pool.nextTaskFor(wt.workQueue) :
+            null;
+    }
+
+    // tag operations
+
+    /**
+     * Returns the tag for this task.
+     *
+     * @return the tag for this task
+     * @since 1.8
+     */
+    public final short getForkJoinTaskTag() {
+        return (short)status;
+    }
+
+    /**
+     * Atomically sets the tag value for this task.
+     *
+     * @param tag the tag value
+     * @return the previous value of the tag
+     * @since 1.8
+     */
+    public final short setForkJoinTaskTag(short tag) {
+        for (int s;;) {
+            if (U.compareAndSwapInt(this, STATUS, s = status,
+                                    (s & ~SMASK) | (tag & SMASK)))
+                return (short)s;
+        }
+    }
+
+    /**
+     * Atomically conditionally sets the tag value for this task.
+     * Among other applications, tags can be used as visit markers
+     * in tasks operating on graphs, as in methods that check: {@code
+     * if (task.compareAndSetForkJoinTaskTag((short)0, (short)1))}
+     * before processing, otherwise exiting because the node has
+     * already been visited.
+     *
+     * @param e the expected tag value
+     * @param tag the new tag value
+     * @return true if successful; i.e., the current value was
+     * equal to e and is now tag.
+     * @since 1.8
+     */
+    public final boolean compareAndSetForkJoinTaskTag(short e, short tag) {
+        for (int s;;) {
+            if ((short)(s = status) != e)
+                return false;
+            if (U.compareAndSwapInt(this, STATUS, s,
+                                    (s & ~SMASK) | (tag & SMASK)))
+                return true;
+        }
     }
 
     /**
@@ -1252,21 +1360,33 @@
     static final class AdaptedRunnable<T> extends ForkJoinTask<T>
         implements RunnableFuture<T> {
         final Runnable runnable;
-        final T resultOnCompletion;
         T result;
         AdaptedRunnable(Runnable runnable, T result) {
             if (runnable == null) throw new NullPointerException();
             this.runnable = runnable;
-            this.resultOnCompletion = result;
+            this.result = result; // OK to set this even before completion
         }
-        public T getRawResult() { return result; }
-        public void setRawResult(T v) { result = v; }
-        public boolean exec() {
-            runnable.run();
-            result = resultOnCompletion;
-            return true;
+        public final T getRawResult() { return result; }
+        public final void setRawResult(T v) { result = v; }
+        public final boolean exec() { runnable.run(); return true; }
+        public final void run() { invoke(); }
+        private static final long serialVersionUID = 5232453952276885070L;
+    }
+
+    /**
+     * Adaptor for Runnables without results
+     */
+    static final class AdaptedRunnableAction extends ForkJoinTask<Void>
+        implements RunnableFuture<Void> {
+        final Runnable runnable;
+        AdaptedRunnableAction(Runnable runnable) {
+            if (runnable == null) throw new NullPointerException();
+            this.runnable = runnable;
         }
-        public void run() { invoke(); }
+        public final Void getRawResult() { return null; }
+        public final void setRawResult(Void v) { }
+        public final boolean exec() { runnable.run(); return true; }
+        public final void run() { invoke(); }
         private static final long serialVersionUID = 5232453952276885070L;
     }
 
@@ -1281,9 +1401,9 @@
             if (callable == null) throw new NullPointerException();
             this.callable = callable;
         }
-        public T getRawResult() { return result; }
-        public void setRawResult(T v) { result = v; }
-        public boolean exec() {
+        public final T getRawResult() { return result; }
+        public final void setRawResult(T v) { result = v; }
+        public final boolean exec() {
             try {
                 result = callable.call();
                 return true;
@@ -1295,7 +1415,7 @@
                 throw new RuntimeException(ex);
             }
         }
-        public void run() { invoke(); }
+        public final void run() { invoke(); }
         private static final long serialVersionUID = 2838392045355241008L;
     }
 
@@ -1308,7 +1428,7 @@
      * @return the task
      */
     public static ForkJoinTask<?> adapt(Runnable runnable) {
-        return new AdaptedRunnable<Void>(runnable, null);
+        return new AdaptedRunnableAction(runnable);
     }
 
     /**
@@ -1342,11 +1462,10 @@
     private static final long serialVersionUID = -7721805057305804111L;
 
     /**
-     * Saves the state to a stream (that is, serializes it).
+     * Saves this task to a stream (that is, serializes it).
      *
      * @serialData the current run status and the exception thrown
      * during execution, or {@code null} if none
-     * @param s the stream
      */
     private void writeObject(java.io.ObjectOutputStream s)
         throws java.io.IOException {
@@ -1355,9 +1474,7 @@
     }
 
     /**
-     * Reconstitutes the instance from a stream (that is, deserializes it).
-     *
-     * @param s the stream
+     * Reconstitutes this task from a stream (that is, deserializes it).
      */
     private void readObject(java.io.ObjectInputStream s)
         throws java.io.IOException, ClassNotFoundException {
@@ -1368,16 +1485,18 @@
     }
 
     // Unsafe mechanics
-    private static final sun.misc.Unsafe UNSAFE;
-    private static final long statusOffset;
+    private static final sun.misc.Unsafe U;
+    private static final long STATUS;
+
     static {
         exceptionTableLock = new ReentrantLock();
         exceptionTableRefQueue = new ReferenceQueue<Object>();
         exceptionTable = new ExceptionNode[EXCEPTION_MAP_CAPACITY];
         try {
-            UNSAFE = sun.misc.Unsafe.getUnsafe();
-            statusOffset = UNSAFE.objectFieldOffset
-                (ForkJoinTask.class.getDeclaredField("status"));
+            U = sun.misc.Unsafe.getUnsafe();
+            Class<?> k = ForkJoinTask.class;
+            STATUS = U.objectFieldOffset
+                (k.getDeclaredField("status"));
         } catch (Exception e) {
             throw new Error(e);
         }
--- a/jdk/src/share/classes/java/util/concurrent/ForkJoinWorkerThread.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/java/util/concurrent/ForkJoinWorkerThread.java	Wed Jul 05 18:34:47 2017 +0200
@@ -35,9 +35,6 @@
 
 package java.util.concurrent;
 
-import java.util.Collection;
-import java.util.concurrent.RejectedExecutionException;
-
 /**
  * A thread managed by a {@link ForkJoinPool}, which executes
  * {@link ForkJoinTask}s.
@@ -54,238 +51,20 @@
  */
 public class ForkJoinWorkerThread extends Thread {
     /*
-     * Overview:
-     *
      * ForkJoinWorkerThreads are managed by ForkJoinPools and perform
-     * ForkJoinTasks. This class includes bookkeeping in support of
-     * worker activation, suspension, and lifecycle control described
-     * in more detail in the internal documentation of class
-     * ForkJoinPool. And as described further below, this class also
-     * includes special-cased support for some ForkJoinTask
-     * methods. But the main mechanics involve work-stealing:
-     *
-     * Work-stealing queues are special forms of Deques that support
-     * only three of the four possible end-operations -- push, pop,
-     * and deq (aka steal), under the further constraints that push
-     * and pop are called only from the owning thread, while deq may
-     * be called from other threads.  (If you are unfamiliar with
-     * them, you probably want to read Herlihy and Shavit's book "The
-     * Art of Multiprocessor programming", chapter 16 describing these
-     * in more detail before proceeding.)  The main work-stealing
-     * queue design is roughly similar to those in the papers "Dynamic
-     * Circular Work-Stealing Deque" by Chase and Lev, SPAA 2005
-     * (http://research.sun.com/scalable/pubs/index.html) and
-     * "Idempotent work stealing" by Michael, Saraswat, and Vechev,
-     * PPoPP 2009 (http://portal.acm.org/citation.cfm?id=1504186).
-     * The main differences ultimately stem from gc requirements that
-     * we null out taken slots as soon as we can, to maintain as small
-     * a footprint as possible even in programs generating huge
-     * numbers of tasks. To accomplish this, we shift the CAS
-     * arbitrating pop vs deq (steal) from being on the indices
-     * ("queueBase" and "queueTop") to the slots themselves (mainly
-     * via method "casSlotNull()"). So, both a successful pop and deq
-     * mainly entail a CAS of a slot from non-null to null.  Because
-     * we rely on CASes of references, we do not need tag bits on
-     * queueBase or queueTop.  They are simple ints as used in any
-     * circular array-based queue (see for example ArrayDeque).
-     * Updates to the indices must still be ordered in a way that
-     * guarantees that queueTop == queueBase means the queue is empty,
-     * but otherwise may err on the side of possibly making the queue
-     * appear nonempty when a push, pop, or deq have not fully
-     * committed. Note that this means that the deq operation,
-     * considered individually, is not wait-free. One thief cannot
-     * successfully continue until another in-progress one (or, if
-     * previously empty, a push) completes.  However, in the
-     * aggregate, we ensure at least probabilistic non-blockingness.
-     * If an attempted steal fails, a thief always chooses a different
-     * random victim target to try next. So, in order for one thief to
-     * progress, it suffices for any in-progress deq or new push on
-     * any empty queue to complete.
+     * ForkJoinTasks. For explanation, see the internal documentation
+     * of class ForkJoinPool.
      *
-     * This approach also enables support for "async mode" where local
-     * task processing is in FIFO, not LIFO order; simply by using a
-     * version of deq rather than pop when locallyFifo is true (as set
-     * by the ForkJoinPool).  This allows use in message-passing
-     * frameworks in which tasks are never joined.  However neither
-     * mode considers affinities, loads, cache localities, etc, so
-     * rarely provide the best possible performance on a given
-     * machine, but portably provide good throughput by averaging over
-     * these factors.  (Further, even if we did try to use such
-     * information, we do not usually have a basis for exploiting
-     * it. For example, some sets of tasks profit from cache
-     * affinities, but others are harmed by cache pollution effects.)
-     *
-     * When a worker would otherwise be blocked waiting to join a
-     * task, it first tries a form of linear helping: Each worker
-     * records (in field currentSteal) the most recent task it stole
-     * from some other worker. Plus, it records (in field currentJoin)
-     * the task it is currently actively joining. Method joinTask uses
-     * these markers to try to find a worker to help (i.e., steal back
-     * a task from and execute it) that could hasten completion of the
-     * actively joined task. In essence, the joiner executes a task
-     * that would be on its own local deque had the to-be-joined task
-     * not been stolen. This may be seen as a conservative variant of
-     * the approach in Wagner & Calder "Leapfrogging: a portable
-     * technique for implementing efficient futures" SIGPLAN Notices,
-     * 1993 (http://portal.acm.org/citation.cfm?id=155354). It differs
-     * in that: (1) We only maintain dependency links across workers
-     * upon steals, rather than use per-task bookkeeping.  This may
-     * require a linear scan of workers array to locate stealers, but
-     * usually doesn't because stealers leave hints (that may become
-     * stale/wrong) of where to locate them. This isolates cost to
-     * when it is needed, rather than adding to per-task overhead.
-     * (2) It is "shallow", ignoring nesting and potentially cyclic
-     * mutual steals.  (3) It is intentionally racy: field currentJoin
-     * is updated only while actively joining, which means that we
-     * miss links in the chain during long-lived tasks, GC stalls etc
-     * (which is OK since blocking in such cases is usually a good
-     * idea).  (4) We bound the number of attempts to find work (see
-     * MAX_HELP) and fall back to suspending the worker and if
-     * necessary replacing it with another.
-     *
-     * Efficient implementation of these algorithms currently relies
-     * on an uncomfortable amount of "Unsafe" mechanics. To maintain
-     * correct orderings, reads and writes of variable queueBase
-     * require volatile ordering.  Variable queueTop need not be
-     * volatile because non-local reads always follow those of
-     * queueBase.  Similarly, because they are protected by volatile
-     * queueBase reads, reads of the queue array and its slots by
-     * other threads do not need volatile load semantics, but writes
-     * (in push) require store order and CASes (in pop and deq)
-     * require (volatile) CAS semantics.  (Michael, Saraswat, and
-     * Vechev's algorithm has similar properties, but without support
-     * for nulling slots.)  Since these combinations aren't supported
-     * using ordinary volatiles, the only way to accomplish these
-     * efficiently is to use direct Unsafe calls. (Using external
-     * AtomicIntegers and AtomicReferenceArrays for the indices and
-     * array is significantly slower because of memory locality and
-     * indirection effects.)
-     *
-     * Further, performance on most platforms is very sensitive to
-     * placement and sizing of the (resizable) queue array.  Even
-     * though these queues don't usually become all that big, the
-     * initial size must be large enough to counteract cache
-     * contention effects across multiple queues (especially in the
-     * presence of GC cardmarking). Also, to improve thread-locality,
-     * queues are initialized after starting.
+     * This class just maintains links to its pool and WorkQueue.  The
+     * pool field is set immediately upon construction, but the
+     * workQueue field is not set until a call to registerWorker
+     * completes. This leads to a visibility race, that is tolerated
+     * by requiring that the workQueue field is only accessed by the
+     * owning thread.
      */
 
-    /**
-     * Mask for pool indices encoded as shorts
-     */
-    private static final int  SMASK  = 0xffff;
-
-    /**
-     * Capacity of work-stealing queue array upon initialization.
-     * Must be a power of two. Initial size must be at least 4, but is
-     * padded to minimize cache effects.
-     */
-    private static final int INITIAL_QUEUE_CAPACITY = 1 << 13;
-
-    /**
-     * Maximum size for queue array. Must be a power of two
-     * less than or equal to 1 << (31 - width of array entry) to
-     * ensure lack of index wraparound, but is capped at a lower
-     * value to help users trap runaway computations.
-     */
-    private static final int MAXIMUM_QUEUE_CAPACITY = 1 << 24; // 16M
-
-    /**
-     * The work-stealing queue array. Size must be a power of two.
-     * Initialized when started (as opposed to when constructed), to
-     * improve memory locality.
-     */
-    ForkJoinTask<?>[] queue;
-
-    /**
-     * The pool this thread works in. Accessed directly by ForkJoinTask.
-     */
-    final ForkJoinPool pool;
-
-    /**
-     * Index (mod queue.length) of next queue slot to push to or pop
-     * from. It is written only by owner thread, and accessed by other
-     * threads only after reading (volatile) queueBase.  Both queueTop
-     * and queueBase are allowed to wrap around on overflow, but
-     * (queueTop - queueBase) still estimates size.
-     */
-    int queueTop;
-
-    /**
-     * Index (mod queue.length) of least valid queue slot, which is
-     * always the next position to steal from if nonempty.
-     */
-    volatile int queueBase;
-
-    /**
-     * The index of most recent stealer, used as a hint to avoid
-     * traversal in method helpJoinTask. This is only a hint because a
-     * worker might have had multiple steals and this only holds one
-     * of them (usually the most current). Declared non-volatile,
-     * relying on other prevailing sync to keep reasonably current.
-     */
-    int stealHint;
-
-    /**
-     * Index of this worker in pool array. Set once by pool before
-     * running, and accessed directly by pool to locate this worker in
-     * its workers array.
-     */
-    final int poolIndex;
-
-    /**
-     * Encoded record for pool task waits. Usages are always
-     * surrounded by volatile reads/writes
-     */
-    int nextWait;
-
-    /**
-     * Complement of poolIndex, offset by count of entries of task
-     * waits. Accessed by ForkJoinPool to manage event waiters.
-     */
-    volatile int eventCount;
-
-    /**
-     * Seed for random number generator for choosing steal victims.
-     * Uses Marsaglia xorshift. Must be initialized as nonzero.
-     */
-    int seed;
-
-    /**
-     * Number of steals. Directly accessed (and reset) by pool when
-     * idle.
-     */
-    int stealCount;
-
-    /**
-     * True if this worker should or did terminate
-     */
-    volatile boolean terminate;
-
-    /**
-     * Set to true before LockSupport.park; false on return
-     */
-    volatile boolean parked;
-
-    /**
-     * True if use local fifo, not default lifo, for local polling.
-     * Shadows value from ForkJoinPool.
-     */
-    final boolean locallyFifo;
-
-    /**
-     * The task most recently stolen from another worker (or
-     * submission queue).  All uses are surrounded by enough volatile
-     * reads/writes to maintain as non-volatile.
-     */
-    ForkJoinTask<?> currentSteal;
-
-    /**
-     * The task currently being joined, set only when actively trying
-     * to help other stealers in helpJoinTask. All uses are surrounded
-     * by enough volatile reads/writes to maintain as non-volatile.
-     */
-    ForkJoinTask<?> currentJoin;
+    final ForkJoinPool pool;                // the pool this thread works in
+    final ForkJoinPool.WorkQueue workQueue; // work-stealing mechanics
 
     /**
      * Creates a ForkJoinWorkerThread operating in the given pool.
@@ -294,20 +73,12 @@
      * @throws NullPointerException if pool is null
      */
     protected ForkJoinWorkerThread(ForkJoinPool pool) {
-        super(pool.nextWorkerName());
+        // Use a placeholder until a useful name can be set in registerWorker
+        super("aForkJoinWorkerThread");
         this.pool = pool;
-        int k = pool.registerWorker(this);
-        poolIndex = k;
-        eventCount = ~k & SMASK; // clear wait count
-        locallyFifo = pool.locallyFifo;
-        Thread.UncaughtExceptionHandler ueh = pool.ueh;
-        if (ueh != null)
-            setUncaughtExceptionHandler(ueh);
-        setDaemon(true);
+        this.workQueue = pool.registerWorker(this);
     }
 
-    // Public methods
-
     /**
      * Returns the pool hosting this thread.
      *
@@ -327,28 +98,9 @@
      * @return the index number
      */
     public int getPoolIndex() {
-        return poolIndex;
+        return workQueue.poolIndex;
     }
 
-    // Randomization
-
-    /**
-     * Computes next value for random victim probes and backoffs.
-     * Scans don't require a very high quality generator, but also not
-     * a crummy one.  Marsaglia xor-shift is cheap and works well
-     * enough.  Note: This is manually inlined in FJP.scan() to avoid
-     * writes inside busy loops.
-     */
-    private int nextSeed() {
-        int r = seed;
-        r ^= r << 13;
-        r ^= r >>> 17;
-        r ^= r << 5;
-        return seed = r;
-    }
-
-    // Run State management
-
     /**
      * Initializes internal state after construction but before
      * processing any tasks. If you override this method, you must
@@ -359,9 +111,6 @@
      * processing tasks.
      */
     protected void onStart() {
-        queue = new ForkJoinTask<?>[INITIAL_QUEUE_CAPACITY];
-        int r = ForkJoinPool.workerSeedGenerator.nextInt();
-        seed = (r == 0) ? 1 : r; //  must be nonzero
     }
 
     /**
@@ -373,17 +122,6 @@
      * to an unrecoverable error, or {@code null} if completed normally
      */
     protected void onTermination(Throwable exception) {
-        try {
-            terminate = true;
-            cancelTasks();
-            pool.deregisterWorker(this, exception);
-        } catch (Throwable ex) {        // Shouldn't ever happen
-            if (exception == null)      // but if so, at least rethrown
-                exception = ex;
-        } finally {
-            if (exception != null)
-                UNSAFE.throwException(exception);
-        }
     }
 
     /**
@@ -395,604 +133,18 @@
         Throwable exception = null;
         try {
             onStart();
-            pool.work(this);
+            pool.runWorker(workQueue);
         } catch (Throwable ex) {
             exception = ex;
         } finally {
-            onTermination(exception);
-        }
-    }
-
-    /*
-     * Intrinsics-based atomic writes for queue slots. These are
-     * basically the same as methods in AtomicReferenceArray, but
-     * specialized for (1) ForkJoinTask elements (2) requirement that
-     * nullness and bounds checks have already been performed by
-     * callers and (3) effective offsets are known not to overflow
-     * from int to long (because of MAXIMUM_QUEUE_CAPACITY). We don't
-     * need corresponding version for reads: plain array reads are OK
-     * because they are protected by other volatile reads and are
-     * confirmed by CASes.
-     *
-     * Most uses don't actually call these methods, but instead
-     * contain inlined forms that enable more predictable
-     * optimization.  We don't define the version of write used in
-     * pushTask at all, but instead inline there a store-fenced array
-     * slot write.
-     *
-     * Also in most methods, as a performance (not correctness) issue,
-     * we'd like to encourage compilers not to arbitrarily postpone
-     * setting queueTop after writing slot.  Currently there is no
-     * intrinsic for arranging this, but using Unsafe putOrderedInt
-     * may be a preferable strategy on some compilers even though its
-     * main effect is a pre-, not post- fence. To simplify possible
-     * changes, the option is left in comments next to the associated
-     * assignments.
-     */
-
-    /**
-     * CASes slot i of array q from t to null. Caller must ensure q is
-     * non-null and index is in range.
-     */
-    private static final boolean casSlotNull(ForkJoinTask<?>[] q, int i,
-                                             ForkJoinTask<?> t) {
-        return UNSAFE.compareAndSwapObject(q, (i << ASHIFT) + ABASE, t, null);
-    }
-
-    /**
-     * Performs a volatile write of the given task at given slot of
-     * array q.  Caller must ensure q is non-null and index is in
-     * range. This method is used only during resets and backouts.
-     */
-    private static final void writeSlot(ForkJoinTask<?>[] q, int i,
-                                        ForkJoinTask<?> t) {
-        UNSAFE.putObjectVolatile(q, (i << ASHIFT) + ABASE, t);
-    }
-
-    // queue methods
-
-    /**
-     * Pushes a task. Call only from this thread.
-     *
-     * @param t the task. Caller must ensure non-null.
-     */
-    final void pushTask(ForkJoinTask<?> t) {
-        ForkJoinTask<?>[] q; int s, m;
-        if ((q = queue) != null) {    // ignore if queue removed
-            long u = (((s = queueTop) & (m = q.length - 1)) << ASHIFT) + ABASE;
-            UNSAFE.putOrderedObject(q, u, t);
-            queueTop = s + 1;         // or use putOrderedInt
-            if ((s -= queueBase) <= 2)
-                pool.signalWork();
-            else if (s == m)
-                growQueue();
-        }
-    }
-
-    /**
-     * Creates or doubles queue array.  Transfers elements by
-     * emulating steals (deqs) from old array and placing, oldest
-     * first, into new array.
-     */
-    private void growQueue() {
-        ForkJoinTask<?>[] oldQ = queue;
-        int size = oldQ != null ? oldQ.length << 1 : INITIAL_QUEUE_CAPACITY;
-        if (size > MAXIMUM_QUEUE_CAPACITY)
-            throw new RejectedExecutionException("Queue capacity exceeded");
-        if (size < INITIAL_QUEUE_CAPACITY)
-            size = INITIAL_QUEUE_CAPACITY;
-        ForkJoinTask<?>[] q = queue = new ForkJoinTask<?>[size];
-        int mask = size - 1;
-        int top = queueTop;
-        int oldMask;
-        if (oldQ != null && (oldMask = oldQ.length - 1) >= 0) {
-            for (int b = queueBase; b != top; ++b) {
-                long u = ((b & oldMask) << ASHIFT) + ABASE;
-                Object x = UNSAFE.getObjectVolatile(oldQ, u);
-                if (x != null && UNSAFE.compareAndSwapObject(oldQ, u, x, null))
-                    UNSAFE.putObjectVolatile
-                        (q, ((b & mask) << ASHIFT) + ABASE, x);
+            try {
+                onTermination(exception);
+            } catch (Throwable ex) {
+                if (exception == null)
+                    exception = ex;
+            } finally {
+                pool.deregisterWorker(this, exception);
             }
         }
     }
-
-    /**
-     * Tries to take a task from the base of the queue, failing if
-     * empty or contended. Note: Specializations of this code appear
-     * in locallyDeqTask and elsewhere.
-     *
-     * @return a task, or null if none or contended
-     */
-    final ForkJoinTask<?> deqTask() {
-        ForkJoinTask<?> t; ForkJoinTask<?>[] q; int b, i;
-        if (queueTop != (b = queueBase) &&
-            (q = queue) != null && // must read q after b
-            (i = (q.length - 1) & b) >= 0 &&
-            (t = q[i]) != null && queueBase == b &&
-            UNSAFE.compareAndSwapObject(q, (i << ASHIFT) + ABASE, t, null)) {
-            queueBase = b + 1;
-            return t;
-        }
-        return null;
-    }
-
-    /**
-     * Tries to take a task from the base of own queue.  Called only
-     * by this thread.
-     *
-     * @return a task, or null if none
-     */
-    final ForkJoinTask<?> locallyDeqTask() {
-        ForkJoinTask<?> t; int m, b, i;
-        ForkJoinTask<?>[] q = queue;
-        if (q != null && (m = q.length - 1) >= 0) {
-            while (queueTop != (b = queueBase)) {
-                if ((t = q[i = m & b]) != null &&
-                    queueBase == b &&
-                    UNSAFE.compareAndSwapObject(q, (i << ASHIFT) + ABASE,
-                                                t, null)) {
-                    queueBase = b + 1;
-                    return t;
-                }
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Returns a popped task, or null if empty.
-     * Called only by this thread.
-     */
-    private ForkJoinTask<?> popTask() {
-        int m;
-        ForkJoinTask<?>[] q = queue;
-        if (q != null && (m = q.length - 1) >= 0) {
-            for (int s; (s = queueTop) != queueBase;) {
-                int i = m & --s;
-                long u = (i << ASHIFT) + ABASE; // raw offset
-                ForkJoinTask<?> t = q[i];
-                if (t == null)   // lost to stealer
-                    break;
-                if (UNSAFE.compareAndSwapObject(q, u, t, null)) {
-                    queueTop = s; // or putOrderedInt
-                    return t;
-                }
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Specialized version of popTask to pop only if topmost element
-     * is the given task. Called only by this thread.
-     *
-     * @param t the task. Caller must ensure non-null.
-     */
-    final boolean unpushTask(ForkJoinTask<?> t) {
-        ForkJoinTask<?>[] q;
-        int s;
-        if ((q = queue) != null && (s = queueTop) != queueBase &&
-            UNSAFE.compareAndSwapObject
-            (q, (((q.length - 1) & --s) << ASHIFT) + ABASE, t, null)) {
-            queueTop = s; // or putOrderedInt
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Returns next task, or null if empty or contended.
-     */
-    final ForkJoinTask<?> peekTask() {
-        int m;
-        ForkJoinTask<?>[] q = queue;
-        if (q == null || (m = q.length - 1) < 0)
-            return null;
-        int i = locallyFifo ? queueBase : (queueTop - 1);
-        return q[i & m];
-    }
-
-    // Support methods for ForkJoinPool
-
-    /**
-     * Runs the given task, plus any local tasks until queue is empty
-     */
-    final void execTask(ForkJoinTask<?> t) {
-        currentSteal = t;
-        for (;;) {
-            if (t != null)
-                t.doExec();
-            if (queueTop == queueBase)
-                break;
-            t = locallyFifo ? locallyDeqTask() : popTask();
-        }
-        ++stealCount;
-        currentSteal = null;
-    }
-
-    /**
-     * Removes and cancels all tasks in queue.  Can be called from any
-     * thread.
-     */
-    final void cancelTasks() {
-        ForkJoinTask<?> cj = currentJoin; // try to cancel ongoing tasks
-        if (cj != null && cj.status >= 0)
-            cj.cancelIgnoringExceptions();
-        ForkJoinTask<?> cs = currentSteal;
-        if (cs != null && cs.status >= 0)
-            cs.cancelIgnoringExceptions();
-        while (queueBase != queueTop) {
-            ForkJoinTask<?> t = deqTask();
-            if (t != null)
-                t.cancelIgnoringExceptions();
-        }
-    }
-
-    /**
-     * Drains tasks to given collection c.
-     *
-     * @return the number of tasks drained
-     */
-    final int drainTasksTo(Collection<? super ForkJoinTask<?>> c) {
-        int n = 0;
-        while (queueBase != queueTop) {
-            ForkJoinTask<?> t = deqTask();
-            if (t != null) {
-                c.add(t);
-                ++n;
-            }
-        }
-        return n;
-    }
-
-    // Support methods for ForkJoinTask
-
-    /**
-     * Returns an estimate of the number of tasks in the queue.
-     */
-    final int getQueueSize() {
-        return queueTop - queueBase;
-    }
-
-    /**
-     * Gets and removes a local task.
-     *
-     * @return a task, if available
-     */
-    final ForkJoinTask<?> pollLocalTask() {
-        return locallyFifo ? locallyDeqTask() : popTask();
-    }
-
-    /**
-     * Gets and removes a local or stolen task.
-     *
-     * @return a task, if available
-     */
-    final ForkJoinTask<?> pollTask() {
-        ForkJoinWorkerThread[] ws;
-        ForkJoinTask<?> t = pollLocalTask();
-        if (t != null || (ws = pool.workers) == null)
-            return t;
-        int n = ws.length; // cheap version of FJP.scan
-        int steps = n << 1;
-        int r = nextSeed();
-        int i = 0;
-        while (i < steps) {
-            ForkJoinWorkerThread w = ws[(i++ + r) & (n - 1)];
-            if (w != null && w.queueBase != w.queueTop && w.queue != null) {
-                if ((t = w.deqTask()) != null)
-                    return t;
-                i = 0;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * The maximum stolen->joining link depth allowed in helpJoinTask,
-     * as well as the maximum number of retries (allowing on average
-     * one staleness retry per level) per attempt to instead try
-     * compensation.  Depths for legitimate chains are unbounded, but
-     * we use a fixed constant to avoid (otherwise unchecked) cycles
-     * and bound staleness of traversal parameters at the expense of
-     * sometimes blocking when we could be helping.
-     */
-    private static final int MAX_HELP = 16;
-
-    /**
-     * Possibly runs some tasks and/or blocks, until joinMe is done.
-     *
-     * @param joinMe the task to join
-     * @return completion status on exit
-     */
-    final int joinTask(ForkJoinTask<?> joinMe) {
-        ForkJoinTask<?> prevJoin = currentJoin;
-        currentJoin = joinMe;
-        for (int s, retries = MAX_HELP;;) {
-            if ((s = joinMe.status) < 0) {
-                currentJoin = prevJoin;
-                return s;
-            }
-            if (retries > 0) {
-                if (queueTop != queueBase) {
-                    if (!localHelpJoinTask(joinMe))
-                        retries = 0;           // cannot help
-                }
-                else if (retries == MAX_HELP >>> 1) {
-                    --retries;                 // check uncommon case
-                    if (tryDeqAndExec(joinMe) >= 0)
-                        Thread.yield();        // for politeness
-                }
-                else
-                    retries = helpJoinTask(joinMe) ? MAX_HELP : retries - 1;
-            }
-            else {
-                retries = MAX_HELP;           // restart if not done
-                pool.tryAwaitJoin(joinMe);
-            }
-        }
-    }
-
-    /**
-     * If present, pops and executes the given task, or any other
-     * cancelled task
-     *
-     * @return false if any other non-cancelled task exists in local queue
-     */
-    private boolean localHelpJoinTask(ForkJoinTask<?> joinMe) {
-        int s, i; ForkJoinTask<?>[] q; ForkJoinTask<?> t;
-        if ((s = queueTop) != queueBase && (q = queue) != null &&
-            (i = (q.length - 1) & --s) >= 0 &&
-            (t = q[i]) != null) {
-            if (t != joinMe && t.status >= 0)
-                return false;
-            if (UNSAFE.compareAndSwapObject
-                (q, (i << ASHIFT) + ABASE, t, null)) {
-                queueTop = s;           // or putOrderedInt
-                t.doExec();
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Tries to locate and execute tasks for a stealer of the given
-     * task, or in turn one of its stealers, Traces
-     * currentSteal->currentJoin links looking for a thread working on
-     * a descendant of the given task and with a non-empty queue to
-     * steal back and execute tasks from.  The implementation is very
-     * branchy to cope with potential inconsistencies or loops
-     * encountering chains that are stale, unknown, or of length
-     * greater than MAX_HELP links.  All of these cases are dealt with
-     * by just retrying by caller.
-     *
-     * @param joinMe the task to join
-     * @param canSteal true if local queue is empty
-     * @return true if ran a task
-     */
-    private boolean helpJoinTask(ForkJoinTask<?> joinMe) {
-        boolean helped = false;
-        int m = pool.scanGuard & SMASK;
-        ForkJoinWorkerThread[] ws = pool.workers;
-        if (ws != null && ws.length > m && joinMe.status >= 0) {
-            int levels = MAX_HELP;              // remaining chain length
-            ForkJoinTask<?> task = joinMe;      // base of chain
-            outer:for (ForkJoinWorkerThread thread = this;;) {
-                // Try to find v, the stealer of task, by first using hint
-                ForkJoinWorkerThread v = ws[thread.stealHint & m];
-                if (v == null || v.currentSteal != task) {
-                    for (int j = 0; ;) {        // search array
-                        if ((v = ws[j]) != null && v.currentSteal == task) {
-                            thread.stealHint = j;
-                            break;              // save hint for next time
-                        }
-                        if (++j > m)
-                            break outer;        // can't find stealer
-                    }
-                }
-                // Try to help v, using specialized form of deqTask
-                for (;;) {
-                    ForkJoinTask<?>[] q; int b, i;
-                    if (joinMe.status < 0)
-                        break outer;
-                    if ((b = v.queueBase) == v.queueTop ||
-                        (q = v.queue) == null ||
-                        (i = (q.length-1) & b) < 0)
-                        break;                  // empty
-                    long u = (i << ASHIFT) + ABASE;
-                    ForkJoinTask<?> t = q[i];
-                    if (task.status < 0)
-                        break outer;            // stale
-                    if (t != null && v.queueBase == b &&
-                        UNSAFE.compareAndSwapObject(q, u, t, null)) {
-                        v.queueBase = b + 1;
-                        v.stealHint = poolIndex;
-                        ForkJoinTask<?> ps = currentSteal;
-                        currentSteal = t;
-                        t.doExec();
-                        currentSteal = ps;
-                        helped = true;
-                    }
-                }
-                // Try to descend to find v's stealer
-                ForkJoinTask<?> next = v.currentJoin;
-                if (--levels > 0 && task.status >= 0 &&
-                    next != null && next != task) {
-                    task = next;
-                    thread = v;
-                }
-                else
-                    break;  // max levels, stale, dead-end, or cyclic
-            }
-        }
-        return helped;
-    }
-
-    /**
-     * Performs an uncommon case for joinTask: If task t is at base of
-     * some workers queue, steals and executes it.
-     *
-     * @param t the task
-     * @return t's status
-     */
-    private int tryDeqAndExec(ForkJoinTask<?> t) {
-        int m = pool.scanGuard & SMASK;
-        ForkJoinWorkerThread[] ws = pool.workers;
-        if (ws != null && ws.length > m && t.status >= 0) {
-            for (int j = 0; j <= m; ++j) {
-                ForkJoinTask<?>[] q; int b, i;
-                ForkJoinWorkerThread v = ws[j];
-                if (v != null &&
-                    (b = v.queueBase) != v.queueTop &&
-                    (q = v.queue) != null &&
-                    (i = (q.length - 1) & b) >= 0 &&
-                    q[i] == t) {
-                    long u = (i << ASHIFT) + ABASE;
-                    if (v.queueBase == b &&
-                        UNSAFE.compareAndSwapObject(q, u, t, null)) {
-                        v.queueBase = b + 1;
-                        v.stealHint = poolIndex;
-                        ForkJoinTask<?> ps = currentSteal;
-                        currentSteal = t;
-                        t.doExec();
-                        currentSteal = ps;
-                    }
-                    break;
-                }
-            }
-        }
-        return t.status;
-    }
-
-    /**
-     * Implements ForkJoinTask.getSurplusQueuedTaskCount().  Returns
-     * an estimate of the number of tasks, offset by a function of
-     * number of idle workers.
-     *
-     * This method provides a cheap heuristic guide for task
-     * partitioning when programmers, frameworks, tools, or languages
-     * have little or no idea about task granularity.  In essence by
-     * offering this method, we ask users only about tradeoffs in
-     * overhead vs expected throughput and its variance, rather than
-     * how finely to partition tasks.
-     *
-     * In a steady state strict (tree-structured) computation, each
-     * thread makes available for stealing enough tasks for other
-     * threads to remain active. Inductively, if all threads play by
-     * the same rules, each thread should make available only a
-     * constant number of tasks.
-     *
-     * The minimum useful constant is just 1. But using a value of 1
-     * would require immediate replenishment upon each steal to
-     * maintain enough tasks, which is infeasible.  Further,
-     * partitionings/granularities of offered tasks should minimize
-     * steal rates, which in general means that threads nearer the top
-     * of computation tree should generate more than those nearer the
-     * bottom. In perfect steady state, each thread is at
-     * approximately the same level of computation tree. However,
-     * producing extra tasks amortizes the uncertainty of progress and
-     * diffusion assumptions.
-     *
-     * So, users will want to use values larger, but not much larger
-     * than 1 to both smooth over transient shortages and hedge
-     * against uneven progress; as traded off against the cost of
-     * extra task overhead. We leave the user to pick a threshold
-     * value to compare with the results of this call to guide
-     * decisions, but recommend values such as 3.
-     *
-     * When all threads are active, it is on average OK to estimate
-     * surplus strictly locally. In steady-state, if one thread is
-     * maintaining say 2 surplus tasks, then so are others. So we can
-     * just use estimated queue length (although note that (queueTop -
-     * queueBase) can be an overestimate because of stealers lagging
-     * increments of queueBase).  However, this strategy alone leads
-     * to serious mis-estimates in some non-steady-state conditions
-     * (ramp-up, ramp-down, other stalls). We can detect many of these
-     * by further considering the number of "idle" threads, that are
-     * known to have zero queued tasks, so compensate by a factor of
-     * (#idle/#active) threads.
-     */
-    final int getEstimatedSurplusTaskCount() {
-        return queueTop - queueBase - pool.idlePerActive();
-    }
-
-    /**
-     * Runs tasks until {@code pool.isQuiescent()}. We piggyback on
-     * pool's active count ctl maintenance, but rather than blocking
-     * when tasks cannot be found, we rescan until all others cannot
-     * find tasks either. The bracketing by pool quiescerCounts
-     * updates suppresses pool auto-shutdown mechanics that could
-     * otherwise prematurely terminate the pool because all threads
-     * appear to be inactive.
-     */
-    final void helpQuiescePool() {
-        boolean active = true;
-        ForkJoinTask<?> ps = currentSteal; // to restore below
-        ForkJoinPool p = pool;
-        p.addQuiescerCount(1);
-        for (;;) {
-            ForkJoinWorkerThread[] ws = p.workers;
-            ForkJoinWorkerThread v = null;
-            int n;
-            if (queueTop != queueBase)
-                v = this;
-            else if (ws != null && (n = ws.length) > 1) {
-                ForkJoinWorkerThread w;
-                int r = nextSeed(); // cheap version of FJP.scan
-                int steps = n << 1;
-                for (int i = 0; i < steps; ++i) {
-                    if ((w = ws[(i + r) & (n - 1)]) != null &&
-                        w.queueBase != w.queueTop) {
-                        v = w;
-                        break;
-                    }
-                }
-            }
-            if (v != null) {
-                ForkJoinTask<?> t;
-                if (!active) {
-                    active = true;
-                    p.addActiveCount(1);
-                }
-                if ((t = (v != this) ? v.deqTask() :
-                     locallyFifo ? locallyDeqTask() : popTask()) != null) {
-                    currentSteal = t;
-                    t.doExec();
-                    currentSteal = ps;
-                }
-            }
-            else {
-                if (active) {
-                    active = false;
-                    p.addActiveCount(-1);
-                }
-                if (p.isQuiescent()) {
-                    p.addActiveCount(1);
-                    p.addQuiescerCount(-1);
-                    break;
-                }
-            }
-        }
-    }
-
-    // Unsafe mechanics
-    private static final sun.misc.Unsafe UNSAFE;
-    private static final long ABASE;
-    private static final int ASHIFT;
-
-    static {
-        int s;
-        try {
-            UNSAFE = sun.misc.Unsafe.getUnsafe();
-            Class<?> a = ForkJoinTask[].class;
-            ABASE = UNSAFE.arrayBaseOffset(a);
-            s = UNSAFE.arrayIndexScale(a);
-        } catch (Exception e) {
-            throw new Error(e);
-        }
-        if ((s & (s-1)) != 0)
-            throw new Error("data type scale not a power of two");
-        ASHIFT = 31 - Integer.numberOfLeadingZeros(s);
-    }
-
 }
--- a/jdk/src/share/classes/javax/management/MBeanFeatureInfo.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/javax/management/MBeanFeatureInfo.java	Wed Jul 05 18:34:47 2017 +0200
@@ -239,12 +239,10 @@
         case 1:
             final String[] names = (String[])in.readObject();
 
-            if (names.length == 0) {
-                descriptor = ImmutableDescriptor.EMPTY_DESCRIPTOR;
-            } else {
-                final Object[] values = (Object[])in.readObject();
-                descriptor = new ImmutableDescriptor(names, values);
-            }
+            final Object[] values = (Object[]) in.readObject();
+            descriptor = (names.length == 0) ?
+                ImmutableDescriptor.EMPTY_DESCRIPTOR :
+                new ImmutableDescriptor(names, values);
 
             break;
         case 0:
--- a/jdk/src/share/classes/javax/management/MBeanInfo.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/javax/management/MBeanInfo.java	Wed Jul 05 18:34:47 2017 +0200
@@ -704,12 +704,10 @@
         case 1:
             final String[] names = (String[])in.readObject();
 
-            if (names.length == 0) {
-                descriptor = ImmutableDescriptor.EMPTY_DESCRIPTOR;
-            } else {
-                final Object[] values = (Object[])in.readObject();
-                descriptor = new ImmutableDescriptor(names, values);
-            }
+            final Object[] values = (Object[]) in.readObject();
+            descriptor = (names.length == 0) ?
+                ImmutableDescriptor.EMPTY_DESCRIPTOR :
+                new ImmutableDescriptor(names, values);
 
             break;
         case 0:
--- a/jdk/src/share/classes/javax/management/remote/JMXConnectorFactory.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/javax/management/remote/JMXConnectorFactory.java	Wed Jul 05 18:34:47 2017 +0200
@@ -137,8 +137,10 @@
  * JAR conventions for service providers</a>, where the service
  * interface is <code>JMXConnectorProvider</code>.</p>
  *
- * <p>Every implementation must support the RMI connector protocols,
- * specified with the string <code>rmi</code> or
+ * <p>Every implementation must support the RMI connector protocol with
+ * the default RMI transport, specified with string <code>rmi</code>.
+ * An implementation may optionally support the RMI connector protocol
+ * with the RMI/IIOP transport, specified with the string
  * <code>iiop</code>.</p>
  *
  * <p>Once a provider is found, the result of the
--- a/jdk/src/share/classes/javax/management/remote/JMXConnectorServerFactory.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/javax/management/remote/JMXConnectorServerFactory.java	Wed Jul 05 18:34:47 2017 +0200
@@ -129,8 +129,10 @@
  * JAR conventions for service providers</a>, where the service
  * interface is <code>JMXConnectorServerProvider</code>.</p>
  *
- * <p>Every implementation must support the RMI connector protocols,
- * specified with the string <code>rmi</code> or
+ * <p>Every implementation must support the RMI connector protocol with
+ * the default RMI transport, specified with string <code>rmi</code>.
+ * An implementation may optionally support the RMI connector protocol
+ * with the RMI/IIOP transport, specified with the string
  * <code>iiop</code>.</p>
  *
  * <p>Once a provider is found, the result of the
--- a/jdk/src/share/classes/javax/management/remote/rmi/RMIConnector.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/javax/management/remote/rmi/RMIConnector.java	Wed Jul 05 18:34:47 2017 +0200
@@ -238,10 +238,21 @@
     //--------------------------------------------------------------------
     // implements JMXConnector interface
     //--------------------------------------------------------------------
+
+    /**
+     * @throws IOException if the connection could not be made because of a
+     *   communication problem, or in the case of the {@code iiop} protocol,
+     *   that RMI/IIOP is not supported
+     */
     public void connect() throws IOException {
         connect(null);
     }
 
+    /**
+     * @throws IOException if the connection could not be made because of a
+     *   communication problem, or in the case of the {@code iiop} protocol,
+     *   that RMI/IIOP is not supported
+     */
     public synchronized void connect(Map<String,?> environment)
     throws IOException {
         final boolean tracing = logger.traceOn();
--- a/jdk/src/share/classes/javax/management/remote/rmi/RMIConnectorServer.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/javax/management/remote/rmi/RMIConnectorServer.java	Wed Jul 05 18:34:47 2017 +0200
@@ -337,7 +337,8 @@
      * @exception IllegalStateException if the connector server has
      * not been attached to an MBean server.
      * @exception IOException if the connector server cannot be
-     * started.
+     * started, or in the case of the {@code iiop} protocol, that
+     * RMI/IIOP is not supported.
      */
     public synchronized void start() throws IOException {
         final boolean tracing = logger.traceOn();
--- a/jdk/src/share/classes/javax/management/remote/rmi/package.html	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/javax/management/remote/rmi/package.html	Wed Jul 05 18:34:47 2017 +0200
@@ -36,8 +36,8 @@
       that different implementations of the RMI connector can
       interoperate.</p>
 
-    <p>The RMI connector supports both the JRMP and the IIOP transports
-      for RMI.</p>
+    <p>The RMI connector supports the JRMP transport for RMI, and
+      optionally the IIOP transport.</p>
 
     <p>Like most connectors in the JMX Remote API, an RMI connector
       usually has an address, which
--- a/jdk/src/share/classes/javax/security/auth/kerberos/package.html	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/javax/security/auth/kerberos/package.html	Wed Jul 05 18:34:47 2017 +0200
@@ -43,10 +43,15 @@
 
     You can provide the name of your default realm and Key Distribution
     Center (KDC) host for that realm using the system properties
-    java.security.krb5.realm and java.security.krb5.kdc. Alternatively, you 
-    can provide an MIT style configuration file called krb5.conf in
-    &lt;java-home&gt;/lib/security. If you place this file elsewhere, you can
-    indicate that location via the system property java.security.krb5.conf.<p>
+    {@code java.security.krb5.realm} and {@code java.security.krb5.kdc}.
+    Both properties must be set.
+    Alternatively, the {@code java.security.krb5.conf} system property can
+    be set to the location of an MIT style {@code krb5.conf} configuration
+    file. If none of these system properties are set, the {@code krb5.conf}
+    file is searched for in an implementation-specific manner. Typically,
+    an implementation will first look for a {@code krb5.conf} file in
+    {@code <java-home>/lib/security} and failing that, in an OS-specific
+    location.<p>
 <!--
 <h2>Package Specification</h2>
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/jdk/internal/org/xml/sax/Attributes.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// Attributes.java - attribute list with Namespace support
+// http://www.saxproject.org
+// Written by David Megginson
+// NO WARRANTY!  This class is in the public domain.
+// $Id: Attributes.java,v 1.2 2004/11/03 22:44:51 jsuttor Exp $
+
+package jdk.internal.org.xml.sax;
+
+
+/**
+ * Interface for a list of XML attributes.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>This interface allows access to a list of attributes in
+ * three different ways:</p>
+ *
+ * <ol>
+ * <li>by attribute index;</li>
+ * <li>by Namespace-qualified name; or</li>
+ * <li>by qualified (prefixed) name.</li>
+ * </ol>
+ *
+ * <p>The list will not contain attributes that were declared
+ * #IMPLIED but not specified in the start tag.  It will also not
+ * contain attributes used as Namespace declarations (xmlns*) unless
+ * the <code>http://xml.org/sax/features/namespace-prefixes</code>
+ * feature is set to <var>true</var> (it is <var>false</var> by
+ * default).
+ * Because SAX2 conforms to the original "Namespaces in XML"
+ * recommendation, it normally does not
+ * give namespace declaration attributes a namespace URI.
+ * </p>
+ *
+ * <p>Some SAX2 parsers may support using an optional feature flag
+ * (<code>http://xml.org/sax/features/xmlns-uris</code>) to request
+ * that those attributes be given URIs, conforming to a later
+ * backwards-incompatible revision of that recommendation.  (The
+ * attribute's "local name" will be the prefix, or "xmlns" when
+ * defining a default element namespace.)  For portability, handler
+ * code should always resolve that conflict, rather than requiring
+ * parsers that can change the setting of that feature flag.  </p>
+ *
+ * <p>If the namespace-prefixes feature (see above) is
+ * <var>false</var>, access by qualified name may not be available; if
+ * the <code>http://xml.org/sax/features/namespaces</code> feature is
+ * <var>false</var>, access by Namespace-qualified names may not be
+ * available.</p>
+ *
+ * <p>This interface replaces the now-deprecated SAX1 {@link
+ * org.xml.sax.AttributeList AttributeList} interface, which does not
+ * contain Namespace support.  In addition to Namespace support, it
+ * adds the <var>getIndex</var> methods (below).</p>
+ *
+ * <p>The order of attributes in the list is unspecified, and will
+ * vary from implementation to implementation.</p>
+ *
+ * @since SAX 2.0
+ * @author David Megginson
+ * @see org.xml.sax.helpers.AttributesImpl
+ * @see org.xml.sax.ext.DeclHandler#attributeDecl
+ */
+public interface Attributes
+{
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Indexed access.
+    ////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Return the number of attributes in the list.
+     *
+     * <p>Once you know the number of attributes, you can iterate
+     * through the list.</p>
+     *
+     * @return The number of attributes in the list.
+     * @see #getURI(int)
+     * @see #getLocalName(int)
+     * @see #getQName(int)
+     * @see #getType(int)
+     * @see #getValue(int)
+     */
+    public abstract int getLength ();
+
+
+    /**
+     * Look up an attribute's Namespace URI by index.
+     *
+     * @param index The attribute index (zero-based).
+     * @return The Namespace URI, or the empty string if none
+     *         is available, or null if the index is out of
+     *         range.
+     * @see #getLength
+     */
+    public abstract String getURI (int index);
+
+
+    /**
+     * Look up an attribute's local name by index.
+     *
+     * @param index The attribute index (zero-based).
+     * @return The local name, or the empty string if Namespace
+     *         processing is not being performed, or null
+     *         if the index is out of range.
+     * @see #getLength
+     */
+    public abstract String getLocalName (int index);
+
+
+    /**
+     * Look up an attribute's XML qualified (prefixed) name by index.
+     *
+     * @param index The attribute index (zero-based).
+     * @return The XML qualified name, or the empty string
+     *         if none is available, or null if the index
+     *         is out of range.
+     * @see #getLength
+     */
+    public abstract String getQName (int index);
+
+
+    /**
+     * Look up an attribute's type by index.
+     *
+     * <p>The attribute type is one of the strings "CDATA", "ID",
+     * "IDREF", "IDREFS", "NMTOKEN", "NMTOKENS", "ENTITY", "ENTITIES",
+     * or "NOTATION" (always in upper case).</p>
+     *
+     * <p>If the parser has not read a declaration for the attribute,
+     * or if the parser does not report attribute types, then it must
+     * return the value "CDATA" as stated in the XML 1.0 Recommendation
+     * (clause 3.3.3, "Attribute-Value Normalization").</p>
+     *
+     * <p>For an enumerated attribute that is not a notation, the
+     * parser will report the type as "NMTOKEN".</p>
+     *
+     * @param index The attribute index (zero-based).
+     * @return The attribute's type as a string, or null if the
+     *         index is out of range.
+     * @see #getLength
+     */
+    public abstract String getType (int index);
+
+
+    /**
+     * Look up an attribute's value by index.
+     *
+     * <p>If the attribute value is a list of tokens (IDREFS,
+     * ENTITIES, or NMTOKENS), the tokens will be concatenated
+     * into a single string with each token separated by a
+     * single space.</p>
+     *
+     * @param index The attribute index (zero-based).
+     * @return The attribute's value as a string, or null if the
+     *         index is out of range.
+     * @see #getLength
+     */
+    public abstract String getValue (int index);
+
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Name-based query.
+    ////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Look up the index of an attribute by Namespace name.
+     *
+     * @param uri The Namespace URI, or the empty string if
+     *        the name has no Namespace URI.
+     * @param localName The attribute's local name.
+     * @return The index of the attribute, or -1 if it does not
+     *         appear in the list.
+     */
+    public int getIndex (String uri, String localName);
+
+
+    /**
+     * Look up the index of an attribute by XML qualified (prefixed) name.
+     *
+     * @param qName The qualified (prefixed) name.
+     * @return The index of the attribute, or -1 if it does not
+     *         appear in the list.
+     */
+    public int getIndex (String qName);
+
+
+    /**
+     * Look up an attribute's type by Namespace name.
+     *
+     * <p>See {@link #getType(int) getType(int)} for a description
+     * of the possible types.</p>
+     *
+     * @param uri The Namespace URI, or the empty String if the
+     *        name has no Namespace URI.
+     * @param localName The local name of the attribute.
+     * @return The attribute type as a string, or null if the
+     *         attribute is not in the list or if Namespace
+     *         processing is not being performed.
+     */
+    public abstract String getType (String uri, String localName);
+
+
+    /**
+     * Look up an attribute's type by XML qualified (prefixed) name.
+     *
+     * <p>See {@link #getType(int) getType(int)} for a description
+     * of the possible types.</p>
+     *
+     * @param qName The XML qualified name.
+     * @return The attribute type as a string, or null if the
+     *         attribute is not in the list or if qualified names
+     *         are not available.
+     */
+    public abstract String getType (String qName);
+
+
+    /**
+     * Look up an attribute's value by Namespace name.
+     *
+     * <p>See {@link #getValue(int) getValue(int)} for a description
+     * of the possible values.</p>
+     *
+     * @param uri The Namespace URI, or the empty String if the
+     *        name has no Namespace URI.
+     * @param localName The local name of the attribute.
+     * @return The attribute value as a string, or null if the
+     *         attribute is not in the list.
+     */
+    public abstract String getValue (String uri, String localName);
+
+
+    /**
+     * Look up an attribute's value by XML qualified (prefixed) name.
+     *
+     * <p>See {@link #getValue(int) getValue(int)} for a description
+     * of the possible values.</p>
+     *
+     * @param qName The XML qualified name.
+     * @return The attribute value as a string, or null if the
+     *         attribute is not in the list or if qualified names
+     *         are not available.
+     */
+    public abstract String getValue (String qName);
+
+}
+
+// end of Attributes.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/jdk/internal/org/xml/sax/ContentHandler.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,443 @@
+/*
+ * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// ContentHandler.java - handle main document content.
+// http://www.saxproject.org
+// Written by David Megginson
+// NO WARRANTY!  This class is in the public domain.
+// $Id: ContentHandler.java,v 1.2 2004/11/03 22:44:51 jsuttor Exp $
+
+package jdk.internal.org.xml.sax;
+
+
+/**
+ * Receive notification of the logical content of a document.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>This is the main interface that most SAX applications
+ * implement: if the application needs to be informed of basic parsing
+ * events, it implements this interface and registers an instance with
+ * the SAX parser using the {@link org.xml.sax.XMLReader#setContentHandler
+ * setContentHandler} method.  The parser uses the instance to report
+ * basic document-related events like the start and end of elements
+ * and character data.</p>
+ *
+ * <p>The order of events in this interface is very important, and
+ * mirrors the order of information in the document itself.  For
+ * example, all of an element's content (character data, processing
+ * instructions, and/or subelements) will appear, in order, between
+ * the startElement event and the corresponding endElement event.</p>
+ *
+ * <p>This interface is similar to the now-deprecated SAX 1.0
+ * DocumentHandler interface, but it adds support for Namespaces
+ * and for reporting skipped entities (in non-validating XML
+ * processors).</p>
+ *
+ * <p>Implementors should note that there is also a
+ * <code>ContentHandler</code> class in the <code>java.net</code>
+ * package; that means that it's probably a bad idea to do</p>
+ *
+ * <pre>import java.net.*;
+ * import org.xml.sax.*;
+ * </pre>
+ *
+ * <p>In fact, "import ...*" is usually a sign of sloppy programming
+ * anyway, so the user should consider this a feature rather than a
+ * bug.</p>
+ *
+ * @since SAX 2.0
+ * @author David Megginson
+ * @see org.xml.sax.XMLReader
+ * @see org.xml.sax.DTDHandler
+ * @see org.xml.sax.ErrorHandler
+ */
+public interface ContentHandler
+{
+
+    /**
+     * Receive an object for locating the origin of SAX document events.
+     *
+     * <p>SAX parsers are strongly encouraged (though not absolutely
+     * required) to supply a locator: if it does so, it must supply
+     * the locator to the application by invoking this method before
+     * invoking any of the other methods in the ContentHandler
+     * interface.</p>
+     *
+     * <p>The locator allows the application to determine the end
+     * position of any document-related event, even if the parser is
+     * not reporting an error.  Typically, the application will
+     * use this information for reporting its own errors (such as
+     * character content that does not match an application's
+     * business rules).  The information returned by the locator
+     * is probably not sufficient for use with a search engine.</p>
+     *
+     * <p>Note that the locator will return correct information only
+     * during the invocation SAX event callbacks after
+     * {@link #startDocument startDocument} returns and before
+     * {@link #endDocument endDocument} is called.  The
+     * application should not attempt to use it at any other time.</p>
+     *
+     * @param locator an object that can return the location of
+     *                any SAX document event
+     * @see org.xml.sax.Locator
+     */
+    public void setDocumentLocator (Locator locator);
+
+
+    /**
+     * Receive notification of the beginning of a document.
+     *
+     * <p>The SAX parser will invoke this method only once, before any
+     * other event callbacks (except for {@link #setDocumentLocator
+     * setDocumentLocator}).</p>
+     *
+     * @throws org.xml.sax.SAXException any SAX exception, possibly
+     *            wrapping another exception
+     * @see #endDocument
+     */
+    public void startDocument ()
+        throws SAXException;
+
+
+    /**
+     * Receive notification of the end of a document.
+     *
+     * <p><strong>There is an apparent contradiction between the
+     * documentation for this method and the documentation for {@link
+     * org.xml.sax.ErrorHandler#fatalError}.  Until this ambiguity is
+     * resolved in a future major release, clients should make no
+     * assumptions about whether endDocument() will or will not be
+     * invoked when the parser has reported a fatalError() or thrown
+     * an exception.</strong></p>
+     *
+     * <p>The SAX parser will invoke this method only once, and it will
+     * be the last method invoked during the parse.  The parser shall
+     * not invoke this method until it has either abandoned parsing
+     * (because of an unrecoverable error) or reached the end of
+     * input.</p>
+     *
+     * @throws org.xml.sax.SAXException any SAX exception, possibly
+     *            wrapping another exception
+     * @see #startDocument
+     */
+    public void endDocument()
+        throws SAXException;
+
+
+    /**
+     * Begin the scope of a prefix-URI Namespace mapping.
+     *
+     * <p>The information from this event is not necessary for
+     * normal Namespace processing: the SAX XML reader will
+     * automatically replace prefixes for element and attribute
+     * names when the <code>http://xml.org/sax/features/namespaces</code>
+     * feature is <var>true</var> (the default).</p>
+     *
+     * <p>There are cases, however, when applications need to
+     * use prefixes in character data or in attribute values,
+     * where they cannot safely be expanded automatically; the
+     * start/endPrefixMapping event supplies the information
+     * to the application to expand prefixes in those contexts
+     * itself, if necessary.</p>
+     *
+     * <p>Note that start/endPrefixMapping events are not
+     * guaranteed to be properly nested relative to each other:
+     * all startPrefixMapping events will occur immediately before the
+     * corresponding {@link #startElement startElement} event,
+     * and all {@link #endPrefixMapping endPrefixMapping}
+     * events will occur immediately after the corresponding
+     * {@link #endElement endElement} event,
+     * but their order is not otherwise
+     * guaranteed.</p>
+     *
+     * <p>There should never be start/endPrefixMapping events for the
+     * "xml" prefix, since it is predeclared and immutable.</p>
+     *
+     * @param prefix the Namespace prefix being declared.
+     *  An empty string is used for the default element namespace,
+     *  which has no prefix.
+     * @param uri the Namespace URI the prefix is mapped to
+     * @throws org.xml.sax.SAXException the client may throw
+     *            an exception during processing
+     * @see #endPrefixMapping
+     * @see #startElement
+     */
+    public void startPrefixMapping (String prefix, String uri)
+        throws SAXException;
+
+
+    /**
+     * End the scope of a prefix-URI mapping.
+     *
+     * <p>See {@link #startPrefixMapping startPrefixMapping} for
+     * details.  These events will always occur immediately after the
+     * corresponding {@link #endElement endElement} event, but the order of
+     * {@link #endPrefixMapping endPrefixMapping} events is not otherwise
+     * guaranteed.</p>
+     *
+     * @param prefix the prefix that was being mapped.
+     *  This is the empty string when a default mapping scope ends.
+     * @throws org.xml.sax.SAXException the client may throw
+     *            an exception during processing
+     * @see #startPrefixMapping
+     * @see #endElement
+     */
+    public void endPrefixMapping (String prefix)
+        throws SAXException;
+
+
+    /**
+     * Receive notification of the beginning of an element.
+     *
+     * <p>The Parser will invoke this method at the beginning of every
+     * element in the XML document; there will be a corresponding
+     * {@link #endElement endElement} event for every startElement event
+     * (even when the element is empty). All of the element's content will be
+     * reported, in order, before the corresponding endElement
+     * event.</p>
+     *
+     * <p>This event allows up to three name components for each
+     * element:</p>
+     *
+     * <ol>
+     * <li>the Namespace URI;</li>
+     * <li>the local name; and</li>
+     * <li>the qualified (prefixed) name.</li>
+     * </ol>
+     *
+     * <p>Any or all of these may be provided, depending on the
+     * values of the <var>http://xml.org/sax/features/namespaces</var>
+     * and the <var>http://xml.org/sax/features/namespace-prefixes</var>
+     * properties:</p>
+     *
+     * <ul>
+     * <li>the Namespace URI and local name are required when
+     * the namespaces property is <var>true</var> (the default), and are
+     * optional when the namespaces property is <var>false</var> (if one is
+     * specified, both must be);</li>
+     * <li>the qualified name is required when the namespace-prefixes property
+     * is <var>true</var>, and is optional when the namespace-prefixes property
+     * is <var>false</var> (the default).</li>
+     * </ul>
+     *
+     * <p>Note that the attribute list provided will contain only
+     * attributes with explicit values (specified or defaulted):
+     * #IMPLIED attributes will be omitted.  The attribute list
+     * will contain attributes used for Namespace declarations
+     * (xmlns* attributes) only if the
+     * <code>http://xml.org/sax/features/namespace-prefixes</code>
+     * property is true (it is false by default, and support for a
+     * true value is optional).</p>
+     *
+     * <p>Like {@link #characters characters()}, attribute values may have
+     * characters that need more than one <code>char</code> value.  </p>
+     *
+     * @param uri the Namespace URI, or the empty string if the
+     *        element has no Namespace URI or if Namespace
+     *        processing is not being performed
+     * @param localName the local name (without prefix), or the
+     *        empty string if Namespace processing is not being
+     *        performed
+     * @param qName the qualified name (with prefix), or the
+     *        empty string if qualified names are not available
+     * @param atts the attributes attached to the element.  If
+     *        there are no attributes, it shall be an empty
+     *        Attributes object.  The value of this object after
+     *        startElement returns is undefined
+     * @throws org.xml.sax.SAXException any SAX exception, possibly
+     *            wrapping another exception
+     * @see #endElement
+     * @see org.xml.sax.Attributes
+     * @see org.xml.sax.helpers.AttributesImpl
+     */
+    public void startElement (String uri, String localName,
+                              String qName, Attributes atts)
+        throws SAXException;
+
+
+    /**
+     * Receive notification of the end of an element.
+     *
+     * <p>The SAX parser will invoke this method at the end of every
+     * element in the XML document; there will be a corresponding
+     * {@link #startElement startElement} event for every endElement
+     * event (even when the element is empty).</p>
+     *
+     * <p>For information on the names, see startElement.</p>
+     *
+     * @param uri the Namespace URI, or the empty string if the
+     *        element has no Namespace URI or if Namespace
+     *        processing is not being performed
+     * @param localName the local name (without prefix), or the
+     *        empty string if Namespace processing is not being
+     *        performed
+     * @param qName the qualified XML name (with prefix), or the
+     *        empty string if qualified names are not available
+     * @throws org.xml.sax.SAXException any SAX exception, possibly
+     *            wrapping another exception
+     */
+    public void endElement (String uri, String localName,
+                            String qName)
+        throws SAXException;
+
+
+    /**
+     * Receive notification of character data.
+     *
+     * <p>The Parser will call this method to report each chunk of
+     * character data.  SAX parsers may return all contiguous character
+     * data in a single chunk, or they may split it into several
+     * chunks; however, all of the characters in any single event
+     * must come from the same external entity so that the Locator
+     * provides useful information.</p>
+     *
+     * <p>The application must not attempt to read from the array
+     * outside of the specified range.</p>
+     *
+     * <p>Individual characters may consist of more than one Java
+     * <code>char</code> value.  There are two important cases where this
+     * happens, because characters can't be represented in just sixteen bits.
+     * In one case, characters are represented in a <em>Surrogate Pair</em>,
+     * using two special Unicode values. Such characters are in the so-called
+     * "Astral Planes", with a code point above U+FFFF.  A second case involves
+     * composite characters, such as a base character combining with one or
+     * more accent characters. </p>
+     *
+     * <p> Your code should not assume that algorithms using
+     * <code>char</code>-at-a-time idioms will be working in character
+     * units; in some cases they will split characters.  This is relevant
+     * wherever XML permits arbitrary characters, such as attribute values,
+     * processing instruction data, and comments as well as in data reported
+     * from this method.  It's also generally relevant whenever Java code
+     * manipulates internationalized text; the issue isn't unique to XML.</p>
+     *
+     * <p>Note that some parsers will report whitespace in element
+     * content using the {@link #ignorableWhitespace ignorableWhitespace}
+     * method rather than this one (validating parsers <em>must</em>
+     * do so).</p>
+     *
+     * @param ch the characters from the XML document
+     * @param start the start position in the array
+     * @param length the number of characters to read from the array
+     * @throws org.xml.sax.SAXException any SAX exception, possibly
+     *            wrapping another exception
+     * @see #ignorableWhitespace
+     * @see org.xml.sax.Locator
+     */
+    public void characters (char ch[], int start, int length)
+        throws SAXException;
+
+
+    /**
+     * Receive notification of ignorable whitespace in element content.
+     *
+     * <p>Validating Parsers must use this method to report each chunk
+     * of whitespace in element content (see the W3C XML 1.0
+     * recommendation, section 2.10): non-validating parsers may also
+     * use this method if they are capable of parsing and using
+     * content models.</p>
+     *
+     * <p>SAX parsers may return all contiguous whitespace in a single
+     * chunk, or they may split it into several chunks; however, all of
+     * the characters in any single event must come from the same
+     * external entity, so that the Locator provides useful
+     * information.</p>
+     *
+     * <p>The application must not attempt to read from the array
+     * outside of the specified range.</p>
+     *
+     * @param ch the characters from the XML document
+     * @param start the start position in the array
+     * @param length the number of characters to read from the array
+     * @throws org.xml.sax.SAXException any SAX exception, possibly
+     *            wrapping another exception
+     * @see #characters
+     */
+    public void ignorableWhitespace (char ch[], int start, int length)
+        throws SAXException;
+
+
+    /**
+     * Receive notification of a processing instruction.
+     *
+     * <p>The Parser will invoke this method once for each processing
+     * instruction found: note that processing instructions may occur
+     * before or after the main document element.</p>
+     *
+     * <p>A SAX parser must never report an XML declaration (XML 1.0,
+     * section 2.8) or a text declaration (XML 1.0, section 4.3.1)
+     * using this method.</p>
+     *
+     * <p>Like {@link #characters characters()}, processing instruction
+     * data may have characters that need more than one <code>char</code>
+     * value. </p>
+     *
+     * @param target the processing instruction target
+     * @param data the processing instruction data, or null if
+     *        none was supplied.  The data does not include any
+     *        whitespace separating it from the target
+     * @throws org.xml.sax.SAXException any SAX exception, possibly
+     *            wrapping another exception
+     */
+    public void processingInstruction (String target, String data)
+        throws SAXException;
+
+
+    /**
+     * Receive notification of a skipped entity.
+     * This is not called for entity references within markup constructs
+     * such as element start tags or markup declarations.  (The XML
+     * recommendation requires reporting skipped external entities.
+     * SAX also reports internal entity expansion/non-expansion, except
+     * within markup constructs.)
+     *
+     * <p>The Parser will invoke this method each time the entity is
+     * skipped.  Non-validating processors may skip entities if they
+     * have not seen the declarations (because, for example, the
+     * entity was declared in an external DTD subset).  All processors
+     * may skip external entities, depending on the values of the
+     * <code>http://xml.org/sax/features/external-general-entities</code>
+     * and the
+     * <code>http://xml.org/sax/features/external-parameter-entities</code>
+     * properties.</p>
+     *
+     * @param name the name of the skipped entity.  If it is a
+     *        parameter entity, the name will begin with '%', and if
+     *        it is the external DTD subset, it will be the string
+     *        "[dtd]"
+     * @throws org.xml.sax.SAXException any SAX exception, possibly
+     *            wrapping another exception
+     */
+    public void skippedEntity (String name)
+        throws SAXException;
+}
+
+// end of ContentHandler.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/jdk/internal/org/xml/sax/DTDHandler.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// SAX DTD handler.
+// http://www.saxproject.org
+// No warranty; no copyright -- use this as you will.
+// $Id: DTDHandler.java,v 1.2 2004/11/03 22:44:51 jsuttor Exp $
+
+package jdk.internal.org.xml.sax;
+
+/**
+ * Receive notification of basic DTD-related events.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>If a SAX application needs information about notations and
+ * unparsed entities, then the application implements this
+ * interface and registers an instance with the SAX parser using
+ * the parser's setDTDHandler method.  The parser uses the
+ * instance to report notation and unparsed entity declarations to
+ * the application.</p>
+ *
+ * <p>Note that this interface includes only those DTD events that
+ * the XML recommendation <em>requires</em> processors to report:
+ * notation and unparsed entity declarations.</p>
+ *
+ * <p>The SAX parser may report these events in any order, regardless
+ * of the order in which the notations and unparsed entities were
+ * declared; however, all DTD events must be reported after the
+ * document handler's startDocument event, and before the first
+ * startElement event.
+ * (If the {@link org.xml.sax.ext.LexicalHandler LexicalHandler} is
+ * used, these events must also be reported before the endDTD event.)
+ * </p>
+ *
+ * <p>It is up to the application to store the information for
+ * future use (perhaps in a hash table or object tree).
+ * If the application encounters attributes of type "NOTATION",
+ * "ENTITY", or "ENTITIES", it can use the information that it
+ * obtained through this interface to find the entity and/or
+ * notation corresponding with the attribute value.</p>
+ *
+ * @since SAX 1.0
+ * @author David Megginson
+ * @see org.xml.sax.XMLReader#setDTDHandler
+ */
+public interface DTDHandler {
+
+
+    /**
+     * Receive notification of a notation declaration event.
+     *
+     * <p>It is up to the application to record the notation for later
+     * reference, if necessary;
+     * notations may appear as attribute values and in unparsed entity
+     * declarations, and are sometime used with processing instruction
+     * target names.</p>
+     *
+     * <p>At least one of publicId and systemId must be non-null.
+     * If a system identifier is present, and it is a URL, the SAX
+     * parser must resolve it fully before passing it to the
+     * application through this event.</p>
+     *
+     * <p>There is no guarantee that the notation declaration will be
+     * reported before any unparsed entities that use it.</p>
+     *
+     * @param name The notation name.
+     * @param publicId The notation's public identifier, or null if
+     *        none was given.
+     * @param systemId The notation's system identifier, or null if
+     *        none was given.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see #unparsedEntityDecl
+     * @see org.xml.sax.Attributes
+     */
+    public abstract void notationDecl (String name,
+                                       String publicId,
+                                       String systemId)
+        throws SAXException;
+
+
+    /**
+     * Receive notification of an unparsed entity declaration event.
+     *
+     * <p>Note that the notation name corresponds to a notation
+     * reported by the {@link #notationDecl notationDecl} event.
+     * It is up to the application to record the entity for later
+     * reference, if necessary;
+     * unparsed entities may appear as attribute values.
+     * </p>
+     *
+     * <p>If the system identifier is a URL, the parser must resolve it
+     * fully before passing it to the application.</p>
+     *
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @param name The unparsed entity's name.
+     * @param publicId The entity's public identifier, or null if none
+     *        was given.
+     * @param systemId The entity's system identifier.
+     * @param notationName The name of the associated notation.
+     * @see #notationDecl
+     * @see org.xml.sax.Attributes
+     */
+    public abstract void unparsedEntityDecl (String name,
+                                             String publicId,
+                                             String systemId,
+                                             String notationName)
+        throws SAXException;
+
+}
+
+// end of DTDHandler.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/jdk/internal/org/xml/sax/EntityResolver.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// SAX entity resolver.
+// http://www.saxproject.org
+// No warranty; no copyright -- use this as you will.
+// $Id: EntityResolver.java,v 1.2 2004/11/03 22:44:52 jsuttor Exp $
+
+package jdk.internal.org.xml.sax;
+
+import java.io.IOException;
+
+
+/**
+ * Basic interface for resolving entities.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>If a SAX application needs to implement customized handling
+ * for external entities, it must implement this interface and
+ * register an instance with the SAX driver using the
+ * {@link org.xml.sax.XMLReader#setEntityResolver setEntityResolver}
+ * method.</p>
+ *
+ * <p>The XML reader will then allow the application to intercept any
+ * external entities (including the external DTD subset and external
+ * parameter entities, if any) before including them.</p>
+ *
+ * <p>Many SAX applications will not need to implement this interface,
+ * but it will be especially useful for applications that build
+ * XML documents from databases or other specialised input sources,
+ * or for applications that use URI types other than URLs.</p>
+ *
+ * <p>The following resolver would provide the application
+ * with a special character stream for the entity with the system
+ * identifier "http://www.myhost.com/today":</p>
+ *
+ * <pre>
+ * import org.xml.sax.EntityResolver;
+ * import org.xml.sax.InputSource;
+ *
+ * public class MyResolver implements EntityResolver {
+ *   public InputSource resolveEntity (String publicId, String systemId)
+ *   {
+ *     if (systemId.equals("http://www.myhost.com/today")) {
+ *              // return a special input source
+ *       MyReader reader = new MyReader();
+ *       return new InputSource(reader);
+ *     } else {
+ *              // use the default behaviour
+ *       return null;
+ *     }
+ *   }
+ * }
+ * </pre>
+ *
+ * <p>The application can also use this interface to redirect system
+ * identifiers to local URIs or to look up replacements in a catalog
+ * (possibly by using the public identifier).</p>
+ *
+ * @since SAX 1.0
+ * @author David Megginson
+ * @see org.xml.sax.XMLReader#setEntityResolver
+ * @see org.xml.sax.InputSource
+ */
+public interface EntityResolver {
+
+
+    /**
+     * Allow the application to resolve external entities.
+     *
+     * <p>The parser will call this method before opening any external
+     * entity except the top-level document entity.  Such entities include
+     * the external DTD subset and external parameter entities referenced
+     * within the DTD (in either case, only if the parser reads external
+     * parameter entities), and external general entities referenced
+     * within the document element (if the parser reads external general
+     * entities).  The application may request that the parser locate
+     * the entity itself, that it use an alternative URI, or that it
+     * use data provided by the application (as a character or byte
+     * input stream).</p>
+     *
+     * <p>Application writers can use this method to redirect external
+     * system identifiers to secure and/or local URIs, to look up
+     * public identifiers in a catalogue, or to read an entity from a
+     * database or other input source (including, for example, a dialog
+     * box).  Neither XML nor SAX specifies a preferred policy for using
+     * public or system IDs to resolve resources.  However, SAX specifies
+     * how to interpret any InputSource returned by this method, and that
+     * if none is returned, then the system ID will be dereferenced as
+     * a URL.  </p>
+     *
+     * <p>If the system identifier is a URL, the SAX parser must
+     * resolve it fully before reporting it to the application.</p>
+     *
+     * @param publicId The public identifier of the external entity
+     *        being referenced, or null if none was supplied.
+     * @param systemId The system identifier of the external entity
+     *        being referenced.
+     * @return An InputSource object describing the new input source,
+     *         or null to request that the parser open a regular
+     *         URI connection to the system identifier.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @exception java.io.IOException A Java-specific IO exception,
+     *            possibly the result of creating a new InputStream
+     *            or Reader for the InputSource.
+     * @see org.xml.sax.InputSource
+     */
+    public abstract InputSource resolveEntity (String publicId,
+                                               String systemId)
+        throws SAXException, IOException;
+
+}
+
+// end of EntityResolver.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/jdk/internal/org/xml/sax/ErrorHandler.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// SAX error handler.
+// http://www.saxproject.org
+// No warranty; no copyright -- use this as you will.
+// $Id: ErrorHandler.java,v 1.2 2004/11/03 22:44:52 jsuttor Exp $
+
+package jdk.internal.org.xml.sax;
+
+
+/**
+ * Basic interface for SAX error handlers.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>If a SAX application needs to implement customized error
+ * handling, it must implement this interface and then register an
+ * instance with the XML reader using the
+ * {@link org.xml.sax.XMLReader#setErrorHandler setErrorHandler}
+ * method.  The parser will then report all errors and warnings
+ * through this interface.</p>
+ *
+ * <p><strong>WARNING:</strong> If an application does <em>not</em>
+ * register an ErrorHandler, XML parsing errors will go unreported,
+ * except that <em>SAXParseException</em>s will be thrown for fatal errors.
+ * In order to detect validity errors, an ErrorHandler that does something
+ * with {@link #error error()} calls must be registered.</p>
+ *
+ * <p>For XML processing errors, a SAX driver must use this interface
+ * in preference to throwing an exception: it is up to the application
+ * to decide whether to throw an exception for different types of
+ * errors and warnings.  Note, however, that there is no requirement that
+ * the parser continue to report additional errors after a call to
+ * {@link #fatalError fatalError}.  In other words, a SAX driver class
+ * may throw an exception after reporting any fatalError.
+ * Also parsers may throw appropriate exceptions for non-XML errors.
+ * For example, {@link XMLReader#parse XMLReader.parse()} would throw
+ * an IOException for errors accessing entities or the document.</p>
+ *
+ * @since SAX 1.0
+ * @author David Megginson
+ * @see org.xml.sax.XMLReader#setErrorHandler
+ * @see org.xml.sax.SAXParseException
+ */
+public interface ErrorHandler {
+
+
+    /**
+     * Receive notification of a warning.
+     *
+     * <p>SAX parsers will use this method to report conditions that
+     * are not errors or fatal errors as defined by the XML
+     * recommendation.  The default behaviour is to take no
+     * action.</p>
+     *
+     * <p>The SAX parser must continue to provide normal parsing events
+     * after invoking this method: it should still be possible for the
+     * application to process the document through to the end.</p>
+     *
+     * <p>Filters may use this method to report other, non-XML warnings
+     * as well.</p>
+     *
+     * @param exception The warning information encapsulated in a
+     *                  SAX parse exception.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.SAXParseException
+     */
+    public abstract void warning (SAXParseException exception)
+        throws SAXException;
+
+
+    /**
+     * Receive notification of a recoverable error.
+     *
+     * <p>This corresponds to the definition of "error" in section 1.2
+     * of the W3C XML 1.0 Recommendation.  For example, a validating
+     * parser would use this callback to report the violation of a
+     * validity constraint.  The default behaviour is to take no
+     * action.</p>
+     *
+     * <p>The SAX parser must continue to provide normal parsing
+     * events after invoking this method: it should still be possible
+     * for the application to process the document through to the end.
+     * If the application cannot do so, then the parser should report
+     * a fatal error even if the XML recommendation does not require
+     * it to do so.</p>
+     *
+     * <p>Filters may use this method to report other, non-XML errors
+     * as well.</p>
+     *
+     * @param exception The error information encapsulated in a
+     *                  SAX parse exception.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.SAXParseException
+     */
+    public abstract void error (SAXParseException exception)
+        throws SAXException;
+
+
+    /**
+     * Receive notification of a non-recoverable error.
+     *
+     * <p><strong>There is an apparent contradiction between the
+     * documentation for this method and the documentation for {@link
+     * org.xml.sax.ContentHandler#endDocument}.  Until this ambiguity
+     * is resolved in a future major release, clients should make no
+     * assumptions about whether endDocument() will or will not be
+     * invoked when the parser has reported a fatalError() or thrown
+     * an exception.</strong></p>
+     *
+     * <p>This corresponds to the definition of "fatal error" in
+     * section 1.2 of the W3C XML 1.0 Recommendation.  For example, a
+     * parser would use this callback to report the violation of a
+     * well-formedness constraint.</p>
+     *
+     * <p>The application must assume that the document is unusable
+     * after the parser has invoked this method, and should continue
+     * (if at all) only for the sake of collecting additional error
+     * messages: in fact, SAX parsers are free to stop reporting any
+     * other events once this method has been invoked.</p>
+     *
+     * @param exception The error information encapsulated in a
+     *                  SAX parse exception.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.SAXParseException
+     */
+    public abstract void fatalError (SAXParseException exception)
+        throws SAXException;
+
+}
+
+// end of ErrorHandler.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/jdk/internal/org/xml/sax/InputSource.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,360 @@
+/*
+ * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// SAX input source.
+// http://www.saxproject.org
+// No warranty; no copyright -- use this as you will.
+// $Id: InputSource.java,v 1.2 2004/11/03 22:55:32 jsuttor Exp $
+
+package jdk.internal.org.xml.sax;
+
+import java.io.Reader;
+import java.io.InputStream;
+
+/**
+ * A single input source for an XML entity.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>This class allows a SAX application to encapsulate information
+ * about an input source in a single object, which may include
+ * a public identifier, a system identifier, a byte stream (possibly
+ * with a specified encoding), and/or a character stream.</p>
+ *
+ * <p>There are two places that the application can deliver an
+ * input source to the parser: as the argument to the Parser.parse
+ * method, or as the return value of the EntityResolver.resolveEntity
+ * method.</p>
+ *
+ * <p>The SAX parser will use the InputSource object to determine how
+ * to read XML input.  If there is a character stream available, the
+ * parser will read that stream directly, disregarding any text
+ * encoding declaration found in that stream.
+ * If there is no character stream, but there is
+ * a byte stream, the parser will use that byte stream, using the
+ * encoding specified in the InputSource or else (if no encoding is
+ * specified) autodetecting the character encoding using an algorithm
+ * such as the one in the XML specification.  If neither a character
+ * stream nor a
+ * byte stream is available, the parser will attempt to open a URI
+ * connection to the resource identified by the system
+ * identifier.</p>
+ *
+ * <p>An InputSource object belongs to the application: the SAX parser
+ * shall never modify it in any way (it may modify a copy if
+ * necessary).  However, standard processing of both byte and
+ * character streams is to close them on as part of end-of-parse cleanup,
+ * so applications should not attempt to re-use such streams after they
+ * have been handed to a parser.  </p>
+ *
+ * @since SAX 1.0
+ * @author David Megginson
+ * @see org.xml.sax.XMLReader#parse(org.xml.sax.InputSource)
+ * @see org.xml.sax.EntityResolver#resolveEntity
+ * @see java.io.InputStream
+ * @see java.io.Reader
+ */
+public class InputSource {
+
+    /**
+     * Zero-argument default constructor.
+     *
+     * @see #setPublicId
+     * @see #setSystemId
+     * @see #setByteStream
+     * @see #setCharacterStream
+     * @see #setEncoding
+     */
+    public InputSource ()
+    {
+    }
+
+
+    /**
+     * Create a new input source with a system identifier.
+     *
+     * <p>Applications may use setPublicId to include a
+     * public identifier as well, or setEncoding to specify
+     * the character encoding, if known.</p>
+     *
+     * <p>If the system identifier is a URL, it must be fully
+     * resolved (it may not be a relative URL).</p>
+     *
+     * @param systemId The system identifier (URI).
+     * @see #setPublicId
+     * @see #setSystemId
+     * @see #setByteStream
+     * @see #setEncoding
+     * @see #setCharacterStream
+     */
+    public InputSource (String systemId)
+    {
+        setSystemId(systemId);
+    }
+
+
+    /**
+     * Create a new input source with a byte stream.
+     *
+     * <p>Application writers should use setSystemId() to provide a base
+     * for resolving relative URIs, may use setPublicId to include a
+     * public identifier, and may use setEncoding to specify the object's
+     * character encoding.</p>
+     *
+     * @param byteStream The raw byte stream containing the document.
+     * @see #setPublicId
+     * @see #setSystemId
+     * @see #setEncoding
+     * @see #setByteStream
+     * @see #setCharacterStream
+     */
+    public InputSource (InputStream byteStream)
+    {
+        setByteStream(byteStream);
+    }
+
+
+    /**
+     * Create a new input source with a character stream.
+     *
+     * <p>Application writers should use setSystemId() to provide a base
+     * for resolving relative URIs, and may use setPublicId to include a
+     * public identifier.</p>
+     *
+     * <p>The character stream shall not include a byte order mark.</p>
+     *
+     * @see #setPublicId
+     * @see #setSystemId
+     * @see #setByteStream
+     * @see #setCharacterStream
+     */
+    public InputSource (Reader characterStream)
+    {
+        setCharacterStream(characterStream);
+    }
+
+
+    /**
+     * Set the public identifier for this input source.
+     *
+     * <p>The public identifier is always optional: if the application
+     * writer includes one, it will be provided as part of the
+     * location information.</p>
+     *
+     * @param publicId The public identifier as a string.
+     * @see #getPublicId
+     * @see org.xml.sax.Locator#getPublicId
+     * @see org.xml.sax.SAXParseException#getPublicId
+     */
+    public void setPublicId (String publicId)
+    {
+        this.publicId = publicId;
+    }
+
+
+    /**
+     * Get the public identifier for this input source.
+     *
+     * @return The public identifier, or null if none was supplied.
+     * @see #setPublicId
+     */
+    public String getPublicId ()
+    {
+        return publicId;
+    }
+
+
+    /**
+     * Set the system identifier for this input source.
+     *
+     * <p>The system identifier is optional if there is a byte stream
+     * or a character stream, but it is still useful to provide one,
+     * since the application can use it to resolve relative URIs
+     * and can include it in error messages and warnings (the parser
+     * will attempt to open a connection to the URI only if
+     * there is no byte stream or character stream specified).</p>
+     *
+     * <p>If the application knows the character encoding of the
+     * object pointed to by the system identifier, it can register
+     * the encoding using the setEncoding method.</p>
+     *
+     * <p>If the system identifier is a URL, it must be fully
+     * resolved (it may not be a relative URL).</p>
+     *
+     * @param systemId The system identifier as a string.
+     * @see #setEncoding
+     * @see #getSystemId
+     * @see org.xml.sax.Locator#getSystemId
+     * @see org.xml.sax.SAXParseException#getSystemId
+     */
+    public void setSystemId (String systemId)
+    {
+        this.systemId = systemId;
+    }
+
+
+    /**
+     * Get the system identifier for this input source.
+     *
+     * <p>The getEncoding method will return the character encoding
+     * of the object pointed to, or null if unknown.</p>
+     *
+     * <p>If the system ID is a URL, it will be fully resolved.</p>
+     *
+     * @return The system identifier, or null if none was supplied.
+     * @see #setSystemId
+     * @see #getEncoding
+     */
+    public String getSystemId ()
+    {
+        return systemId;
+    }
+
+
+    /**
+     * Set the byte stream for this input source.
+     *
+     * <p>The SAX parser will ignore this if there is also a character
+     * stream specified, but it will use a byte stream in preference
+     * to opening a URI connection itself.</p>
+     *
+     * <p>If the application knows the character encoding of the
+     * byte stream, it should set it with the setEncoding method.</p>
+     *
+     * @param byteStream A byte stream containing an XML document or
+     *        other entity.
+     * @see #setEncoding
+     * @see #getByteStream
+     * @see #getEncoding
+     * @see java.io.InputStream
+     */
+    public void setByteStream (InputStream byteStream)
+    {
+        this.byteStream = byteStream;
+    }
+
+
+    /**
+     * Get the byte stream for this input source.
+     *
+     * <p>The getEncoding method will return the character
+     * encoding for this byte stream, or null if unknown.</p>
+     *
+     * @return The byte stream, or null if none was supplied.
+     * @see #getEncoding
+     * @see #setByteStream
+     */
+    public InputStream getByteStream ()
+    {
+        return byteStream;
+    }
+
+
+    /**
+     * Set the character encoding, if known.
+     *
+     * <p>The encoding must be a string acceptable for an
+     * XML encoding declaration (see section 4.3.3 of the XML 1.0
+     * recommendation).</p>
+     *
+     * <p>This method has no effect when the application provides a
+     * character stream.</p>
+     *
+     * @param encoding A string describing the character encoding.
+     * @see #setSystemId
+     * @see #setByteStream
+     * @see #getEncoding
+     */
+    public void setEncoding (String encoding)
+    {
+        this.encoding = encoding;
+    }
+
+
+    /**
+     * Get the character encoding for a byte stream or URI.
+     * This value will be ignored when the application provides a
+     * character stream.
+     *
+     * @return The encoding, or null if none was supplied.
+     * @see #setByteStream
+     * @see #getSystemId
+     * @see #getByteStream
+     */
+    public String getEncoding ()
+    {
+        return encoding;
+    }
+
+
+    /**
+     * Set the character stream for this input source.
+     *
+     * <p>If there is a character stream specified, the SAX parser
+     * will ignore any byte stream and will not attempt to open
+     * a URI connection to the system identifier.</p>
+     *
+     * @param characterStream The character stream containing the
+     *        XML document or other entity.
+     * @see #getCharacterStream
+     * @see java.io.Reader
+     */
+    public void setCharacterStream (Reader characterStream)
+    {
+        this.characterStream = characterStream;
+    }
+
+
+    /**
+     * Get the character stream for this input source.
+     *
+     * @return The character stream, or null if none was supplied.
+     * @see #setCharacterStream
+     */
+    public Reader getCharacterStream ()
+    {
+        return characterStream;
+    }
+
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Internal state.
+    ////////////////////////////////////////////////////////////////////
+
+    private String publicId;
+    private String systemId;
+    private InputStream byteStream;
+    private String encoding;
+    private Reader characterStream;
+
+}
+
+// end of InputSource.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/jdk/internal/org/xml/sax/Locator.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// SAX locator interface for document events.
+// http://www.saxproject.org
+// No warranty; no copyright -- use this as you will.
+// $Id: Locator.java,v 1.2 2004/11/03 22:55:32 jsuttor Exp $
+
+package jdk.internal.org.xml.sax;
+
+
+/**
+ * Interface for associating a SAX event with a document location.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>If a SAX parser provides location information to the SAX
+ * application, it does so by implementing this interface and then
+ * passing an instance to the application using the content
+ * handler's {@link org.xml.sax.ContentHandler#setDocumentLocator
+ * setDocumentLocator} method.  The application can use the
+ * object to obtain the location of any other SAX event
+ * in the XML source document.</p>
+ *
+ * <p>Note that the results returned by the object will be valid only
+ * during the scope of each callback method: the application
+ * will receive unpredictable results if it attempts to use the
+ * locator at any other time, or after parsing completes.</p>
+ *
+ * <p>SAX parsers are not required to supply a locator, but they are
+ * very strongly encouraged to do so.  If the parser supplies a
+ * locator, it must do so before reporting any other document events.
+ * If no locator has been set by the time the application receives
+ * the {@link org.xml.sax.ContentHandler#startDocument startDocument}
+ * event, the application should assume that a locator is not
+ * available.</p>
+ *
+ * @since SAX 1.0
+ * @author David Megginson
+ * @see org.xml.sax.ContentHandler#setDocumentLocator
+ */
+public interface Locator {
+
+
+    /**
+     * Return the public identifier for the current document event.
+     *
+     * <p>The return value is the public identifier of the document
+     * entity or of the external parsed entity in which the markup
+     * triggering the event appears.</p>
+     *
+     * @return A string containing the public identifier, or
+     *         null if none is available.
+     * @see #getSystemId
+     */
+    public abstract String getPublicId ();
+
+
+    /**
+     * Return the system identifier for the current document event.
+     *
+     * <p>The return value is the system identifier of the document
+     * entity or of the external parsed entity in which the markup
+     * triggering the event appears.</p>
+     *
+     * <p>If the system identifier is a URL, the parser must resolve it
+     * fully before passing it to the application.  For example, a file
+     * name must always be provided as a <em>file:...</em> URL, and other
+     * kinds of relative URI are also resolved against their bases.</p>
+     *
+     * @return A string containing the system identifier, or null
+     *         if none is available.
+     * @see #getPublicId
+     */
+    public abstract String getSystemId ();
+
+
+    /**
+     * Return the line number where the current document event ends.
+     * Lines are delimited by line ends, which are defined in
+     * the XML specification.
+     *
+     * <p><strong>Warning:</strong> The return value from the method
+     * is intended only as an approximation for the sake of diagnostics;
+     * it is not intended to provide sufficient information
+     * to edit the character content of the original XML document.
+     * In some cases, these "line" numbers match what would be displayed
+     * as columns, and in others they may not match the source text
+     * due to internal entity expansion.  </p>
+     *
+     * <p>The return value is an approximation of the line number
+     * in the document entity or external parsed entity where the
+     * markup triggering the event appears.</p>
+     *
+     * <p>If possible, the SAX driver should provide the line position
+     * of the first character after the text associated with the document
+     * event.  The first line is line 1.</p>
+     *
+     * @return The line number, or -1 if none is available.
+     * @see #getColumnNumber
+     */
+    public abstract int getLineNumber ();
+
+
+    /**
+     * Return the column number where the current document event ends.
+     * This is one-based number of Java <code>char</code> values since
+     * the last line end.
+     *
+     * <p><strong>Warning:</strong> The return value from the method
+     * is intended only as an approximation for the sake of diagnostics;
+     * it is not intended to provide sufficient information
+     * to edit the character content of the original XML document.
+     * For example, when lines contain combining character sequences, wide
+     * characters, surrogate pairs, or bi-directional text, the value may
+     * not correspond to the column in a text editor's display. </p>
+     *
+     * <p>The return value is an approximation of the column number
+     * in the document entity or external parsed entity where the
+     * markup triggering the event appears.</p>
+     *
+     * <p>If possible, the SAX driver should provide the line position
+     * of the first character after the text associated with the document
+     * event.  The first column in each line is column 1.</p>
+     *
+     * @return The column number, or -1 if none is available.
+     * @see #getLineNumber
+     */
+    public abstract int getColumnNumber ();
+
+}
+
+// end of Locator.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/jdk/internal/org/xml/sax/SAXException.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// SAX exception class.
+// http://www.saxproject.org
+// No warranty; no copyright -- use this as you will.
+// $Id: SAXException.java,v 1.3 2004/11/03 22:55:32 jsuttor Exp $
+
+package jdk.internal.org.xml.sax;
+
+/**
+ * Encapsulate a general SAX error or warning.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>This class can contain basic error or warning information from
+ * either the XML parser or the application: a parser writer or
+ * application writer can subclass it to provide additional
+ * functionality.  SAX handlers may throw this exception or
+ * any exception subclassed from it.</p>
+ *
+ * <p>If the application needs to pass through other types of
+ * exceptions, it must wrap those exceptions in a SAXException
+ * or an exception derived from a SAXException.</p>
+ *
+ * <p>If the parser or application needs to include information about a
+ * specific location in an XML document, it should use the
+ * {@link org.xml.sax.SAXParseException SAXParseException} subclass.</p>
+ *
+ * @since SAX 1.0
+ * @author David Megginson
+ * @version 2.0.1 (sax2r2)
+ * @see org.xml.sax.SAXParseException
+ */
+public class SAXException extends Exception {
+
+
+    /**
+     * Create a new SAXException.
+     */
+    public SAXException ()
+    {
+        super();
+        this.exception = null;
+    }
+
+
+    /**
+     * Create a new SAXException.
+     *
+     * @param message The error or warning message.
+     */
+    public SAXException (String message) {
+        super(message);
+        this.exception = null;
+    }
+
+
+    /**
+     * Create a new SAXException wrapping an existing exception.
+     *
+     * <p>The existing exception will be embedded in the new
+     * one, and its message will become the default message for
+     * the SAXException.</p>
+     *
+     * @param e The exception to be wrapped in a SAXException.
+     */
+    public SAXException (Exception e)
+    {
+        super();
+        this.exception = e;
+    }
+
+
+    /**
+     * Create a new SAXException from an existing exception.
+     *
+     * <p>The existing exception will be embedded in the new
+     * one, but the new exception will have its own message.</p>
+     *
+     * @param message The detail message.
+     * @param e The exception to be wrapped in a SAXException.
+     */
+    public SAXException (String message, Exception e)
+    {
+        super(message);
+        this.exception = e;
+    }
+
+
+    /**
+     * Return a detail message for this exception.
+     *
+     * <p>If there is an embedded exception, and if the SAXException
+     * has no detail message of its own, this method will return
+     * the detail message from the embedded exception.</p>
+     *
+     * @return The error or warning message.
+     */
+    public String getMessage ()
+    {
+        String message = super.getMessage();
+
+        if (message == null && exception != null) {
+            return exception.getMessage();
+        } else {
+            return message;
+        }
+    }
+
+
+    /**
+     * Return the embedded exception, if any.
+     *
+     * @return The embedded exception, or null if there is none.
+     */
+    public Exception getException ()
+    {
+        return exception;
+    }
+
+    /**
+     * Return the cause of the exception
+     *
+     * @return Return the cause of the exception
+     */
+    public Throwable getCause() {
+        return exception;
+    }
+
+    /**
+     * Override toString to pick up any embedded exception.
+     *
+     * @return A string representation of this exception.
+     */
+    public String toString ()
+    {
+        if (exception != null) {
+            return super.toString() + "\n" + exception.toString();
+        } else {
+            return super.toString();
+        }
+    }
+
+
+
+    //////////////////////////////////////////////////////////////////////
+    // Internal state.
+    //////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * @serial The embedded exception if tunnelling, or null.
+     */
+    private Exception exception;
+
+    // Added serialVersionUID to preserve binary compatibility
+    static final long serialVersionUID = 583241635256073760L;
+}
+
+// end of SAXException.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/jdk/internal/org/xml/sax/SAXNotRecognizedException.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// SAXNotRecognizedException.java - unrecognized feature or value.
+// http://www.saxproject.org
+// Written by David Megginson
+// NO WARRANTY!  This class is in the Public Domain.
+// $Id: SAXNotRecognizedException.java,v 1.3 2004/11/03 22:55:32 jsuttor Exp $
+
+package jdk.internal.org.xml.sax;
+
+
+/**
+ * Exception class for an unrecognized identifier.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>An XMLReader will throw this exception when it finds an
+ * unrecognized feature or property identifier; SAX applications and
+ * extensions may use this class for other, similar purposes.</p>
+ *
+ * @since SAX 2.0
+ * @author David Megginson
+ * @see org.xml.sax.SAXNotSupportedException
+ */
+public class SAXNotRecognizedException extends SAXException
+{
+
+    /**
+     * Default constructor.
+     */
+    public SAXNotRecognizedException ()
+    {
+        super();
+    }
+
+
+    /**
+     * Construct a new exception with the given message.
+     *
+     * @param message The text message of the exception.
+     */
+    public SAXNotRecognizedException (String message)
+    {
+        super(message);
+    }
+
+    // Added serialVersionUID to preserve binary compatibility
+    static final long serialVersionUID = 5440506620509557213L;
+}
+
+// end of SAXNotRecognizedException.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/jdk/internal/org/xml/sax/SAXNotSupportedException.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// SAXNotSupportedException.java - unsupported feature or value.
+// http://www.saxproject.org
+// Written by David Megginson
+// NO WARRANTY!  This class is in the Public Domain.
+// $Id: SAXNotSupportedException.java,v 1.4 2004/11/03 22:55:32 jsuttor Exp $
+
+package jdk.internal.org.xml.sax;
+
+/**
+ * Exception class for an unsupported operation.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>An XMLReader will throw this exception when it recognizes a
+ * feature or property identifier, but cannot perform the requested
+ * operation (setting a state or value).  Other SAX2 applications and
+ * extensions may use this class for similar purposes.</p>
+ *
+ * @since SAX 2.0
+ * @author David Megginson
+ * @see org.xml.sax.SAXNotRecognizedException
+ */
+public class SAXNotSupportedException extends SAXException
+{
+
+    /**
+     * Construct a new exception with no message.
+     */
+    public SAXNotSupportedException ()
+    {
+        super();
+    }
+
+
+    /**
+     * Construct a new exception with the given message.
+     *
+     * @param message The text message of the exception.
+     */
+    public SAXNotSupportedException (String message)
+    {
+        super(message);
+    }
+
+    // Added serialVersionUID to preserve binary compatibility
+    static final long serialVersionUID = -1422818934641823846L;
+}
+
+// end of SAXNotSupportedException.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/jdk/internal/org/xml/sax/SAXParseException.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,313 @@
+/*
+ * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// SAX exception class.
+// http://www.saxproject.org
+// No warranty; no copyright -- use this as you will.
+// $Id: SAXParseException.java,v 1.2 2004/11/03 22:55:32 jsuttor Exp $
+
+package jdk.internal.org.xml.sax;
+
+/**
+ * Encapsulate an XML parse error or warning.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>This exception may include information for locating the error
+ * in the original XML document, as if it came from a {@link Locator}
+ * object.  Note that although the application
+ * will receive a SAXParseException as the argument to the handlers
+ * in the {@link org.xml.sax.ErrorHandler ErrorHandler} interface,
+ * the application is not actually required to throw the exception;
+ * instead, it can simply read the information in it and take a
+ * different action.</p>
+ *
+ * <p>Since this exception is a subclass of {@link org.xml.sax.SAXException
+ * SAXException}, it inherits the ability to wrap another exception.</p>
+ *
+ * @since SAX 1.0
+ * @author David Megginson
+ * @version 2.0.1 (sax2r2)
+ * @see org.xml.sax.SAXException
+ * @see org.xml.sax.Locator
+ * @see org.xml.sax.ErrorHandler
+ */
+public class SAXParseException extends SAXException {
+
+
+    //////////////////////////////////////////////////////////////////////
+    // Constructors.
+    //////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Create a new SAXParseException from a message and a Locator.
+     *
+     * <p>This constructor is especially useful when an application is
+     * creating its own exception from within a {@link org.xml.sax.ContentHandler
+     * ContentHandler} callback.</p>
+     *
+     * @param message The error or warning message.
+     * @param locator The locator object for the error or warning (may be
+     *        null).
+     * @see org.xml.sax.Locator
+     */
+    public SAXParseException (String message, Locator locator) {
+        super(message);
+        if (locator != null) {
+            init(locator.getPublicId(), locator.getSystemId(),
+                 locator.getLineNumber(), locator.getColumnNumber());
+        } else {
+            init(null, null, -1, -1);
+        }
+    }
+
+
+    /**
+     * Wrap an existing exception in a SAXParseException.
+     *
+     * <p>This constructor is especially useful when an application is
+     * creating its own exception from within a {@link org.xml.sax.ContentHandler
+     * ContentHandler} callback, and needs to wrap an existing exception that is not a
+     * subclass of {@link org.xml.sax.SAXException SAXException}.</p>
+     *
+     * @param message The error or warning message, or null to
+     *                use the message from the embedded exception.
+     * @param locator The locator object for the error or warning (may be
+     *        null).
+     * @param e Any exception.
+     * @see org.xml.sax.Locator
+     */
+    public SAXParseException (String message, Locator locator,
+                              Exception e) {
+        super(message, e);
+        if (locator != null) {
+            init(locator.getPublicId(), locator.getSystemId(),
+                 locator.getLineNumber(), locator.getColumnNumber());
+        } else {
+            init(null, null, -1, -1);
+        }
+    }
+
+
+    /**
+     * Create a new SAXParseException.
+     *
+     * <p>This constructor is most useful for parser writers.</p>
+     *
+     * <p>All parameters except the message are as if
+     * they were provided by a {@link Locator}.  For example, if the
+     * system identifier is a URL (including relative filename), the
+     * caller must resolve it fully before creating the exception.</p>
+     *
+     *
+     * @param message The error or warning message.
+     * @param publicId The public identifier of the entity that generated
+     *                 the error or warning.
+     * @param systemId The system identifier of the entity that generated
+     *                 the error or warning.
+     * @param lineNumber The line number of the end of the text that
+     *                   caused the error or warning.
+     * @param columnNumber The column number of the end of the text that
+     *                     cause the error or warning.
+     */
+    public SAXParseException (String message, String publicId, String systemId,
+                              int lineNumber, int columnNumber)
+    {
+        super(message);
+        init(publicId, systemId, lineNumber, columnNumber);
+    }
+
+
+    /**
+     * Create a new SAXParseException with an embedded exception.
+     *
+     * <p>This constructor is most useful for parser writers who
+     * need to wrap an exception that is not a subclass of
+     * {@link org.xml.sax.SAXException SAXException}.</p>
+     *
+     * <p>All parameters except the message and exception are as if
+     * they were provided by a {@link Locator}.  For example, if the
+     * system identifier is a URL (including relative filename), the
+     * caller must resolve it fully before creating the exception.</p>
+     *
+     * @param message The error or warning message, or null to use
+     *                the message from the embedded exception.
+     * @param publicId The public identifier of the entity that generated
+     *                 the error or warning.
+     * @param systemId The system identifier of the entity that generated
+     *                 the error or warning.
+     * @param lineNumber The line number of the end of the text that
+     *                   caused the error or warning.
+     * @param columnNumber The column number of the end of the text that
+     *                     cause the error or warning.
+     * @param e Another exception to embed in this one.
+     */
+    public SAXParseException (String message, String publicId, String systemId,
+                              int lineNumber, int columnNumber, Exception e)
+    {
+        super(message, e);
+        init(publicId, systemId, lineNumber, columnNumber);
+    }
+
+
+    /**
+     * Internal initialization method.
+     *
+     * @param publicId The public identifier of the entity which generated the exception,
+     *        or null.
+     * @param systemId The system identifier of the entity which generated the exception,
+     *        or null.
+     * @param lineNumber The line number of the error, or -1.
+     * @param columnNumber The column number of the error, or -1.
+     */
+    private void init (String publicId, String systemId,
+                       int lineNumber, int columnNumber)
+    {
+        this.publicId = publicId;
+        this.systemId = systemId;
+        this.lineNumber = lineNumber;
+        this.columnNumber = columnNumber;
+    }
+
+
+    /**
+     * Get the public identifier of the entity where the exception occurred.
+     *
+     * @return A string containing the public identifier, or null
+     *         if none is available.
+     * @see org.xml.sax.Locator#getPublicId
+     */
+    public String getPublicId ()
+    {
+        return this.publicId;
+    }
+
+
+    /**
+     * Get the system identifier of the entity where the exception occurred.
+     *
+     * <p>If the system identifier is a URL, it will have been resolved
+     * fully.</p>
+     *
+     * @return A string containing the system identifier, or null
+     *         if none is available.
+     * @see org.xml.sax.Locator#getSystemId
+     */
+    public String getSystemId ()
+    {
+        return this.systemId;
+    }
+
+
+    /**
+     * The line number of the end of the text where the exception occurred.
+     *
+     * <p>The first line is line 1.</p>
+     *
+     * @return An integer representing the line number, or -1
+     *         if none is available.
+     * @see org.xml.sax.Locator#getLineNumber
+     */
+    public int getLineNumber ()
+    {
+        return this.lineNumber;
+    }
+
+
+    /**
+     * The column number of the end of the text where the exception occurred.
+     *
+     * <p>The first column in a line is position 1.</p>
+     *
+     * @return An integer representing the column number, or -1
+     *         if none is available.
+     * @see org.xml.sax.Locator#getColumnNumber
+     */
+    public int getColumnNumber ()
+    {
+        return this.columnNumber;
+    }
+
+    /**
+     * Override toString to provide more detailed error message.
+     *
+     * @return A string representation of this exception.
+     */
+    public String toString() {
+        StringBuilder buf = new StringBuilder(getClass().getName());
+        String message = getLocalizedMessage();
+        if (publicId!=null)    buf.append("publicId: ").append(publicId);
+        if (systemId!=null)    buf.append("; systemId: ").append(systemId);
+        if (lineNumber!=-1)    buf.append("; lineNumber: ").append(lineNumber);
+        if (columnNumber!=-1)  buf.append("; columnNumber: ").append(columnNumber);
+
+       //append the exception message at the end
+        if (message!=null)     buf.append("; ").append(message);
+        return buf.toString();
+    }
+
+    //////////////////////////////////////////////////////////////////////
+    // Internal state.
+    //////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * @serial The public identifier, or null.
+     * @see #getPublicId
+     */
+    private String publicId;
+
+
+    /**
+     * @serial The system identifier, or null.
+     * @see #getSystemId
+     */
+    private String systemId;
+
+
+    /**
+     * @serial The line number, or -1.
+     * @see #getLineNumber
+     */
+    private int lineNumber;
+
+
+    /**
+     * @serial The column number, or -1.
+     * @see #getColumnNumber
+     */
+    private int columnNumber;
+
+    // Added serialVersionUID to preserve binary compatibility
+    static final long serialVersionUID = -5651165872476709336L;
+}
+
+// end of SAXParseException.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/jdk/internal/org/xml/sax/XMLReader.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,428 @@
+/*
+ * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// XMLReader.java - read an XML document.
+// http://www.saxproject.org
+// Written by David Megginson
+// NO WARRANTY!  This class is in the Public Domain.
+// $Id: XMLReader.java,v 1.3 2004/11/03 22:55:32 jsuttor Exp $
+
+package jdk.internal.org.xml.sax;
+
+import java.io.IOException;
+
+
+/**
+ * Interface for reading an XML document using callbacks.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p><strong>Note:</strong> despite its name, this interface does
+ * <em>not</em> extend the standard Java {@link java.io.Reader Reader}
+ * interface, because reading XML is a fundamentally different activity
+ * than reading character data.</p>
+ *
+ * <p>XMLReader is the interface that an XML parser's SAX2 driver must
+ * implement.  This interface allows an application to set and
+ * query features and properties in the parser, to register
+ * event handlers for document processing, and to initiate
+ * a document parse.</p>
+ *
+ * <p>All SAX interfaces are assumed to be synchronous: the
+ * {@link #parse parse} methods must not return until parsing
+ * is complete, and readers must wait for an event-handler callback
+ * to return before reporting the next event.</p>
+ *
+ * <p>This interface replaces the (now deprecated) SAX 1.0 {@link
+ * org.xml.sax.Parser Parser} interface.  The XMLReader interface
+ * contains two important enhancements over the old Parser
+ * interface (as well as some minor ones):</p>
+ *
+ * <ol>
+ * <li>it adds a standard way to query and set features and
+ *  properties; and</li>
+ * <li>it adds Namespace support, which is required for many
+ *  higher-level XML standards.</li>
+ * </ol>
+ *
+ * <p>There are adapters available to convert a SAX1 Parser to
+ * a SAX2 XMLReader and vice-versa.</p>
+ *
+ * @since SAX 2.0
+ * @author David Megginson
+ * @see org.xml.sax.XMLFilter
+ * @see org.xml.sax.helpers.ParserAdapter
+ * @see org.xml.sax.helpers.XMLReaderAdapter
+ */
+public interface XMLReader
+{
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Configuration.
+    ////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Look up the value of a feature flag.
+     *
+     * <p>The feature name is any fully-qualified URI.  It is
+     * possible for an XMLReader to recognize a feature name but
+     * temporarily be unable to return its value.
+     * Some feature values may be available only in specific
+     * contexts, such as before, during, or after a parse.
+     * Also, some feature values may not be programmatically accessible.
+     * (In the case of an adapter for SAX1 {@link Parser}, there is no
+     * implementation-independent way to expose whether the underlying
+     * parser is performing validation, expanding external entities,
+     * and so forth.) </p>
+     *
+     * <p>All XMLReaders are required to recognize the
+     * http://xml.org/sax/features/namespaces and the
+     * http://xml.org/sax/features/namespace-prefixes feature names.</p>
+     *
+     * <p>Typical usage is something like this:</p>
+     *
+     * <pre>
+     * XMLReader r = new MySAXDriver();
+     *
+     *                         // try to activate validation
+     * try {
+     *   r.setFeature("http://xml.org/sax/features/validation", true);
+     * } catch (SAXException e) {
+     *   System.err.println("Cannot activate validation.");
+     * }
+     *
+     *                         // register event handlers
+     * r.setContentHandler(new MyContentHandler());
+     * r.setErrorHandler(new MyErrorHandler());
+     *
+     *                         // parse the first document
+     * try {
+     *   r.parse("http://www.foo.com/mydoc.xml");
+     * } catch (IOException e) {
+     *   System.err.println("I/O exception reading XML document");
+     * } catch (SAXException e) {
+     *   System.err.println("XML exception reading document.");
+     * }
+     * </pre>
+     *
+     * <p>Implementors are free (and encouraged) to invent their own features,
+     * using names built on their own URIs.</p>
+     *
+     * @param name The feature name, which is a fully-qualified URI.
+     * @return The current value of the feature (true or false).
+     * @exception org.xml.sax.SAXNotRecognizedException If the feature
+     *            value can't be assigned or retrieved.
+     * @exception org.xml.sax.SAXNotSupportedException When the
+     *            XMLReader recognizes the feature name but
+     *            cannot determine its value at this time.
+     * @see #setFeature
+     */
+    public boolean getFeature (String name)
+        throws SAXNotRecognizedException, SAXNotSupportedException;
+
+
+    /**
+     * Set the value of a feature flag.
+     *
+     * <p>The feature name is any fully-qualified URI.  It is
+     * possible for an XMLReader to expose a feature value but
+     * to be unable to change the current value.
+     * Some feature values may be immutable or mutable only
+     * in specific contexts, such as before, during, or after
+     * a parse.</p>
+     *
+     * <p>All XMLReaders are required to support setting
+     * http://xml.org/sax/features/namespaces to true and
+     * http://xml.org/sax/features/namespace-prefixes to false.</p>
+     *
+     * @param name The feature name, which is a fully-qualified URI.
+     * @param value The requested value of the feature (true or false).
+     * @exception org.xml.sax.SAXNotRecognizedException If the feature
+     *            value can't be assigned or retrieved.
+     * @exception org.xml.sax.SAXNotSupportedException When the
+     *            XMLReader recognizes the feature name but
+     *            cannot set the requested value.
+     * @see #getFeature
+     */
+    public void setFeature (String name, boolean value)
+        throws SAXNotRecognizedException, SAXNotSupportedException;
+
+
+    /**
+     * Look up the value of a property.
+     *
+     * <p>The property name is any fully-qualified URI.  It is
+     * possible for an XMLReader to recognize a property name but
+     * temporarily be unable to return its value.
+     * Some property values may be available only in specific
+     * contexts, such as before, during, or after a parse.</p>
+     *
+     * <p>XMLReaders are not required to recognize any specific
+     * property names, though an initial core set is documented for
+     * SAX2.</p>
+     *
+     * <p>Implementors are free (and encouraged) to invent their own properties,
+     * using names built on their own URIs.</p>
+     *
+     * @param name The property name, which is a fully-qualified URI.
+     * @return The current value of the property.
+     * @exception org.xml.sax.SAXNotRecognizedException If the property
+     *            value can't be assigned or retrieved.
+     * @exception org.xml.sax.SAXNotSupportedException When the
+     *            XMLReader recognizes the property name but
+     *            cannot determine its value at this time.
+     * @see #setProperty
+     */
+    public Object getProperty (String name)
+        throws SAXNotRecognizedException, SAXNotSupportedException;
+
+
+    /**
+     * Set the value of a property.
+     *
+     * <p>The property name is any fully-qualified URI.  It is
+     * possible for an XMLReader to recognize a property name but
+     * to be unable to change the current value.
+     * Some property values may be immutable or mutable only
+     * in specific contexts, such as before, during, or after
+     * a parse.</p>
+     *
+     * <p>XMLReaders are not required to recognize setting
+     * any specific property names, though a core set is defined by
+     * SAX2.</p>
+     *
+     * <p>This method is also the standard mechanism for setting
+     * extended handlers.</p>
+     *
+     * @param name The property name, which is a fully-qualified URI.
+     * @param value The requested value for the property.
+     * @exception org.xml.sax.SAXNotRecognizedException If the property
+     *            value can't be assigned or retrieved.
+     * @exception org.xml.sax.SAXNotSupportedException When the
+     *            XMLReader recognizes the property name but
+     *            cannot set the requested value.
+     */
+    public void setProperty (String name, Object value)
+        throws SAXNotRecognizedException, SAXNotSupportedException;
+
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Event handlers.
+    ////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Allow an application to register an entity resolver.
+     *
+     * <p>If the application does not register an entity resolver,
+     * the XMLReader will perform its own default resolution.</p>
+     *
+     * <p>Applications may register a new or different resolver in the
+     * middle of a parse, and the SAX parser must begin using the new
+     * resolver immediately.</p>
+     *
+     * @param resolver The entity resolver.
+     * @see #getEntityResolver
+     */
+    public void setEntityResolver (EntityResolver resolver);
+
+
+    /**
+     * Return the current entity resolver.
+     *
+     * @return The current entity resolver, or null if none
+     *         has been registered.
+     * @see #setEntityResolver
+     */
+    public EntityResolver getEntityResolver ();
+
+
+    /**
+     * Allow an application to register a DTD event handler.
+     *
+     * <p>If the application does not register a DTD handler, all DTD
+     * events reported by the SAX parser will be silently ignored.</p>
+     *
+     * <p>Applications may register a new or different handler in the
+     * middle of a parse, and the SAX parser must begin using the new
+     * handler immediately.</p>
+     *
+     * @param handler The DTD handler.
+     * @see #getDTDHandler
+     */
+    public void setDTDHandler (DTDHandler handler);
+
+
+    /**
+     * Return the current DTD handler.
+     *
+     * @return The current DTD handler, or null if none
+     *         has been registered.
+     * @see #setDTDHandler
+     */
+    public DTDHandler getDTDHandler ();
+
+
+    /**
+     * Allow an application to register a content event handler.
+     *
+     * <p>If the application does not register a content handler, all
+     * content events reported by the SAX parser will be silently
+     * ignored.</p>
+     *
+     * <p>Applications may register a new or different handler in the
+     * middle of a parse, and the SAX parser must begin using the new
+     * handler immediately.</p>
+     *
+     * @param handler The content handler.
+     * @see #getContentHandler
+     */
+    public void setContentHandler (ContentHandler handler);
+
+
+    /**
+     * Return the current content handler.
+     *
+     * @return The current content handler, or null if none
+     *         has been registered.
+     * @see #setContentHandler
+     */
+    public ContentHandler getContentHandler ();
+
+
+    /**
+     * Allow an application to register an error event handler.
+     *
+     * <p>If the application does not register an error handler, all
+     * error events reported by the SAX parser will be silently
+     * ignored; however, normal processing may not continue.  It is
+     * highly recommended that all SAX applications implement an
+     * error handler to avoid unexpected bugs.</p>
+     *
+     * <p>Applications may register a new or different handler in the
+     * middle of a parse, and the SAX parser must begin using the new
+     * handler immediately.</p>
+     *
+     * @param handler The error handler.
+     * @see #getErrorHandler
+     */
+    public void setErrorHandler (ErrorHandler handler);
+
+
+    /**
+     * Return the current error handler.
+     *
+     * @return The current error handler, or null if none
+     *         has been registered.
+     * @see #setErrorHandler
+     */
+    public ErrorHandler getErrorHandler ();
+
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Parsing.
+    ////////////////////////////////////////////////////////////////////
+
+    /**
+     * Parse an XML document.
+     *
+     * <p>The application can use this method to instruct the XML
+     * reader to begin parsing an XML document from any valid input
+     * source (a character stream, a byte stream, or a URI).</p>
+     *
+     * <p>Applications may not invoke this method while a parse is in
+     * progress (they should create a new XMLReader instead for each
+     * nested XML document).  Once a parse is complete, an
+     * application may reuse the same XMLReader object, possibly with a
+     * different input source.
+     * Configuration of the XMLReader object (such as handler bindings and
+     * values established for feature flags and properties) is unchanged
+     * by completion of a parse, unless the definition of that aspect of
+     * the configuration explicitly specifies other behavior.
+     * (For example, feature flags or properties exposing
+     * characteristics of the document being parsed.)
+     * </p>
+     *
+     * <p>During the parse, the XMLReader will provide information
+     * about the XML document through the registered event
+     * handlers.</p>
+     *
+     * <p>This method is synchronous: it will not return until parsing
+     * has ended.  If a client application wants to terminate
+     * parsing early, it should throw an exception.</p>
+     *
+     * @param input The input source for the top-level of the
+     *        XML document.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @exception java.io.IOException An IO exception from the parser,
+     *            possibly from a byte stream or character stream
+     *            supplied by the application.
+     * @see org.xml.sax.InputSource
+     * @see #parse(java.lang.String)
+     * @see #setEntityResolver
+     * @see #setDTDHandler
+     * @see #setContentHandler
+     * @see #setErrorHandler
+     */
+    public void parse (InputSource input)
+        throws IOException, SAXException;
+
+
+    /**
+     * Parse an XML document from a system identifier (URI).
+     *
+     * <p>This method is a shortcut for the common case of reading a
+     * document from a system identifier.  It is the exact
+     * equivalent of the following:</p>
+     *
+     * <pre>
+     * parse(new InputSource(systemId));
+     * </pre>
+     *
+     * <p>If the system identifier is a URL, it must be fully resolved
+     * by the application before it is passed to the parser.</p>
+     *
+     * @param systemId The system identifier (URI).
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @exception java.io.IOException An IO exception from the parser,
+     *            possibly from a byte stream or character stream
+     *            supplied by the application.
+     * @see #parse(org.xml.sax.InputSource)
+     */
+    public void parse (String systemId)
+        throws IOException, SAXException;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/jdk/internal/org/xml/sax/helpers/DefaultHandler.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,491 @@
+/*
+ * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// DefaultHandler.java - default implementation of the core handlers.
+// http://www.saxproject.org
+// Written by David Megginson
+// NO WARRANTY!  This class is in the public domain.
+// $Id: DefaultHandler.java,v 1.3 2006/04/13 02:06:32 jeffsuttor Exp $
+
+package jdk.internal.org.xml.sax.helpers;
+
+import java.io.IOException;
+
+import jdk.internal.org.xml.sax.InputSource;
+import jdk.internal.org.xml.sax.Locator;
+import jdk.internal.org.xml.sax.Attributes;
+import jdk.internal.org.xml.sax.EntityResolver;
+import jdk.internal.org.xml.sax.DTDHandler;
+import jdk.internal.org.xml.sax.ContentHandler;
+import jdk.internal.org.xml.sax.ErrorHandler;
+import jdk.internal.org.xml.sax.SAXException;
+import jdk.internal.org.xml.sax.SAXParseException;
+
+
+/**
+ * Default base class for SAX2 event handlers.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>This class is available as a convenience base class for SAX2
+ * applications: it provides default implementations for all of the
+ * callbacks in the four core SAX2 handler classes:</p>
+ *
+ * <ul>
+ * <li>{@link org.xml.sax.EntityResolver EntityResolver}</li>
+ * <li>{@link org.xml.sax.DTDHandler DTDHandler}</li>
+ * <li>{@link org.xml.sax.ContentHandler ContentHandler}</li>
+ * <li>{@link org.xml.sax.ErrorHandler ErrorHandler}</li>
+ * </ul>
+ *
+ * <p>Application writers can extend this class when they need to
+ * implement only part of an interface; parser writers can
+ * instantiate this class to provide default handlers when the
+ * application has not supplied its own.</p>
+ *
+ * <p>This class replaces the deprecated SAX1
+ * {@link org.xml.sax.HandlerBase HandlerBase} class.</p>
+ *
+ * @since SAX 2.0
+ * @author David Megginson,
+ * @see org.xml.sax.EntityResolver
+ * @see org.xml.sax.DTDHandler
+ * @see org.xml.sax.ContentHandler
+ * @see org.xml.sax.ErrorHandler
+ */
+public class DefaultHandler
+    implements EntityResolver, DTDHandler, ContentHandler, ErrorHandler
+{
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Default implementation of the EntityResolver interface.
+    ////////////////////////////////////////////////////////////////////
+
+    /**
+     * Resolve an external entity.
+     *
+     * <p>Always return null, so that the parser will use the system
+     * identifier provided in the XML document.  This method implements
+     * the SAX default behaviour: application writers can override it
+     * in a subclass to do special translations such as catalog lookups
+     * or URI redirection.</p>
+     *
+     * @param publicId The public identifier, or null if none is
+     *                 available.
+     * @param systemId The system identifier provided in the XML
+     *                 document.
+     * @return The new input source, or null to require the
+     *         default behaviour.
+     * @exception java.io.IOException If there is an error setting
+     *            up the new input source.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.EntityResolver#resolveEntity
+     */
+    public InputSource resolveEntity (String publicId, String systemId)
+        throws IOException, SAXException
+    {
+        return null;
+    }
+
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Default implementation of DTDHandler interface.
+    ////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Receive notification of a notation declaration.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method in a subclass if they wish to keep track of the notations
+     * declared in a document.</p>
+     *
+     * @param name The notation name.
+     * @param publicId The notation public identifier, or null if not
+     *                 available.
+     * @param systemId The notation system identifier.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.DTDHandler#notationDecl
+     */
+    public void notationDecl (String name, String publicId, String systemId)
+        throws SAXException
+    {
+        // no op
+    }
+
+
+    /**
+     * Receive notification of an unparsed entity declaration.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method in a subclass to keep track of the unparsed entities
+     * declared in a document.</p>
+     *
+     * @param name The entity name.
+     * @param publicId The entity public identifier, or null if not
+     *                 available.
+     * @param systemId The entity system identifier.
+     * @param notationName The name of the associated notation.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.DTDHandler#unparsedEntityDecl
+     */
+    public void unparsedEntityDecl (String name, String publicId,
+                                    String systemId, String notationName)
+        throws SAXException
+    {
+        // no op
+    }
+
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Default implementation of ContentHandler interface.
+    ////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Receive a Locator object for document events.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method in a subclass if they wish to store the locator for use
+     * with other document events.</p>
+     *
+     * @param locator A locator for all SAX document events.
+     * @see org.xml.sax.ContentHandler#setDocumentLocator
+     * @see org.xml.sax.Locator
+     */
+    public void setDocumentLocator (Locator locator)
+    {
+        // no op
+    }
+
+
+    /**
+     * Receive notification of the beginning of the document.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method in a subclass to take specific actions at the beginning
+     * of a document (such as allocating the root node of a tree or
+     * creating an output file).</p>
+     *
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.ContentHandler#startDocument
+     */
+    public void startDocument ()
+        throws SAXException
+    {
+        // no op
+    }
+
+
+    /**
+     * Receive notification of the end of the document.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method in a subclass to take specific actions at the end
+     * of a document (such as finalising a tree or closing an output
+     * file).</p>
+     *
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.ContentHandler#endDocument
+     */
+    public void endDocument ()
+        throws SAXException
+    {
+        // no op
+    }
+
+
+    /**
+     * Receive notification of the start of a Namespace mapping.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method in a subclass to take specific actions at the start of
+     * each Namespace prefix scope (such as storing the prefix mapping).</p>
+     *
+     * @param prefix The Namespace prefix being declared.
+     * @param uri The Namespace URI mapped to the prefix.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.ContentHandler#startPrefixMapping
+     */
+    public void startPrefixMapping (String prefix, String uri)
+        throws SAXException
+    {
+        // no op
+    }
+
+
+    /**
+     * Receive notification of the end of a Namespace mapping.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method in a subclass to take specific actions at the end of
+     * each prefix mapping.</p>
+     *
+     * @param prefix The Namespace prefix being declared.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.ContentHandler#endPrefixMapping
+     */
+    public void endPrefixMapping (String prefix)
+        throws SAXException
+    {
+        // no op
+    }
+
+
+    /**
+     * Receive notification of the start of an element.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method in a subclass to take specific actions at the start of
+     * each element (such as allocating a new tree node or writing
+     * output to a file).</p>
+     *
+     * @param uri The Namespace URI, or the empty string if the
+     *        element has no Namespace URI or if Namespace
+     *        processing is not being performed.
+     * @param localName The local name (without prefix), or the
+     *        empty string if Namespace processing is not being
+     *        performed.
+     * @param qName The qualified name (with prefix), or the
+     *        empty string if qualified names are not available.
+     * @param attributes The attributes attached to the element.  If
+     *        there are no attributes, it shall be an empty
+     *        Attributes object.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.ContentHandler#startElement
+     */
+    public void startElement (String uri, String localName,
+                              String qName, Attributes attributes)
+        throws SAXException
+    {
+        // no op
+    }
+
+
+    /**
+     * Receive notification of the end of an element.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method in a subclass to take specific actions at the end of
+     * each element (such as finalising a tree node or writing
+     * output to a file).</p>
+     *
+     * @param uri The Namespace URI, or the empty string if the
+     *        element has no Namespace URI or if Namespace
+     *        processing is not being performed.
+     * @param localName The local name (without prefix), or the
+     *        empty string if Namespace processing is not being
+     *        performed.
+     * @param qName The qualified name (with prefix), or the
+     *        empty string if qualified names are not available.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.ContentHandler#endElement
+     */
+    public void endElement (String uri, String localName, String qName)
+        throws SAXException
+    {
+        // no op
+    }
+
+
+    /**
+     * Receive notification of character data inside an element.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method to take specific actions for each chunk of character data
+     * (such as adding the data to a node or buffer, or printing it to
+     * a file).</p>
+     *
+     * @param ch The characters.
+     * @param start The start position in the character array.
+     * @param length The number of characters to use from the
+     *               character array.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.ContentHandler#characters
+     */
+    public void characters (char ch[], int start, int length)
+        throws SAXException
+    {
+        // no op
+    }
+
+
+    /**
+     * Receive notification of ignorable whitespace in element content.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method to take specific actions for each chunk of ignorable
+     * whitespace (such as adding data to a node or buffer, or printing
+     * it to a file).</p>
+     *
+     * @param ch The whitespace characters.
+     * @param start The start position in the character array.
+     * @param length The number of characters to use from the
+     *               character array.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.ContentHandler#ignorableWhitespace
+     */
+    public void ignorableWhitespace (char ch[], int start, int length)
+        throws SAXException
+    {
+        // no op
+    }
+
+
+    /**
+     * Receive notification of a processing instruction.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method in a subclass to take specific actions for each
+     * processing instruction, such as setting status variables or
+     * invoking other methods.</p>
+     *
+     * @param target The processing instruction target.
+     * @param data The processing instruction data, or null if
+     *             none is supplied.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.ContentHandler#processingInstruction
+     */
+    public void processingInstruction (String target, String data)
+        throws SAXException
+    {
+        // no op
+    }
+
+
+    /**
+     * Receive notification of a skipped entity.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method in a subclass to take specific actions for each
+     * processing instruction, such as setting status variables or
+     * invoking other methods.</p>
+     *
+     * @param name The name of the skipped entity.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.ContentHandler#processingInstruction
+     */
+    public void skippedEntity (String name)
+        throws SAXException
+    {
+        // no op
+    }
+
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Default implementation of the ErrorHandler interface.
+    ////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Receive notification of a parser warning.
+     *
+     * <p>The default implementation does nothing.  Application writers
+     * may override this method in a subclass to take specific actions
+     * for each warning, such as inserting the message in a log file or
+     * printing it to the console.</p>
+     *
+     * @param e The warning information encoded as an exception.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.ErrorHandler#warning
+     * @see org.xml.sax.SAXParseException
+     */
+    public void warning (SAXParseException e)
+        throws SAXException
+    {
+        // no op
+    }
+
+
+    /**
+     * Receive notification of a recoverable parser error.
+     *
+     * <p>The default implementation does nothing.  Application writers
+     * may override this method in a subclass to take specific actions
+     * for each error, such as inserting the message in a log file or
+     * printing it to the console.</p>
+     *
+     * @param e The error information encoded as an exception.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.ErrorHandler#warning
+     * @see org.xml.sax.SAXParseException
+     */
+    public void error (SAXParseException e)
+        throws SAXException
+    {
+        // no op
+    }
+
+
+    /**
+     * Report a fatal XML parsing error.
+     *
+     * <p>The default implementation throws a SAXParseException.
+     * Application writers may override this method in a subclass if
+     * they need to take specific actions for each fatal error (such as
+     * collecting all of the errors into a single report): in any case,
+     * the application must stop all regular processing when this
+     * method is invoked, since the document is no longer reliable, and
+     * the parser may no longer report parsing events.</p>
+     *
+     * @param e The error information encoded as an exception.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.ErrorHandler#fatalError
+     * @see org.xml.sax.SAXParseException
+     */
+    public void fatalError (SAXParseException e)
+        throws SAXException
+    {
+        throw e;
+    }
+
+}
+
+// end of DefaultHandler.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/jdk/internal/util/xml/BasicXmlPropertiesProvider.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.util.xml;
+
+import java.util.Properties;
+import java.util.InvalidPropertiesFormatException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+
+import sun.util.spi.XmlPropertiesProvider;
+
+/**
+ * A {@code XmlPropertiesProvider} implementation that uses the UKit XML parser.
+ */
+
+public class BasicXmlPropertiesProvider extends XmlPropertiesProvider {
+
+    public BasicXmlPropertiesProvider() { }
+
+    @Override
+    public void load(Properties props, InputStream in)
+        throws IOException, InvalidPropertiesFormatException
+    {
+        PropertiesDefaultHandler handler = new PropertiesDefaultHandler();
+        handler.load(props, in);
+    }
+
+    @Override
+    public void store(Properties props, OutputStream os, String comment,
+                      String encoding)
+        throws IOException
+    {
+        PropertiesDefaultHandler handler = new PropertiesDefaultHandler();
+        handler.store(props, os, comment, encoding);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/jdk/internal/util/xml/PropertiesDefaultHandler.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.util.xml;
+
+import java.io.*;
+import java.util.InvalidPropertiesFormatException;
+import java.util.Properties;
+import jdk.internal.org.xml.sax.Attributes;
+import jdk.internal.org.xml.sax.InputSource;
+import jdk.internal.org.xml.sax.SAXException;
+import jdk.internal.org.xml.sax.SAXParseException;
+import jdk.internal.org.xml.sax.helpers.DefaultHandler;
+import jdk.internal.util.xml.impl.SAXParserImpl;
+import jdk.internal.util.xml.impl.XMLStreamWriterImpl;
+
+/**
+ * A class used to aid in Properties load and save in XML. This class is
+ * re-implemented using a subset of SAX
+ *
+ * @author Joe Wang
+ * @since 8
+ */
+public class PropertiesDefaultHandler extends DefaultHandler {
+
+    // Elements specified in the properties.dtd
+    private static final String ELEMENT_ROOT = "properties";
+    private static final String ELEMENT_COMMENT = "comment";
+    private static final String ELEMENT_ENTRY = "entry";
+    private static final String ATTR_KEY = "key";
+    // The required DTD URI for exported properties
+    private static final String PROPS_DTD_DECL =
+            "<!DOCTYPE properties SYSTEM \"http://java.sun.com/dtd/properties.dtd\">";
+    private static final String PROPS_DTD_URI =
+            "http://java.sun.com/dtd/properties.dtd";
+    private static final String PROPS_DTD =
+            "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+            + "<!-- DTD for properties -->"
+            + "<!ELEMENT properties ( comment?, entry* ) >"
+            + "<!ATTLIST properties"
+            + " version CDATA #FIXED \"1.0\">"
+            + "<!ELEMENT comment (#PCDATA) >"
+            + "<!ELEMENT entry (#PCDATA) >"
+            + "<!ATTLIST entry "
+            + " key CDATA #REQUIRED>";
+    /**
+     * Version number for the format of exported properties files.
+     */
+    private static final String EXTERNAL_XML_VERSION = "1.0";
+    private Properties properties;
+
+    public void load(Properties props, InputStream in)
+        throws IOException, InvalidPropertiesFormatException, UnsupportedEncodingException
+    {
+        this.properties = props;
+
+        try {
+            SAXParser parser = new SAXParserImpl();
+            parser.parse(in, this);
+        } catch (SAXException saxe) {
+            throw new InvalidPropertiesFormatException(saxe);
+        }
+
+        /**
+         * String xmlVersion = propertiesElement.getAttribute("version"); if
+         * (xmlVersion.compareTo(EXTERNAL_XML_VERSION) > 0) throw new
+         * InvalidPropertiesFormatException( "Exported Properties file format
+         * version " + xmlVersion + " is not supported. This java installation
+         * can read" + " versions " + EXTERNAL_XML_VERSION + " or older. You" +
+         * " may need to install a newer version of JDK.");
+         */
+    }
+
+    public void store(Properties props, OutputStream os, String comment, String encoding)
+        throws IOException
+    {
+        try {
+            XMLStreamWriter writer = new XMLStreamWriterImpl(os, encoding);
+            writer.writeStartDocument();
+            writer.writeDTD(PROPS_DTD_DECL);
+            writer.writeStartElement(ELEMENT_ROOT);
+            if (comment != null && comment.length() > 0) {
+                writer.writeStartElement(ELEMENT_COMMENT);
+                writer.writeCharacters(comment);
+                writer.writeEndElement();
+            }
+
+            for (String key : props.stringPropertyNames()) {
+                String val = props.getProperty(key);
+                writer.writeStartElement(ELEMENT_ENTRY);
+                writer.writeAttribute(ATTR_KEY, key);
+                writer.writeCharacters(val);
+                writer.writeEndElement();
+            }
+
+            writer.writeEndElement();
+            writer.writeEndDocument();
+            writer.close();
+        } catch (XMLStreamException e) {
+            if (e.getCause() instanceof UnsupportedEncodingException) {
+                throw (UnsupportedEncodingException) e.getCause();
+            }
+            throw new IOException(e);
+        }
+
+    }
+    ////////////////////////////////////////////////////////////////////
+    // Validate while parsing
+    ////////////////////////////////////////////////////////////////////
+    final static String ALLOWED_ELEMENTS = "properties, comment, entry";
+    final static String ALLOWED_COMMENT = "comment";
+    ////////////////////////////////////////////////////////////////////
+    // Handler methods
+    ////////////////////////////////////////////////////////////////////
+    StringBuffer buf = new StringBuffer();
+    boolean sawComment = false;
+    boolean validEntry = false;
+    int rootElem = 0;
+    String key;
+    String rootElm;
+
+    @Override
+    public void startElement(String uri, String localName, String qName, Attributes attributes)
+        throws SAXException
+    {
+        if (rootElem < 2) {
+            rootElem++;
+        }
+
+        if (rootElm == null) {
+            fatalError(new SAXParseException("An XML properties document must contain"
+                    + " the DOCTYPE declaration as defined by java.util.Properties.", null));
+        }
+
+        if (rootElem == 1 && !rootElm.equals(qName)) {
+            fatalError(new SAXParseException("Document root element \"" + qName
+                    + "\", must match DOCTYPE root \"" + rootElm + "\"", null));
+        }
+        if (!ALLOWED_ELEMENTS.contains(qName)) {
+            fatalError(new SAXParseException("Element type \"" + qName + "\" must be declared.", null));
+        }
+        if (qName.equals(ELEMENT_ENTRY)) {
+            validEntry = true;
+            key = attributes.getValue(ATTR_KEY);
+            if (key == null) {
+                fatalError(new SAXParseException("Attribute \"key\" is required and must be specified for element type \"entry\"", null));
+            }
+        } else if (qName.equals(ALLOWED_COMMENT)) {
+            if (sawComment) {
+                fatalError(new SAXParseException("Only one comment element may be allowed. "
+                        + "The content of element type \"properties\" must match \"(comment?,entry*)\"", null));
+            }
+            sawComment = true;
+        }
+    }
+
+    @Override
+    public void characters(char[] ch, int start, int length) throws SAXException {
+        if (validEntry) {
+            buf.append(ch, start, length);
+        }
+    }
+
+    @Override
+    public void endElement(String uri, String localName, String qName) throws SAXException {
+        if (!ALLOWED_ELEMENTS.contains(qName)) {
+            fatalError(new SAXParseException("Element: " + qName + " is invalid, must match  \"(comment?,entry*)\".", null));
+        }
+
+        if (validEntry) {
+            properties.setProperty(key, buf.toString());
+            buf.delete(0, buf.length());
+            validEntry = false;
+        }
+    }
+
+    @Override
+    public void notationDecl(String name, String publicId, String systemId) throws SAXException {
+        rootElm = name;
+    }
+
+    @Override
+    public InputSource resolveEntity(String pubid, String sysid)
+            throws SAXException, IOException {
+        {
+            if (sysid.equals(PROPS_DTD_URI)) {
+                InputSource is;
+                is = new InputSource(new StringReader(PROPS_DTD));
+                is.setSystemId(PROPS_DTD_URI);
+                return is;
+            }
+            throw new SAXException("Invalid system identifier: " + sysid);
+        }
+    }
+
+    @Override
+    public void error(SAXParseException x) throws SAXException {
+        throw x;
+    }
+
+    @Override
+    public void fatalError(SAXParseException x) throws SAXException {
+        throw x;
+    }
+
+    @Override
+    public void warning(SAXParseException x) throws SAXException {
+        throw x;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/jdk/internal/util/xml/SAXParser.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.util.xml;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import jdk.internal.org.xml.sax.InputSource;
+import jdk.internal.org.xml.sax.SAXException;
+import jdk.internal.org.xml.sax.XMLReader;
+import jdk.internal.org.xml.sax.helpers.DefaultHandler;
+
+
+/**
+ * Defines the API that wraps an {@link org.xml.sax.XMLReader}
+ * implementation class. In JAXP 1.0, this class wrapped the
+ * {@link org.xml.sax.Parser} interface, however this interface was
+ * replaced by the {@link org.xml.sax.XMLReader}. For ease
+ * of transition, this class continues to support the same name
+ * and interface as well as supporting new methods.
+ *
+ * An instance of this class can be obtained from the
+ * {@link javax.xml.parsers.SAXParserFactory#newSAXParser()} method.
+ * Once an instance of this class is obtained, XML can be parsed from
+ * a variety of input sources. These input sources are InputStreams,
+ * Files, URLs, and SAX InputSources.<p>
+ *
+ * This static method creates a new factory instance based
+ * on a system property setting or uses the platform default
+ * if no property has been defined.<p>
+ *
+ * The system property that controls which Factory implementation
+ * to create is named <code>&quot;javax.xml.parsers.SAXParserFactory&quot;</code>.
+ * This property names a class that is a concrete subclass of this
+ * abstract class. If no property is defined, a platform default
+ * will be used.</p>
+ *
+ * As the content is parsed by the underlying parser, methods of the
+ * given
+ * {@link org.xml.sax.helpers.DefaultHandler} are called.<p>
+ *
+ * Implementors of this class which wrap an underlaying implementation
+ * can consider using the {@link org.xml.sax.helpers.ParserAdapter}
+ * class to initially adapt their SAX1 implementation to work under
+ * this revised class.
+ *
+ * @author <a href="mailto:Jeff.Suttor@Sun.com">Jeff Suttor</a>
+ * @version $Revision: 1.8 $, $Date: 2010-11-01 04:36:09 $
+ *
+ * @author Joe Wang
+ * This is a subset of that in JAXP, javax.xml.parsers.SAXParser
+ *
+ */
+public abstract class SAXParser {
+
+    /**
+     * <p>Protected constructor to prevent instantiation.</p>
+     */
+    protected SAXParser() {
+    }
+
+    /**
+     * Parse the content of the given {@link java.io.InputStream}
+     * instance as XML using the specified
+     * {@link org.xml.sax.helpers.DefaultHandler}.
+     *
+     * @param is InputStream containing the content to be parsed.
+     * @param dh The SAX DefaultHandler to use.
+     *
+     * @throws IllegalArgumentException If the given InputStream is null.
+     * @throws IOException If any IO errors occur.
+     * @throws SAXException If any SAX errors occur during processing.
+     *
+     * @see org.xml.sax.DocumentHandler
+     */
+    public void parse(InputStream is, DefaultHandler dh)
+        throws SAXException, IOException
+    {
+        if (is == null) {
+            throw new IllegalArgumentException("InputStream cannot be null");
+        }
+
+        InputSource input = new InputSource(is);
+        this.parse(input, dh);
+    }
+
+    /**
+     * Parse the content described by the giving Uniform Resource
+     * Identifier (URI) as XML using the specified
+     * {@link org.xml.sax.helpers.DefaultHandler}.
+     *
+     * @param uri The location of the content to be parsed.
+     * @param dh The SAX DefaultHandler to use.
+     *
+     * @throws IllegalArgumentException If the uri is null.
+     * @throws IOException If any IO errors occur.
+     * @throws SAXException If any SAX errors occur during processing.
+     *
+     * @see org.xml.sax.DocumentHandler
+     */
+    public void parse(String uri, DefaultHandler dh)
+        throws SAXException, IOException
+    {
+        if (uri == null) {
+            throw new IllegalArgumentException("uri cannot be null");
+        }
+
+        InputSource input = new InputSource(uri);
+        this.parse(input, dh);
+    }
+
+    /**
+     * Parse the content of the file specified as XML using the
+     * specified {@link org.xml.sax.helpers.DefaultHandler}.
+     *
+     * @param f The file containing the XML to parse
+     * @param dh The SAX DefaultHandler to use.
+     *
+     * @throws IllegalArgumentException If the File object is null.
+     * @throws IOException If any IO errors occur.
+     * @throws SAXException If any SAX errors occur during processing.
+     *
+     * @see org.xml.sax.DocumentHandler
+     */
+    public void parse(File f, DefaultHandler dh)
+        throws SAXException, IOException
+    {
+        if (f == null) {
+            throw new IllegalArgumentException("File cannot be null");
+        }
+
+        //convert file to appropriate URI, f.toURI().toASCIIString()
+        //converts the URI to string as per rule specified in
+        //RFC 2396,
+        InputSource input = new InputSource(f.toURI().toASCIIString());
+        this.parse(input, dh);
+    }
+
+    /**
+     * Parse the content given {@link org.xml.sax.InputSource}
+     * as XML using the specified
+     * {@link org.xml.sax.helpers.DefaultHandler}.
+     *
+     * @param is The InputSource containing the content to be parsed.
+     * @param dh The SAX DefaultHandler to use.
+     *
+     * @throws IllegalArgumentException If the <code>InputSource</code> object
+     *   is <code>null</code>.
+     * @throws IOException If any IO errors occur.
+     * @throws SAXException If any SAX errors occur during processing.
+     *
+     * @see org.xml.sax.DocumentHandler
+     */
+    public void parse(InputSource is, DefaultHandler dh)
+        throws SAXException, IOException
+    {
+        if (is == null) {
+            throw new IllegalArgumentException("InputSource cannot be null");
+        }
+
+        XMLReader reader = this.getXMLReader();
+        if (dh != null) {
+            reader.setContentHandler(dh);
+            reader.setEntityResolver(dh);
+            reader.setErrorHandler(dh);
+            reader.setDTDHandler(dh);
+        }
+        reader.parse(is);
+    }
+
+    /**
+     * Returns the {@link org.xml.sax.XMLReader} that is encapsulated by the
+     * implementation of this class.
+     *
+     * @return The XMLReader that is encapsulated by the
+     *         implementation of this class.
+     *
+     * @throws SAXException If any SAX errors occur during processing.
+     */
+    public abstract XMLReader getXMLReader() throws SAXException;
+
+    /**
+     * Indicates whether or not this parser is configured to
+     * understand namespaces.
+     *
+     * @return true if this parser is configured to
+     *         understand namespaces; false otherwise.
+     */
+    public abstract boolean isNamespaceAware();
+
+    /**
+     * Indicates whether or not this parser is configured to
+     * validate XML documents.
+     *
+     * @return true if this parser is configured to
+     *         validate XML documents; false otherwise.
+     */
+    public abstract boolean isValidating();
+
+    /**
+     * <p>Get the XInclude processing mode for this parser.</p>
+     *
+     * @return
+     *      the return value of
+     *      the {@link SAXParserFactory#isXIncludeAware()}
+     *      when this parser was created from factory.
+     *
+     * @throws UnsupportedOperationException When implementation does not
+     *   override this method
+     *
+     * @since 1.5
+     *
+     * @see SAXParserFactory#setXIncludeAware(boolean)
+     */
+    public boolean isXIncludeAware() {
+        throw new UnsupportedOperationException(
+                "This parser does not support specification \""
+                + this.getClass().getPackage().getSpecificationTitle()
+                + "\" version \""
+                + this.getClass().getPackage().getSpecificationVersion()
+                + "\"");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/jdk/internal/util/xml/XMLStreamException.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.util.xml;
+
+/**
+ * A copy of the StAX XMLStreamException without Location support
+ *
+ * The base exception for unexpected processing errors.  This Exception
+ * class is used to report well-formedness errors as well as unexpected
+ * processing conditions.
+ * @version 1.0
+ * @author Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
+ * @since 1.6
+ */
+
+public class XMLStreamException extends Exception {
+    private static final long serialVersionUID = 1L;
+
+
+    protected Throwable nested;
+
+    /**
+     * Default constructor
+     */
+    public XMLStreamException() {
+        super();
+    }
+
+    /**
+     * Construct an exception with the assocated message.
+     *
+     * @param msg the message to report
+     */
+    public XMLStreamException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Construct an exception with the assocated exception
+     *
+     * @param th a nested exception
+     */
+    public XMLStreamException(Throwable th) {
+        super(th);
+        nested = th;
+    }
+
+    /**
+     * Construct an exception with the assocated message and exception
+     *
+     * @param th a nested exception
+     * @param msg the message to report
+     */
+    public XMLStreamException(String msg, Throwable th) {
+        super(msg, th);
+        nested = th;
+    }
+
+    /**
+     * Gets the nested exception.
+     *
+     * @return Nested exception
+     */
+    public Throwable getNestedException() {
+        return nested;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/jdk/internal/util/xml/XMLStreamWriter.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.util.xml;
+
+/**
+ * Basic XMLStreamWriter for writing simple XML files such as those
+ * defined in java.util.Properties
+ *
+ * This is a subset of javax.xml.stream.XMLStreamWriter
+ *
+ * @author Joe Wang
+ */
+public  interface XMLStreamWriter {
+
+    //Defaults the XML version to 1.0, and the encoding to utf-8
+    public final static String DEFAULT_XML_VERSION = "1.0";
+    public final static String DEFAULT_ENCODING = "UTF-8";
+
+    /**
+     * Writes a start tag to the output.  All writeStartElement methods
+     * open a new scope in the internal namespace context.  Writing the
+     * corresponding EndElement causes the scope to be closed.
+     * @param localName local name of the tag, may not be null
+     * @throws XMLStreamException
+     */
+    public void writeStartElement(String localName) throws XMLStreamException;
+
+    /**
+     * Writes an empty element tag to the output
+     * @param localName local name of the tag, may not be null
+     * @throws XMLStreamException
+     */
+    public void writeEmptyElement(String localName) throws XMLStreamException;
+
+    /**
+     * Writes an end tag to the output relying on the internal
+     * state of the writer to determine the prefix and local name
+     * of the event.
+     * @throws XMLStreamException
+     */
+    public void writeEndElement() throws XMLStreamException;
+
+    /**
+     * Closes any start tags and writes corresponding end tags.
+     * @throws XMLStreamException
+     */
+    public void writeEndDocument() throws XMLStreamException;
+
+    /**
+     * Close this writer and free any resources associated with the
+     * writer.  This must not close the underlying output stream.
+     * @throws XMLStreamException
+     */
+    public void close() throws XMLStreamException;
+
+    /**
+     * Write any cached data to the underlying output mechanism.
+     * @throws XMLStreamException
+     */
+    public void flush() throws XMLStreamException;
+
+    /**
+     * Writes an attribute to the output stream without
+     * a prefix.
+     * @param localName the local name of the attribute
+     * @param value the value of the attribute
+     * @throws IllegalStateException if the current state does not allow Attribute writing
+     * @throws XMLStreamException
+     */
+    public void writeAttribute(String localName, String value)
+            throws XMLStreamException;
+
+    /**
+     * Writes a CData section
+     * @param data the data contained in the CData Section, may not be null
+     * @throws XMLStreamException
+     */
+    public void writeCData(String data) throws XMLStreamException;
+
+    /**
+     * Write a DTD section.  This string represents the entire doctypedecl production
+     * from the XML 1.0 specification.
+     *
+     * @param dtd the DTD to be written
+     * @throws XMLStreamException
+     */
+    public void writeDTD(String dtd) throws XMLStreamException;
+
+    /**
+     * Write the XML Declaration. Defaults the XML version to 1.0, and the encoding to utf-8
+     * @throws XMLStreamException
+     */
+    public void writeStartDocument() throws XMLStreamException;
+
+    /**
+     * Write the XML Declaration. Defaults the the encoding to utf-8
+     * @param version version of the xml document
+     * @throws XMLStreamException
+     */
+    public void writeStartDocument(String version) throws XMLStreamException;
+
+    /**
+     * Write the XML Declaration.  Note that the encoding parameter does
+     * not set the actual encoding of the underlying output.  That must
+     * be set when the instance of the XMLStreamWriter is created using the
+     * XMLOutputFactory
+     * @param encoding encoding of the xml declaration
+     * @param version version of the xml document
+     * @throws XMLStreamException If given encoding does not match encoding
+     * of the underlying stream
+     */
+    public void writeStartDocument(String encoding, String version)
+        throws XMLStreamException;
+
+    /**
+     * Write text to the output
+     * @param text the value to write
+     * @throws XMLStreamException
+     */
+    public void writeCharacters(String text) throws XMLStreamException;
+
+    /**
+     * Write text to the output
+     * @param text the value to write
+     * @param start the starting position in the array
+     * @param len the number of characters to write
+     * @throws XMLStreamException
+     */
+    public void writeCharacters(char[] text, int start, int len)
+        throws XMLStreamException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/jdk/internal/util/xml/impl/Attrs.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,430 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.util.xml.impl;
+
+import jdk.internal.org.xml.sax.Attributes;
+
+public class Attrs implements Attributes {
+
+    /**
+     * Attributes string array. Each individual attribute is represented by four
+     * strings: namespace URL(+0), qname(+1), local name(+2), value(+3),
+     * type(+4), declared["d"] and default["D"](+5). In order to find attribute
+     * by the attrubute index, the attribute index MUST be multiplied by 8. The
+     * result will point to the attribute namespace URL.
+     */
+    /* pkg */ String[] mItems;
+    /**
+     * Number of attributes in the attributes string array.
+     */
+    private char mLength;
+    /**
+     * current index
+     */
+    private char mAttrIdx = 0;
+
+    /**
+     * Constructor.
+     */
+    public Attrs() {
+        //              The default number of attributies capacity is 8.
+        mItems = new String[(8 << 3)];
+    }
+
+    /**
+     * Sets up the number of attributes and ensure the capacity of the attribute
+     * string array.
+     *
+     * @param length The number of attributes in the object.
+     */
+    public void setLength(char length) {
+        if (length > ((char) (mItems.length >> 3))) {
+            mItems = new String[length << 3];
+        }
+        mLength = length;
+    }
+
+    /**
+     * Return the number of attributes in the list.
+     *
+     * <p>Once you know the number of attributes, you can iterate through the
+     * list.</p>
+     *
+     * @return The number of attributes in the list.
+     * @see #getURI(int)
+     * @see #getLocalName(int)
+     * @see #getQName(int)
+     * @see #getType(int)
+     * @see #getValue(int)
+     */
+    public int getLength() {
+        return mLength;
+    }
+
+    /**
+     * Look up an attribute's Namespace URI by index.
+     *
+     * @param index The attribute index (zero-based).
+     * @return The Namespace URI, or the empty string if none is available, or
+     * null if the index is out of range.
+     * @see #getLength
+     */
+    public String getURI(int index) {
+        return ((index >= 0) && (index < mLength))
+                ? (mItems[index << 3])
+                : null;
+    }
+
+    /**
+     * Look up an attribute's local name by index.
+     *
+     * @param index The attribute index (zero-based).
+     * @return The local name, or the empty string if Namespace processing is
+     * not being performed, or null if the index is out of range.
+     * @see #getLength
+     */
+    public String getLocalName(int index) {
+        return ((index >= 0) && (index < mLength))
+                ? (mItems[(index << 3) + 2])
+                : null;
+    }
+
+    /**
+     * Look up an attribute's XML 1.0 qualified name by index.
+     *
+     * @param index The attribute index (zero-based).
+     * @return The XML 1.0 qualified name, or the empty string if none is
+     * available, or null if the index is out of range.
+     * @see #getLength
+     */
+    public String getQName(int index) {
+        if ((index < 0) || (index >= mLength)) {
+            return null;
+        }
+        return mItems[(index << 3) + 1];
+    }
+
+    /**
+     * Look up an attribute's type by index.
+     *
+     * <p>The attribute type is one of the strings "CDATA", "ID", "IDREF",
+     * "IDREFS", "NMTOKEN", "NMTOKENS", "ENTITY", "ENTITIES", or "NOTATION"
+     * (always in upper case).</p>
+     *
+     * <p>If the parser has not read a declaration for the attribute, or if the
+     * parser does not report attribute types, then it must return the value
+     * "CDATA" as stated in the XML 1.0 Recommentation (clause 3.3.3,
+     * "Attribute-Value Normalization").</p>
+     *
+     * <p>For an enumerated attribute that is not a notation, the parser will
+     * report the type as "NMTOKEN".</p>
+     *
+     * @param index The attribute index (zero-based).
+     * @return The attribute's type as a string, or null if the index is out of
+     * range.
+     * @see #getLength
+     */
+    public String getType(int index) {
+        return ((index >= 0) && (index < (mItems.length >> 3)))
+                ? (mItems[(index << 3) + 4])
+                : null;
+    }
+
+    /**
+     * Look up an attribute's value by index.
+     *
+     * <p>If the attribute value is a list of tokens (IDREFS, ENTITIES, or
+     * NMTOKENS), the tokens will be concatenated into a single string with each
+     * token separated by a single space.</p>
+     *
+     * @param index The attribute index (zero-based).
+     * @return The attribute's value as a string, or null if the index is out of
+     * range.
+     * @see #getLength
+     */
+    public String getValue(int index) {
+        return ((index >= 0) && (index < mLength))
+                ? (mItems[(index << 3) + 3])
+                : null;
+    }
+
+    /**
+     * Look up the index of an attribute by Namespace name.
+     *
+     * @param uri The Namespace URI, or the empty string if the name has no
+     * Namespace URI.
+     * @param localName The attribute's local name.
+     * @return The index of the attribute, or -1 if it does not appear in the
+     * list.
+     */
+    public int getIndex(String uri, String localName) {
+        char len = mLength;
+        for (char idx = 0; idx < len; idx++) {
+            if ((mItems[idx << 3]).equals(uri)
+                    && mItems[(idx << 3) + 2].equals(localName)) {
+                return idx;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Look up the index of an attribute by Namespace name.
+     *
+     * @param uri The Namespace URI, or the empty string if the name has no
+     * Namespace URI. <code>null</code> value enforce the search by the local
+     * name only.
+     * @param localName The attribute's local name.
+     * @return The index of the attribute, or -1 if it does not appear in the
+     * list.
+     */
+    /* pkg */ int getIndexNullNS(String uri, String localName) {
+        char len = mLength;
+        if (uri != null) {
+            for (char idx = 0; idx < len; idx++) {
+                if ((mItems[idx << 3]).equals(uri)
+                        && mItems[(idx << 3) + 2].equals(localName)) {
+                    return idx;
+                }
+            }
+        } else {
+            for (char idx = 0; idx < len; idx++) {
+                if (mItems[(idx << 3) + 2].equals(localName)) {
+                    return idx;
+                }
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Look up the index of an attribute by XML 1.0 qualified name.
+     *
+     * @param qName The qualified (prefixed) name.
+     * @return The index of the attribute, or -1 if it does not appear in the
+     * list.
+     */
+    public int getIndex(String qName) {
+        char len = mLength;
+        for (char idx = 0; idx < len; idx++) {
+            if (mItems[(idx << 3) + 1].equals(qName)) {
+                return idx;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Look up an attribute's type by Namespace name.
+     *
+     * <p>See {@link #getType(int) getType(int)} for a description of the
+     * possible types.</p>
+     *
+     * @param uri The Namespace URI, or the empty String if the name has no
+     * Namespace URI.
+     * @param localName The local name of the attribute.
+     * @return The attribute type as a string, or null if the attribute is not
+     * in the list or if Namespace processing is not being performed.
+     */
+    public String getType(String uri, String localName) {
+        int idx = getIndex(uri, localName);
+        return (idx >= 0) ? (mItems[(idx << 3) + 4]) : null;
+    }
+
+    /**
+     * Look up an attribute's type by XML 1.0 qualified name.
+     *
+     * <p>See {@link #getType(int) getType(int)} for a description of the
+     * possible types.</p>
+     *
+     * @param qName The XML 1.0 qualified name.
+     * @return The attribute type as a string, or null if the attribute is not
+     * in the list or if qualified names are not available.
+     */
+    public String getType(String qName) {
+        int idx = getIndex(qName);
+        return (idx >= 0) ? (mItems[(idx << 3) + 4]) : null;
+    }
+
+    /**
+     * Look up an attribute's value by Namespace name.
+     *
+     * <p>See {@link #getValue(int) getValue(int)} for a description of the
+     * possible values.</p>
+     *
+     * @param uri The Namespace URI, or the empty String if the name has no
+     * Namespace URI.
+     * @param localName The local name of the attribute.
+     * @return The attribute value as a string, or null if the attribute is not
+     * in the list.
+     */
+    public String getValue(String uri, String localName) {
+        int idx = getIndex(uri, localName);
+        return (idx >= 0) ? (mItems[(idx << 3) + 3]) : null;
+    }
+
+    /**
+     * Look up an attribute's value by XML 1.0 qualified name.
+     *
+     * <p>See {@link #getValue(int) getValue(int)} for a description of the
+     * possible values.</p>
+     *
+     * @param qName The XML 1.0 qualified name.
+     * @return The attribute value as a string, or null if the attribute is not
+     * in the list or if qualified names are not available.
+     */
+    public String getValue(String qName) {
+        int idx = getIndex(qName);
+        return (idx >= 0) ? (mItems[(idx << 3) + 3]) : null;
+    }
+
+    /**
+     * Returns false unless the attribute was declared in the DTD. This helps
+     * distinguish two kinds of attributes that SAX reports as CDATA: ones that
+     * were declared (and hence are usually valid), and those that were not (and
+     * which are never valid).
+     *
+     * @param index The attribute index (zero-based).
+     * @return true if the attribute was declared in the DTD, false otherwise.
+     * @exception java.lang.ArrayIndexOutOfBoundsException When the supplied
+     * index does not identify an attribute.
+     */
+    public boolean isDeclared(int index) {
+        if ((index < 0) || (index >= mLength)) {
+            throw new ArrayIndexOutOfBoundsException("");
+        }
+
+        return ((mItems[(index << 3) + 5]) != null);
+    }
+
+    /**
+     * Returns false unless the attribute was declared in the DTD. This helps
+     * distinguish two kinds of attributes that SAX reports as CDATA: ones that
+     * were declared (and hence are usually valid), and those that were not (and
+     * which are never valid).
+     *
+     * @param qName The XML qualified (prefixed) name.
+     * @return true if the attribute was declared in the DTD, false otherwise.
+     * @exception java.lang.IllegalArgumentException When the supplied name does
+     * not identify an attribute.
+     */
+    public boolean isDeclared(String qName) {
+        int idx = getIndex(qName);
+        if (idx < 0) {
+            throw new IllegalArgumentException("");
+        }
+
+        return ((mItems[(idx << 3) + 5]) != null);
+    }
+
+    /**
+     * Returns false unless the attribute was declared in the DTD. This helps
+     * distinguish two kinds of attributes that SAX reports as CDATA: ones that
+     * were declared (and hence are usually valid), and those that were not (and
+     * which are never valid).
+     *
+     * <p>Remember that since DTDs do not "understand" namespaces, the namespace
+     * URI associated with an attribute may not have come from the DTD. The
+     * declaration will have applied to the attribute's <em>qName</em>.
+     *
+     * @param uri The Namespace URI, or the empty string if the name has no
+     * Namespace URI.
+     * @param localName The attribute's local name.
+     * @return true if the attribute was declared in the DTD, false otherwise.
+     * @exception java.lang.IllegalArgumentException When the supplied names do
+     * not identify an attribute.
+     */
+    public boolean isDeclared(String uri, String localName) {
+        int idx = getIndex(uri, localName);
+        if (idx < 0) {
+            throw new IllegalArgumentException("");
+        }
+
+        return ((mItems[(idx << 3) + 5]) != null);
+    }
+
+    /**
+     * Returns true unless the attribute value was provided by DTD defaulting.
+     *
+     * @param index The attribute index (zero-based).
+     * @return true if the value was found in the XML text, false if the value
+     * was provided by DTD defaulting.
+     * @exception java.lang.ArrayIndexOutOfBoundsException When the supplied
+     * index does not identify an attribute.
+     */
+    public boolean isSpecified(int index) {
+        if ((index < 0) || (index >= mLength)) {
+            throw new ArrayIndexOutOfBoundsException("");
+        }
+
+        String str = mItems[(index << 3) + 5];
+        return ((str != null) ? (str.charAt(0) == 'd') : true);
+    }
+
+    /**
+     * Returns true unless the attribute value was provided by DTD defaulting.
+     *
+     * <p>Remember that since DTDs do not "understand" namespaces, the namespace
+     * URI associated with an attribute may not have come from the DTD. The
+     * declaration will have applied to the attribute's <em>qName</em>.
+     *
+     * @param uri The Namespace URI, or the empty string if the name has no
+     * Namespace URI.
+     * @param localName The attribute's local name.
+     * @return true if the value was found in the XML text, false if the value
+     * was provided by DTD defaulting.
+     * @exception java.lang.IllegalArgumentException When the supplied names do
+     * not identify an attribute.
+     */
+    public boolean isSpecified(String uri, String localName) {
+        int idx = getIndex(uri, localName);
+        if (idx < 0) {
+            throw new IllegalArgumentException("");
+        }
+
+        String str = mItems[(idx << 3) + 5];
+        return ((str != null) ? (str.charAt(0) == 'd') : true);
+    }
+
+    /**
+     * Returns true unless the attribute value was provided by DTD defaulting.
+     *
+     * @param qName The XML qualified (prefixed) name.
+     * @return true if the value was found in the XML text, false if the value
+     * was provided by DTD defaulting.
+     * @exception java.lang.IllegalArgumentException When the supplied name does
+     * not identify an attribute.
+     */
+    public boolean isSpecified(String qName) {
+        int idx = getIndex(qName);
+        if (idx < 0) {
+            throw new IllegalArgumentException("");
+        }
+
+        String str = mItems[(idx << 3) + 5];
+        return ((str != null) ? (str.charAt(0) == 'd') : true);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/jdk/internal/util/xml/impl/Input.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.util.xml.impl;
+
+import java.io.Reader;
+
+/**
+ * A parsed entity input state.
+ *
+ * This class represents a parsed entity input state. The parser uses
+ * an instance of this class to manage input.
+ */
+
+public class Input {
+
+    /** The entity public identifier or null. */
+    public String pubid;
+    /** The entity systen identifier or null. */
+    public String sysid;
+    /** The encoding from XML declaration or null */
+    public String xmlenc;
+    /** The XML version from XML declaration or 0x0000 */
+    public char xmlver;
+    /** The entity reader. */
+    public Reader src;
+    /** The character buffer. */
+    public char[] chars;
+    /** The length of the character buffer. */
+    public int chLen;
+    /** The index of the next character to read. */
+    public int chIdx;
+    /** The next input in a chain. */
+    public Input next;
+
+    /**
+     * Constructor.
+     *
+     * @param buffsize The input buffer size.
+     */
+    public Input(int buffsize) {
+        chars = new char[buffsize];
+        chLen = chars.length;
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param buff The input buffer.
+     */
+    public Input(char[] buff) {
+        chars = buff;
+        chLen = chars.length;
+    }
+
+    /**
+     * Constructor.
+     */
+    public Input() {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/jdk/internal/util/xml/impl/Pair.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.util.xml.impl;
+
+
+/**
+ * A name with value pair.
+ *
+ * This class keeps name with value pair with additional information and
+ * supports pair chaining.
+ */
+public class Pair {
+
+    /** The pair name. */
+    public String name;
+    /** The pair value. */
+    public String value;
+    /** The pair numeric value. */
+    public int num;
+    /** The characters of name. */
+    public char[] chars;
+    /** The pair identifier. */
+    public int id;
+    /** The list of associated pairs. */
+    public Pair list;
+    /** The next pair in a chain. */
+    public Pair next;
+
+    /**
+     * Creates a qualified name string from qualified name.
+     *
+     * @return The qualified name string.
+     */
+    public String qname() {
+        return new String(chars, 1, chars.length - 1);
+    }
+
+    /**
+     * Creates a local name string from qualified name.
+     *
+     * @return The local name string.
+     */
+    public String local() {
+        if (chars[0] != 0) {
+            return new String(chars, chars[0] + 1, chars.length - chars[0] - 1);
+        }
+        return new String(chars, 1, chars.length - 1);
+    }
+
+    /**
+     * Creates a prefix string from qualified name.
+     *
+     * @return The prefix string.
+     */
+    public String pref() {
+        if (chars[0] != 0) {
+            return new String(chars, 1, chars[0] - 1);
+        }
+        return "";
+    }
+
+    /**
+     * Compares two qualified name prefixes.
+     *
+     * @param qname A qualified name.
+     * @return true if prefixes are equal.
+     */
+    public boolean eqpref(char[] qname) {
+        if (chars[0] == qname[0]) {
+            char len = chars[0];
+            for (char i = 1; i < len; i += 1) {
+                if (chars[i] != qname[i]) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Compares two qualified names.
+     *
+     * @param qname A qualified name.
+     * @return true if qualified names are equal.
+     */
+    public boolean eqname(char[] qname) {
+        char len = (char) chars.length;
+        if (len == qname.length) {
+            for (char i = 0; i < len; i += 1) {
+                if (chars[i] != qname[i]) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/jdk/internal/util/xml/impl/Parser.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,3367 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.util.xml.impl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+import java.util.HashMap;
+import java.util.Map;
+import jdk.internal.org.xml.sax.InputSource;
+import jdk.internal.org.xml.sax.SAXException;
+
+/**
+ * XML non-validating parser engine.
+ */
+public abstract class Parser {
+
+    public final static String FAULT = "";
+    protected final static int BUFFSIZE_READER = 512;
+    protected final static int BUFFSIZE_PARSER = 128;
+    /**
+     * The end of stream character.
+     */
+    public final static char EOS = 0xffff;
+    private Pair mNoNS; // there is no namespace
+    private Pair mXml;  // the xml namespace
+    private Map<String, Input> mEnt;  // the entities look up table
+    private Map<String, Input> mPEnt; // the parmeter entities look up table
+    protected boolean mIsSAlone;     // xml decl standalone flag
+    protected boolean mIsSAloneSet;  // standalone is explicitely set
+    protected boolean mIsNSAware;    // if true - namespace aware mode
+    protected int mPh;  // current phase of document processing
+    protected final static int PH_BEFORE_DOC = -1;  // before parsing
+    protected final static int PH_DOC_START = 0;   // document start
+    protected final static int PH_MISC_DTD = 1;   // misc before DTD
+    protected final static int PH_DTD = 2;   // DTD
+    protected final static int PH_DTD_MISC = 3;   // misc after DTD
+    protected final static int PH_DOCELM = 4;   // document's element
+    protected final static int PH_DOCELM_MISC = 5;   // misc after element
+    protected final static int PH_AFTER_DOC = 6;   // after parsing
+    protected int mEvt;  // current event type
+    protected final static int EV_NULL = 0;   // unknown
+    protected final static int EV_ELM = 1;   // empty element
+    protected final static int EV_ELMS = 2;   // start element
+    protected final static int EV_ELME = 3;   // end element
+    protected final static int EV_TEXT = 4;   // textual content
+    protected final static int EV_WSPC = 5;   // white space content
+    protected final static int EV_PI = 6;   // processing instruction
+    protected final static int EV_CDAT = 7;   // character data
+    protected final static int EV_COMM = 8;   // comment
+    protected final static int EV_DTD = 9;   // document type definition
+    protected final static int EV_ENT = 10;  // skipped entity
+    private char mESt; // built-in entity recognizer state
+    // mESt values:
+    //   0x100   : the initial state
+    //   > 0x100 : unrecognized name
+    //   < 0x100 : replacement character
+    protected char[] mBuff;       // parser buffer
+    protected int mBuffIdx;    // index of the last char
+    protected Pair mPref;       // stack of prefixes
+    protected Pair mElm;        // stack of elements
+    // mAttL.chars - element qname
+    // mAttL.next  - next element
+    // mAttL.list  - list of attributes defined on this element
+    // mAttL.list.chars - attribute qname
+    // mAttL.list.id    - a char representing attribute's type see below
+    // mAttL.list.next  - next attribute defined on the element
+    // mAttL.list.list  - devault value structure or null
+    // mAttL.list.list.chars - "name='value' " chars array for Input
+    //
+    // Attribute type character values:
+    // 'i' - "ID"
+    // 'r' - "IDREF"
+    // 'R' - "IDREFS"
+    // 'n' - "ENTITY"
+    // 'N' - "ENTITIES"
+    // 't' - "NMTOKEN"
+    // 'T' - "NMTOKENS"
+    // 'u' - enumeration type
+    // 'o' - "NOTATION"
+    // 'c' - "CDATA"
+    // see also: bkeyword() and atype()
+    //
+    protected Pair mAttL;       // list of defined attrs by element name
+    protected Input mDoc;        // document entity
+    protected Input mInp;        // stack of entities
+    private char[] mChars;      // reading buffer
+    private int mChLen;      // current capacity
+    private int mChIdx;      // index to the next char
+    protected Attrs mAttrs;      // attributes of the curr. element
+    private String[] mItems;      // attributes array of the curr. element
+    private char mAttrIdx;    // attributes counter/index
+    private String mUnent;  // unresolved entity name
+    private Pair mDltd;   // deleted objects for reuse
+    /**
+     * Default prefixes
+     */
+    private final static char NONS[];
+    private final static char XML[];
+    private final static char XMLNS[];
+
+    static {
+        NONS = new char[1];
+        NONS[0] = (char) 0;
+
+        XML = new char[4];
+        XML[0] = (char) 4;
+        XML[1] = 'x';
+        XML[2] = 'm';
+        XML[3] = 'l';
+
+        XMLNS = new char[6];
+        XMLNS[0] = (char) 6;
+        XMLNS[1] = 'x';
+        XMLNS[2] = 'm';
+        XMLNS[3] = 'l';
+        XMLNS[4] = 'n';
+        XMLNS[5] = 's';
+    }
+    /**
+     * ASCII character type array.
+     *
+     * This array maps an ASCII (7 bit) character to the character type.<br />
+     * Possible character type values are:<br /> - ' ' for any kind of white
+     * space character;<br /> - 'a' for any lower case alphabetical character
+     * value;<br /> - 'A' for any upper case alphabetical character value;<br />
+     * - 'd' for any decimal digit character value;<br /> - 'z' for any
+     * character less then ' ' except '\t', '\n', '\r';<br /> An ASCII (7 bit)
+     * character which does not fall in any category listed above is mapped to
+     * it self.
+     */
+    private static final byte asctyp[];
+    /**
+     * NMTOKEN character type array.
+     *
+     * This array maps an ASCII (7 bit) character to the character type.<br />
+     * Possible character type values are:<br /> - 0 for underscore ('_') or any
+     * lower and upper case alphabetical character value;<br /> - 1 for colon
+     * (':') character;<br /> - 2 for dash ('-') and dot ('.') or any decimal
+     * digit character value;<br /> - 3 for any kind of white space character<br
+     * /> An ASCII (7 bit) character which does not fall in any category listed
+     * above is mapped to 0xff.
+     */
+    private static final byte nmttyp[];
+
+    /**
+     * Static constructor.
+     *
+     * Sets up the ASCII character type array which is used by
+     * {@link #asctyp asctyp} method and NMTOKEN character type array.
+     */
+    static {
+        short i = 0;
+
+        asctyp = new byte[0x80];
+        while (i < ' ') {
+            asctyp[i++] = (byte) 'z';
+        }
+        asctyp['\t'] = (byte) ' ';
+        asctyp['\r'] = (byte) ' ';
+        asctyp['\n'] = (byte) ' ';
+        while (i < '0') {
+            asctyp[i] = (byte) i++;
+        }
+        while (i <= '9') {
+            asctyp[i++] = (byte) 'd';
+        }
+        while (i < 'A') {
+            asctyp[i] = (byte) i++;
+        }
+        while (i <= 'Z') {
+            asctyp[i++] = (byte) 'A';
+        }
+        while (i < 'a') {
+            asctyp[i] = (byte) i++;
+        }
+        while (i <= 'z') {
+            asctyp[i++] = (byte) 'a';
+        }
+        while (i < 0x80) {
+            asctyp[i] = (byte) i++;
+        }
+
+        nmttyp = new byte[0x80];
+        for (i = 0; i < '0'; i++) {
+            nmttyp[i] = (byte) 0xff;
+        }
+        while (i <= '9') {
+            nmttyp[i++] = (byte) 2;  // digits
+        }
+        while (i < 'A') {
+            nmttyp[i++] = (byte) 0xff;
+        }
+        // skiped upper case alphabetical character are already 0
+        for (i = '['; i < 'a'; i++) {
+            nmttyp[i] = (byte) 0xff;
+        }
+        // skiped lower case alphabetical character are already 0
+        for (i = '{'; i < 0x80; i++) {
+            nmttyp[i] = (byte) 0xff;
+        }
+        nmttyp['_'] = 0;
+        nmttyp[':'] = 1;
+        nmttyp['.'] = 2;
+        nmttyp['-'] = 2;
+        nmttyp[' '] = 3;
+        nmttyp['\t'] = 3;
+        nmttyp['\r'] = 3;
+        nmttyp['\n'] = 3;
+    }
+
+    /**
+     * Constructor.
+     */
+    protected Parser() {
+        mPh = PH_BEFORE_DOC;  // before parsing
+
+        //              Initialize the parser
+        mBuff = new char[BUFFSIZE_PARSER];
+        mAttrs = new Attrs();
+
+        //              Default namespace
+        mPref = pair(mPref);
+        mPref.name = "";
+        mPref.value = "";
+        mPref.chars = NONS;
+        mNoNS = mPref;  // no namespace
+        //              XML namespace
+        mPref = pair(mPref);
+        mPref.name = "xml";
+        mPref.value = "http://www.w3.org/XML/1998/namespace";
+        mPref.chars = XML;
+        mXml = mPref;  // XML namespace
+    }
+
+    /**
+     * Initializes parser's internals. Note, current input has to be set before
+     * this method is called.
+     */
+    protected void init() {
+        mUnent = null;
+        mElm = null;
+        mPref = mXml;
+        mAttL = null;
+        mPEnt = new HashMap<>();
+        mEnt = new HashMap<>();
+        mDoc = mInp;          // current input is document entity
+        mChars = mInp.chars;    // use document entity buffer
+        mPh = PH_DOC_START;  // the begining of the document
+    }
+
+    /**
+     * Cleans up parser internal resources.
+     */
+    protected void cleanup() {
+        //              Default attributes
+        while (mAttL != null) {
+            while (mAttL.list != null) {
+                if (mAttL.list.list != null) {
+                    del(mAttL.list.list);
+                }
+                mAttL.list = del(mAttL.list);
+            }
+            mAttL = del(mAttL);
+        }
+        //              Element stack
+        while (mElm != null) {
+            mElm = del(mElm);
+        }
+        //              Namespace prefixes
+        while (mPref != mXml) {
+            mPref = del(mPref);
+        }
+        //              Inputs
+        while (mInp != null) {
+            pop();
+        }
+        //              Document reader
+        if ((mDoc != null) && (mDoc.src != null)) {
+            try {
+                mDoc.src.close();
+            } catch (IOException ioe) {
+            }
+        }
+        mPEnt = null;
+        mEnt = null;
+        mDoc = null;
+        mPh = PH_AFTER_DOC;  // before documnet processing
+    }
+
+    /**
+     * Processes a portion of document. This method returns one of EV_*
+     * constants as an identifier of the portion of document have been read.
+     *
+     * @return Identifier of processed document portion.
+     * @exception Exception is parser specific exception form panic method.
+     * @exception IOException
+     */
+    @SuppressWarnings("fallthrough")
+    protected int step() throws Exception {
+        mEvt = EV_NULL;
+        int st = 0;
+        while (mEvt == EV_NULL) {
+            char ch = (mChIdx < mChLen) ? mChars[mChIdx++] : getch();
+            switch (st) {
+                case 0:     // all sorts of markup (dispetcher)
+                    if (ch != '<') {
+                        bkch();
+                        mBuffIdx = -1;  // clean parser buffer
+                        st = 1;
+                        break;
+                    }
+                    switch (getch()) {
+                        case '/':  // the end of the element content
+                            mEvt = EV_ELME;
+                            if (mElm == null) {
+                                panic(FAULT);
+                            }
+                            //          Check element's open/close tags balance
+                            mBuffIdx = -1;  // clean parser buffer
+                            bname(mIsNSAware);
+                            char[] chars = mElm.chars;
+                            if (chars.length == (mBuffIdx + 1)) {
+                                for (char i = 1; i <= mBuffIdx; i += 1) {
+                                    if (chars[i] != mBuff[i]) {
+                                        panic(FAULT);
+                                    }
+                                }
+                            } else {
+                                panic(FAULT);
+                            }
+                            //          Skip white spaces before '>'
+                            if (wsskip() != '>') {
+                                panic(FAULT);
+                            }
+                            getch();  // read '>'
+                            break;
+
+                        case '!':  // a comment or a CDATA
+                            ch = getch();
+                            bkch();
+                            switch (ch) {
+                                case '-':  // must be a comment
+                                    mEvt = EV_COMM;
+                                    comm();
+                                    break;
+
+                                case '[':  // must be a CDATA section
+                                    mEvt = EV_CDAT;
+                                    cdat();
+                                    break;
+
+                                default:   // must be 'DOCTYPE'
+                                    mEvt = EV_DTD;
+                                    dtd();
+                                    break;
+                            }
+                            break;
+
+                        case '?':  // processing instruction
+                            mEvt = EV_PI;
+                            pi();
+                            break;
+
+                        default:  // must be the first char of an xml name
+                            bkch();
+                            //          Read an element name and put it on top of the
+                            //          element stack
+                            mElm = pair(mElm);  // add new element to the stack
+                            mElm.chars = qname(mIsNSAware);
+                            mElm.name = mElm.local();
+                            mElm.id = (mElm.next != null) ? mElm.next.id : 0;  // flags
+                            mElm.num = 0;     // namespace counter
+                            //          Find the list of defined attributs of the current
+                            //          element
+                            Pair elm = find(mAttL, mElm.chars);
+                            mElm.list = (elm != null) ? elm.list : null;
+                            //          Read attributes till the end of the element tag
+                            mAttrIdx = 0;
+                            Pair att = pair(null);
+                            att.num = 0;  // clear attribute's flags
+                            attr(att);     // get all attributes inc. defaults
+                            del(att);
+                            mElm.value = (mIsNSAware) ? rslv(mElm.chars) : null;
+                            //          Skip white spaces before '>'
+                            switch (wsskip()) {
+                                case '>':
+                                    getch();  // read '>'
+                                    mEvt = EV_ELMS;
+                                    break;
+
+                                case '/':
+                                    getch();  // read '/'
+                                    if (getch() != '>') // read '>'
+                                    {
+                                        panic(FAULT);
+                                    }
+                                    mEvt = EV_ELM;
+                                    break;
+
+                                default:
+                                    panic(FAULT);
+                            }
+                            break;
+                    }
+                    break;
+
+                case 1:     // read white space
+                    switch (ch) {
+                        case ' ':
+                        case '\t':
+                        case '\n':
+                            bappend(ch);
+                            break;
+
+                        case '\r':              // EOL processing [#2.11]
+                            if (getch() != '\n') {
+                                bkch();
+                            }
+                            bappend('\n');
+                            break;
+
+                        case '<':
+                            mEvt = EV_WSPC;
+                            bkch();
+                            bflash_ws();
+                            break;
+
+                        default:
+                            bkch();
+                            st = 2;
+                            break;
+                    }
+                    break;
+
+                case 2:     // read the text content of the element
+                    switch (ch) {
+                        case '&':
+                            if (mUnent == null) {
+                                //              There was no unresolved entity on previous step.
+                                if ((mUnent = ent('x')) != null) {
+                                    mEvt = EV_TEXT;
+                                    bkch();      // move back to ';' after entity name
+                                    setch('&');  // parser must be back on next step
+                                    bflash();
+                                }
+                            } else {
+                                //              There was unresolved entity on previous step.
+                                mEvt = EV_ENT;
+                                skippedEnt(mUnent);
+                                mUnent = null;
+                            }
+                            break;
+
+                        case '<':
+                            mEvt = EV_TEXT;
+                            bkch();
+                            bflash();
+                            break;
+
+                        case '\r':  // EOL processing [#2.11]
+                            if (getch() != '\n') {
+                                bkch();
+                            }
+                            bappend('\n');
+                            break;
+
+                        case EOS:
+                            panic(FAULT);
+
+                        default:
+                            bappend(ch);
+                            break;
+                    }
+                    break;
+
+                default:
+                    panic(FAULT);
+            }
+        }
+
+        return mEvt;
+    }
+
+    /**
+     * Parses the document type declaration.
+     *
+     * @exception Exception is parser specific exception form panic method.
+     * @exception IOException
+     */
+    private void dtd() throws Exception {
+        char ch;
+        String str = null;
+        String name = null;
+        Pair psid = null;
+        // read 'DOCTYPE'
+        if ("DOCTYPE".equals(name(false)) != true) {
+            panic(FAULT);
+        }
+        mPh = PH_DTD;  // DTD
+        for (short st = 0; st >= 0;) {
+            ch = getch();
+            switch (st) {
+                case 0:     // read the document type name
+                    if (chtyp(ch) != ' ') {
+                        bkch();
+                        name = name(mIsNSAware);
+                        wsskip();
+                        st = 1;  // read 'PUPLIC' or 'SYSTEM'
+                    }
+                    break;
+
+                case 1:     // read 'PUPLIC' or 'SYSTEM'
+                    switch (chtyp(ch)) {
+                        case 'A':
+                            bkch();
+                            psid = pubsys(' ');
+                            st = 2;  // skip spaces before internal subset
+                            docType(name, psid.name, psid.value);
+                            break;
+
+                        case '[':
+                            bkch();
+                            st = 2;    // skip spaces before internal subset
+                            docType(name, null, null);
+                            break;
+
+                        case '>':
+                            bkch();
+                            st = 3;    // skip spaces after internal subset
+                            docType(name, null, null);
+                            break;
+
+                        default:
+                            panic(FAULT);
+                    }
+                    break;
+
+                case 2:     // skip spaces before internal subset
+                    switch (chtyp(ch)) {
+                        case '[':
+                            //          Process internal subset
+                            dtdsub();
+                            st = 3;  // skip spaces after internal subset
+                            break;
+
+                        case '>':
+                            //          There is no internal subset
+                            bkch();
+                            st = 3;  // skip spaces after internal subset
+                            break;
+
+                        case ' ':
+                            // skip white spaces
+                            break;
+
+                        default:
+                            panic(FAULT);
+                    }
+                    break;
+
+                case 3:     // skip spaces after internal subset
+                    switch (chtyp(ch)) {
+                        case '>':
+                            if (psid != null) {
+                                //              Report the DTD external subset
+                                InputSource is = resolveEnt(name, psid.name, psid.value);
+                                if (is != null) {
+                                    if (mIsSAlone == false) {
+                                        //              Set the end of DTD external subset char
+                                        bkch();
+                                        setch(']');
+                                        //              Set the DTD external subset InputSource
+                                        push(new Input(BUFFSIZE_READER));
+                                        setinp(is);
+                                        mInp.pubid = psid.name;
+                                        mInp.sysid = psid.value;
+                                        //              Parse the DTD external subset
+                                        dtdsub();
+                                    } else {
+                                        //              Unresolved DTD external subset
+                                        skippedEnt("[dtd]");
+                                        //              Release reader and stream
+                                        if (is.getCharacterStream() != null) {
+                                            try {
+                                                is.getCharacterStream().close();
+                                            } catch (IOException ioe) {
+                                            }
+                                        }
+                                        if (is.getByteStream() != null) {
+                                            try {
+                                                is.getByteStream().close();
+                                            } catch (IOException ioe) {
+                                            }
+                                        }
+                                    }
+                                } else {
+                                    //          Unresolved DTD external subset
+                                    skippedEnt("[dtd]");
+                                }
+                                del(psid);
+                            }
+                            st = -1;  // end of DTD
+                            break;
+
+                        case ' ':
+                            // skip white spaces
+                            break;
+
+                        default:
+                            panic(FAULT);
+                    }
+                    break;
+
+                default:
+                    panic(FAULT);
+            }
+        }
+    }
+
+    /**
+     * Parses the document type declaration subset.
+     *
+     * @exception Exception is parser specific exception form panic method.
+     * @exception IOException
+     */
+    private void dtdsub() throws Exception {
+        char ch;
+        for (short st = 0; st >= 0;) {
+            ch = getch();
+            switch (st) {
+                case 0:     // skip white spaces before a declaration
+                    switch (chtyp(ch)) {
+                        case '<':
+                            ch = getch();
+                            switch (ch) {
+                                case '?':
+                                    pi();
+                                    break;
+
+                                case '!':
+                                    ch = getch();
+                                    bkch();
+                                    if (ch == '-') {
+                                        comm();
+                                        break;
+                                    }
+                                    //          A markup or an entity declaration
+                                    bntok();
+                                    switch (bkeyword()) {
+                                        case 'n':
+                                            dtdent();
+                                            break;
+
+                                        case 'a':
+                                            dtdattl();    // parse attributes declaration
+                                            break;
+
+                                        case 'e':
+                                            dtdelm();     // parse element declaration
+                                            break;
+
+                                        case 'o':
+                                            dtdnot();     // parse notation declaration
+                                            break;
+
+                                        default:
+                                            panic(FAULT); // unsupported markup declaration
+                                            break;
+                                    }
+                                    st = 1;  // read the end of declaration
+                                    break;
+
+                                default:
+                                    panic(FAULT);
+                                    break;
+                            }
+                            break;
+
+                        case '%':
+                            //          A parameter entity reference
+                            pent(' ');
+                            break;
+
+                        case ']':
+                            //          End of DTD subset
+                            st = -1;
+                            break;
+
+                        case ' ':
+                            //          Skip white spaces
+                            break;
+
+                        case 'Z':
+                            //          End of stream
+                            if (getch() != ']') {
+                                panic(FAULT);
+                            }
+                            st = -1;
+                            break;
+
+                        default:
+                            panic(FAULT);
+                    }
+                    break;
+
+                case 1:     // read the end of declaration
+                    switch (ch) {
+                        case '>':   // there is no notation
+                            st = 0; // skip white spaces before a declaration
+                            break;
+
+                        case ' ':
+                        case '\n':
+                        case '\r':
+                        case '\t':
+                            //          Skip white spaces
+                            break;
+
+                        default:
+                            panic(FAULT);
+                            break;
+                    }
+                    break;
+
+                default:
+                    panic(FAULT);
+            }
+        }
+    }
+
+    /**
+     * Parses an entity declaration. This method fills the general (
+     * <code>mEnt</code>) and parameter
+     * (
+     * <code>mPEnt</code>) entity look up table.
+     *
+     * @exception Exception is parser specific exception form panic method.
+     * @exception IOException
+     */
+    @SuppressWarnings("fallthrough")
+    private void dtdent() throws Exception {
+        String str = null;
+        char[] val = null;
+        Input inp = null;
+        Pair ids = null;
+        char ch;
+        for (short st = 0; st >= 0;) {
+            ch = getch();
+            switch (st) {
+                case 0:     // skip white spaces before entity name
+                    switch (chtyp(ch)) {
+                        case ' ':
+                            //          Skip white spaces
+                            break;
+
+                        case '%':
+                            //          Parameter entity or parameter entity declaration.
+                            ch = getch();
+                            bkch();
+                            if (chtyp(ch) == ' ') {
+                                //              Parameter entity declaration.
+                                wsskip();
+                                str = name(false);
+                                switch (chtyp(wsskip())) {
+                                    case 'A':
+                                        //              Read the external identifier
+                                        ids = pubsys(' ');
+                                        if (wsskip() == '>') {
+                                            //          External parsed entity
+                                            if (mPEnt.containsKey(str) == false) {      // [#4.2]
+                                                inp = new Input();
+                                                inp.pubid = ids.name;
+                                                inp.sysid = ids.value;
+                                                mPEnt.put(str, inp);
+                                            }
+                                        } else {
+                                            panic(FAULT);
+                                        }
+                                        del(ids);
+                                        st = -1;  // the end of declaration
+                                        break;
+
+                                    case '\"':
+                                    case '\'':
+                                        //              Read the parameter entity value
+                                        bqstr('d');
+                                        //              Create the parameter entity value
+                                        val = new char[mBuffIdx + 1];
+                                        System.arraycopy(mBuff, 1, val, 1, val.length - 1);
+                                        //              Add surrounding spaces [#4.4.8]
+                                        val[0] = ' ';
+                                        //              Add the entity to the entity look up table
+                                        if (mPEnt.containsKey(str) == false) {  // [#4.2]
+                                            inp = new Input(val);
+                                            inp.pubid = mInp.pubid;
+                                            inp.sysid = mInp.sysid;
+                                            inp.xmlenc = mInp.xmlenc;
+                                            inp.xmlver = mInp.xmlver;
+                                            mPEnt.put(str, inp);
+                                        }
+                                        st = -1;  // the end of declaration
+                                        break;
+
+                                    default:
+                                        panic(FAULT);
+                                        break;
+                                }
+                            } else {
+                                //              Parameter entity reference.
+                                pent(' ');
+                            }
+                            break;
+
+                        default:
+                            bkch();
+                            str = name(false);
+                            st = 1;  // read entity declaration value
+                            break;
+                    }
+                    break;
+
+                case 1:     // read entity declaration value
+                    switch (chtyp(ch)) {
+                        case '\"':  // internal entity
+                        case '\'':
+                            bkch();
+                            bqstr('d');  // read a string into the buffer
+                            if (mEnt.get(str) == null) {
+                                //              Create general entity value
+                                val = new char[mBuffIdx];
+                                System.arraycopy(mBuff, 1, val, 0, val.length);
+                                //              Add the entity to the entity look up table
+                                if (mEnt.containsKey(str) == false) {   // [#4.2]
+                                    inp = new Input(val);
+                                    inp.pubid = mInp.pubid;
+                                    inp.sysid = mInp.sysid;
+                                    inp.xmlenc = mInp.xmlenc;
+                                    inp.xmlver = mInp.xmlver;
+                                    mEnt.put(str, inp);
+                                }
+                            }
+                            st = -1;  // the end of declaration
+                            break;
+
+                        case 'A':  // external entity
+                            bkch();
+                            ids = pubsys(' ');
+                            switch (wsskip()) {
+                                case '>':  // external parsed entity
+                                    if (mEnt.containsKey(str) == false) {  // [#4.2]
+                                        inp = new Input();
+                                        inp.pubid = ids.name;
+                                        inp.sysid = ids.value;
+                                        mEnt.put(str, inp);
+                                    }
+                                    break;
+
+                                case 'N':  // external general unparsed entity
+                                    if ("NDATA".equals(name(false)) == true) {
+                                        wsskip();
+                                        unparsedEntDecl(str, ids.name, ids.value, name(false));
+                                        break;
+                                    }
+                                default:
+                                    panic(FAULT);
+                                    break;
+                            }
+                            del(ids);
+                            st = -1;  // the end of declaration
+                            break;
+
+                        case ' ':
+                            //          Skip white spaces
+                            break;
+
+                        default:
+                            panic(FAULT);
+                            break;
+                    }
+                    break;
+
+                default:
+                    panic(FAULT);
+            }
+        }
+    }
+
+    /**
+     * Parses an element declaration.
+     *
+     * This method parses the declaration up to the closing angle bracket.
+     *
+     * @exception Exception is parser specific exception form panic method.
+     * @exception IOException
+     */
+    @SuppressWarnings("fallthrough")
+    private void dtdelm() throws Exception {
+        //              This is stub implementation which skips an element
+        //              declaration.
+        wsskip();
+        name(mIsNSAware);
+
+        char ch;
+        while (true) {
+            ch = getch();
+            switch (ch) {
+                case '>':
+                    bkch();
+                    return;
+
+                case EOS:
+                    panic(FAULT);
+
+                default:
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Parses an attribute list declaration.
+     *
+     * This method parses the declaration up to the closing angle bracket.
+     *
+     * @exception Exception is parser specific exception form panic method.
+     * @exception IOException
+     */
+    private void dtdattl() throws Exception {
+        char elmqn[] = null;
+        Pair elm = null;
+        char ch;
+        for (short st = 0; st >= 0;) {
+            ch = getch();
+            switch (st) {
+                case 0:     // read the element name
+                    switch (chtyp(ch)) {
+                        case 'a':
+                        case 'A':
+                        case '_':
+                        case 'X':
+                        case ':':
+                            bkch();
+                            //          Get the element from the list or add a new one.
+                            elmqn = qname(mIsNSAware);
+                            elm = find(mAttL, elmqn);
+                            if (elm == null) {
+                                elm = pair(mAttL);
+                                elm.chars = elmqn;
+                                mAttL = elm;
+                            }
+                            st = 1;  // read an attribute declaration
+                            break;
+
+                        case ' ':
+                            break;
+
+                        case '%':
+                            pent(' ');
+                            break;
+
+                        default:
+                            panic(FAULT);
+                            break;
+                    }
+                    break;
+
+                case 1:     // read an attribute declaration
+                    switch (chtyp(ch)) {
+                        case 'a':
+                        case 'A':
+                        case '_':
+                        case 'X':
+                        case ':':
+                            bkch();
+                            dtdatt(elm);
+                            if (wsskip() == '>') {
+                                return;
+                            }
+                            break;
+
+                        case ' ':
+                            break;
+
+                        case '%':
+                            pent(' ');
+                            break;
+
+                        default:
+                            panic(FAULT);
+                            break;
+                    }
+                    break;
+
+                default:
+                    panic(FAULT);
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Parses an attribute declaration.
+     *
+     * The attribute uses the following fields of Pair object: chars - characters
+     * of qualified name id - the type identifier of the attribute list - a pair
+     * which holds the default value (chars field)
+     *
+     * @param elm An object which represents all defined attributes on an
+     * element.
+     * @exception Exception is parser specific exception form panic method.
+     * @exception IOException
+     */
+    @SuppressWarnings("fallthrough")
+    private void dtdatt(Pair elm) throws Exception {
+        char attqn[] = null;
+        Pair att = null;
+        char ch;
+        for (short st = 0; st >= 0;) {
+            ch = getch();
+            switch (st) {
+                case 0:     // the attribute name
+                    switch (chtyp(ch)) {
+                        case 'a':
+                        case 'A':
+                        case '_':
+                        case 'X':
+                        case ':':
+                            bkch();
+                            //          Get the attribut from the list or add a new one.
+                            attqn = qname(mIsNSAware);
+                            att = find(elm.list, attqn);
+                            if (att == null) {
+                                //              New attribute declaration
+                                att = pair(elm.list);
+                                att.chars = attqn;
+                                elm.list = att;
+                            } else {
+                                //              Do not override the attribute declaration [#3.3]
+                                att = pair(null);
+                                att.chars = attqn;
+                                att.id = 'c';
+                            }
+                            wsskip();
+                            st = 1;
+                            break;
+
+                        case '%':
+                            pent(' ');
+                            break;
+
+                        case ' ':
+                            break;
+
+                        default:
+                            panic(FAULT);
+                            break;
+                    }
+                    break;
+
+                case 1:     // the attribute type
+                    switch (chtyp(ch)) {
+                        case '(':
+                            att.id = 'u';  // enumeration type
+                            st = 2;        // read the first element of the list
+                            break;
+
+                        case '%':
+                            pent(' ');
+                            break;
+
+                        case ' ':
+                            break;
+
+                        default:
+                            bkch();
+                            bntok();  // read type id
+                            att.id = bkeyword();
+                            switch (att.id) {
+                                case 'o':   // NOTATION
+                                    if (wsskip() != '(') {
+                                        panic(FAULT);
+                                    }
+                                    ch = getch();
+                                    st = 2;  // read the first element of the list
+                                    break;
+
+                                case 'i':     // ID
+                                case 'r':     // IDREF
+                                case 'R':     // IDREFS
+                                case 'n':     // ENTITY
+                                case 'N':     // ENTITIES
+                                case 't':     // NMTOKEN
+                                case 'T':     // NMTOKENS
+                                case 'c':     // CDATA
+                                    wsskip();
+                                    st = 4;  // read default declaration
+                                    break;
+
+                                default:
+                                    panic(FAULT);
+                                    break;
+                            }
+                            break;
+                    }
+                    break;
+
+                case 2:     // read the first element of the list
+                    switch (chtyp(ch)) {
+                        case 'a':
+                        case 'A':
+                        case 'd':
+                        case '.':
+                        case ':':
+                        case '-':
+                        case '_':
+                        case 'X':
+                            bkch();
+                            switch (att.id) {
+                                case 'u':  // enumeration type
+                                    bntok();
+                                    break;
+
+                                case 'o':  // NOTATION
+                                    mBuffIdx = -1;
+                                    bname(false);
+                                    break;
+
+                                default:
+                                    panic(FAULT);
+                                    break;
+                            }
+                            wsskip();
+                            st = 3;  // read next element of the list
+                            break;
+
+                        case '%':
+                            pent(' ');
+                            break;
+
+                        case ' ':
+                            break;
+
+                        default:
+                            panic(FAULT);
+                            break;
+                    }
+                    break;
+
+                case 3:     // read next element of the list
+                    switch (ch) {
+                        case ')':
+                            wsskip();
+                            st = 4;  // read default declaration
+                            break;
+
+                        case '|':
+                            wsskip();
+                            switch (att.id) {
+                                case 'u':  // enumeration type
+                                    bntok();
+                                    break;
+
+                                case 'o':  // NOTATION
+                                    mBuffIdx = -1;
+                                    bname(false);
+                                    break;
+
+                                default:
+                                    panic(FAULT);
+                                    break;
+                            }
+                            wsskip();
+                            break;
+
+                        case '%':
+                            pent(' ');
+                            break;
+
+                        default:
+                            panic(FAULT);
+                            break;
+                    }
+                    break;
+
+                case 4:     // read default declaration
+                    switch (ch) {
+                        case '#':
+                            bntok();
+                            switch (bkeyword()) {
+                                case 'F':  // FIXED
+                                    switch (wsskip()) {
+                                        case '\"':
+                                        case '\'':
+                                            st = 5;  // read the default value
+                                            break;
+
+                                        case EOS:
+                                            panic(FAULT);
+
+                                        default:
+                                            st = -1;
+                                            break;
+                                    }
+                                    break;
+
+                                case 'Q':  // REQUIRED
+                                case 'I':  // IMPLIED
+                                    st = -1;
+                                    break;
+
+                                default:
+                                    panic(FAULT);
+                                    break;
+                            }
+                            break;
+
+                        case '\"':
+                        case '\'':
+                            bkch();
+                            st = 5;  // read the default value
+                            break;
+
+                        case ' ':
+                        case '\n':
+                        case '\r':
+                        case '\t':
+                            break;
+
+                        case '%':
+                            pent(' ');
+                            break;
+
+                        default:
+                            bkch();
+                            st = -1;
+                            break;
+                    }
+                    break;
+
+                case 5:     // read the default value
+                    switch (ch) {
+                        case '\"':
+                        case '\'':
+                            bkch();
+                            bqstr('d');  // the value in the mBuff now
+                            att.list = pair(null);
+                            //          Create a string like "attqname='value' "
+                            att.list.chars = new char[att.chars.length + mBuffIdx + 3];
+                            System.arraycopy(
+                                    att.chars, 1, att.list.chars, 0, att.chars.length - 1);
+                            att.list.chars[att.chars.length - 1] = '=';
+                            att.list.chars[att.chars.length] = ch;
+                            System.arraycopy(
+                                    mBuff, 1, att.list.chars, att.chars.length + 1, mBuffIdx);
+                            att.list.chars[att.chars.length + mBuffIdx + 1] = ch;
+                            att.list.chars[att.chars.length + mBuffIdx + 2] = ' ';
+                            st = -1;
+                            break;
+
+                        default:
+                            panic(FAULT);
+                            break;
+                    }
+                    break;
+
+                default:
+                    panic(FAULT);
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Parses a notation declaration.
+     *
+     * This method parses the declaration up to the closing angle bracket.
+     *
+     * @exception Exception is parser specific exception form panic method.
+     * @exception IOException
+     */
+    private void dtdnot() throws Exception {
+        wsskip();
+        String name = name(false);
+        wsskip();
+        Pair ids = pubsys('N');
+        notDecl(name, ids.name, ids.value);
+        del(ids);
+    }
+
+    /**
+     * Parses an attribute.
+     *
+     * This recursive method is responsible for prefix addition
+     * (
+     * <code>mPref</code>) on the way down. The element's start tag end triggers
+     * the return process. The method then on it's way back resolves prefixes
+     * and accumulates attributes.
+     *
+     * <p><code>att.num</code> carries attribute flags where: 0x1 - attribute is
+     * declared in DTD (attribute decalration had been read); 0x2 - attribute's
+     * default value is used.</p>
+     *
+     * @param att An object which reprecents current attribute.
+     * @exception Exception is parser specific exception form panic method.
+     * @exception IOException
+     */
+    @SuppressWarnings("fallthrough")
+    private void attr(Pair att) throws Exception {
+        switch (wsskip()) {
+            case '/':
+            case '>':
+                if ((att.num & 0x2) == 0) {  // all attributes have been read
+                    att.num |= 0x2;  // set default attribute flag
+                    Input inp = mInp;
+                    //          Go through all attributes defined on current element.
+                    for (Pair def = mElm.list; def != null; def = def.next) {
+                        if (def.list == null) // no default value
+                        {
+                            continue;
+                        }
+                        //              Go through all attributes defined on current
+                        //              element and add defaults.
+                        Pair act = find(att.next, def.chars);
+                        if (act == null) {
+                            push(new Input(def.list.chars));
+                        }
+                    }
+                    if (mInp != inp) {  // defaults have been added
+                        attr(att);
+                        return;
+                    }
+                }
+                //              Ensure the attribute string array capacity
+                mAttrs.setLength(mAttrIdx);
+                mItems = mAttrs.mItems;
+                return;
+
+            case EOS:
+                panic(FAULT);
+
+            default:
+                //              Read the attribute name and value
+                att.chars = qname(mIsNSAware);
+                att.name = att.local();
+                String type = atype(att);  // sets attribute's type on att.id
+                wsskip();
+                if (getch() != '=') {
+                    panic(FAULT);
+                }
+                bqstr((char) att.id);   // read the value with normalization.
+                String val = new String(mBuff, 1, mBuffIdx);
+                Pair next = pair(att);
+                next.num = (att.num & ~0x1);  // inherit attribute flags
+                //              Put a namespace declaration on top of the prefix stack
+                if ((mIsNSAware == false) || (isdecl(att, val) == false)) {
+                    //          An ordinary attribute
+                    mAttrIdx++;
+                    attr(next);     // recursive call to parse the next attribute
+                    mAttrIdx--;
+                    //          Add the attribute to the attributes string array
+                    char idx = (char) (mAttrIdx << 3);
+                    mItems[idx + 1] = att.qname();  // attr qname
+                    mItems[idx + 2] = (mIsNSAware) ? att.name : ""; // attr local name
+                    mItems[idx + 3] = val;          // attr value
+                    mItems[idx + 4] = type;         // attr type
+                    switch (att.num & 0x3) {
+                        case 0x0:
+                            mItems[idx + 5] = null;
+                            break;
+
+                        case 0x1:  // declared attribute
+                            mItems[idx + 5] = "d";
+                            break;
+
+                        default:  // 0x2, 0x3 - default attribute always declared
+                            mItems[idx + 5] = "D";
+                            break;
+                    }
+                    //          Resolve the prefix if any and report the attribute
+                    //          NOTE: The attribute does not accept the default namespace.
+                    mItems[idx + 0] = (att.chars[0] != 0) ? rslv(att.chars) : "";
+                } else {
+                    //          A namespace declaration. mPref.name contains prefix and
+                    //          mPref.value contains namespace URI set by isdecl method.
+                    //          Report a start of the new mapping
+                    newPrefix();
+                    //          Recursive call to parse the next attribute
+                    attr(next);
+                    //          NOTE: The namespace declaration is not reported.
+                }
+                del(next);
+                break;
+        }
+    }
+
+    /**
+     * Retrieves attribute type.
+     *
+     * This method sets the type of normalization in the attribute
+     * <code>id</code> field and returns the name of attribute type.
+     *
+     * @param att An object which represents current attribute.
+     * @return The name of the attribute type.
+     * @exception Exception is parser specific exception form panic method.
+     */
+    private String atype(Pair att)
+            throws Exception {
+        Pair attr;
+
+        // CDATA-type normalization by default [#3.3.3]
+        att.id = 'c';
+        if (mElm.list == null || (attr = find(mElm.list, att.chars)) == null) {
+            return "CDATA";
+        }
+
+        att.num |= 0x1;  // attribute is declared
+
+        // Non-CDATA normalization except when the attribute type is CDATA.
+        att.id = 'i';
+        switch (attr.id) {
+            case 'i':
+                return "ID";
+
+            case 'r':
+                return "IDREF";
+
+            case 'R':
+                return "IDREFS";
+
+            case 'n':
+                return "ENTITY";
+
+            case 'N':
+                return "ENTITIES";
+
+            case 't':
+                return "NMTOKEN";
+
+            case 'T':
+                return "NMTOKENS";
+
+            case 'u':
+                return "NMTOKEN";
+
+            case 'o':
+                return "NOTATION";
+
+            case 'c':
+                att.id = 'c';
+                return "CDATA";
+
+            default:
+                panic(FAULT);
+        }
+        return null;
+    }
+
+    /**
+     * Parses a comment.
+     *
+     * The &apos;&lt;!&apos; part is read in dispatcher so the method starts
+     * with first &apos;-&apos; after &apos;&lt;!&apos;.
+     *
+     * @exception Exception is parser specific exception form panic method.
+     */
+    @SuppressWarnings("fallthrough")
+    private void comm() throws Exception {
+        if (mPh == PH_DOC_START) {
+            mPh = PH_MISC_DTD;  // misc before DTD
+        }               // '<!' has been already read by dispetcher.
+        char ch;
+        mBuffIdx = -1;
+        for (short st = 0; st >= 0;) {
+            ch = (mChIdx < mChLen) ? mChars[mChIdx++] : getch();
+            if (ch == EOS) {
+                panic(FAULT);
+            }
+            switch (st) {
+                case 0:     // first '-' of the comment open
+                    if (ch == '-') {
+                        st = 1;
+                    } else {
+                        panic(FAULT);
+                    }
+                    break;
+
+                case 1:     // secind '-' of the comment open
+                    if (ch == '-') {
+                        st = 2;
+                    } else {
+                        panic(FAULT);
+                    }
+                    break;
+
+                case 2:     // skip the comment body
+                    switch (ch) {
+                        case '-':
+                            st = 3;
+                            break;
+
+                        default:
+                            bappend(ch);
+                            break;
+                    }
+                    break;
+
+                case 3:     // second '-' of the comment close
+                    switch (ch) {
+                        case '-':
+                            st = 4;
+                            break;
+
+                        default:
+                            bappend('-');
+                            bappend(ch);
+                            st = 2;
+                            break;
+                    }
+                    break;
+
+                case 4:     // '>' of the comment close
+                    if (ch == '>') {
+                        comm(mBuff, mBuffIdx + 1);
+                        st = -1;
+                        break;
+                    }
+                // else - panic [#2.5 compatibility note]
+
+                default:
+                    panic(FAULT);
+            }
+        }
+    }
+
+    /**
+     * Parses a processing instruction.
+     *
+     * The &apos;&lt;?&apos; is read in dispatcher so the method starts with
+     * first character of PI target name after &apos;&lt;?&apos;.
+     *
+     * @exception Exception is parser specific exception form panic method.
+     * @exception IOException
+     */
+    private void pi() throws Exception {
+        // '<?' has been already read by dispetcher.
+        char ch;
+        String str = null;
+        mBuffIdx = -1;
+        for (short st = 0; st >= 0;) {
+            ch = getch();
+            if (ch == EOS) {
+                panic(FAULT);
+            }
+            switch (st) {
+                case 0:     // read the PI target name
+                    switch (chtyp(ch)) {
+                        case 'a':
+                        case 'A':
+                        case '_':
+                        case ':':
+                        case 'X':
+                            bkch();
+                            str = name(false);
+                            //          PI target name may not be empty string [#2.6]
+                            //          PI target name 'XML' is reserved [#2.6]
+                            if ((str.length() == 0)
+                                    || (mXml.name.equals(str.toLowerCase()) == true)) {
+                                panic(FAULT);
+                            }
+                            //          This is processing instruction
+                            if (mPh == PH_DOC_START) // the begining of the document
+                            {
+                                mPh = PH_MISC_DTD;    // misc before DTD
+                            }
+                            wsskip();  // skip spaces after the PI target name
+                            st = 1;    // accumulate the PI body
+                            mBuffIdx = -1;
+                            break;
+
+                        default:
+                            panic(FAULT);
+                    }
+                    break;
+
+                case 1:     // accumulate the PI body
+                    switch (ch) {
+                        case '?':
+                            st = 2;  // end of the PI body
+                            break;
+
+                        default:
+                            bappend(ch);
+                            break;
+                    }
+                    break;
+
+                case 2:     // end of the PI body
+                    switch (ch) {
+                        case '>':
+                            //          PI has been read.
+                            pi(str, new String(mBuff, 0, mBuffIdx + 1));
+                            st = -1;
+                            break;
+
+                        case '?':
+                            bappend('?');
+                            break;
+
+                        default:
+                            bappend('?');
+                            bappend(ch);
+                            st = 1;  // accumulate the PI body
+                            break;
+                    }
+                    break;
+
+                default:
+                    panic(FAULT);
+            }
+        }
+    }
+
+    /**
+     * Parses a character data.
+     *
+     * The &apos;&lt;!&apos; part is read in dispatcher so the method starts
+     * with first &apos;[&apos; after &apos;&lt;!&apos;.
+     *
+     * @exception Exception is parser specific exception form panic method.
+     * @exception IOException
+     */
+    private void cdat()
+            throws Exception {
+        // '<!' has been already read by dispetcher.
+        char ch;
+        mBuffIdx = -1;
+        for (short st = 0; st >= 0;) {
+            ch = getch();
+            switch (st) {
+                case 0:     // the first '[' of the CDATA open
+                    if (ch == '[') {
+                        st = 1;
+                    } else {
+                        panic(FAULT);
+                    }
+                    break;
+
+                case 1:     // read "CDATA"
+                    if (chtyp(ch) == 'A') {
+                        bappend(ch);
+                    } else {
+                        if ("CDATA".equals(
+                                new String(mBuff, 0, mBuffIdx + 1)) != true) {
+                            panic(FAULT);
+                        }
+                        bkch();
+                        st = 2;
+                    }
+                    break;
+
+                case 2:     // the second '[' of the CDATA open
+                    if (ch != '[') {
+                        panic(FAULT);
+                    }
+                    mBuffIdx = -1;
+                    st = 3;
+                    break;
+
+                case 3:     // read data before the first ']'
+                    if (ch != ']') {
+                        bappend(ch);
+                    } else {
+                        st = 4;
+                    }
+                    break;
+
+                case 4:     // read the second ']' or continue to read the data
+                    if (ch != ']') {
+                        bappend(']');
+                        bappend(ch);
+                        st = 3;
+                    } else {
+                        st = 5;
+                    }
+                    break;
+
+                case 5:     // read '>' or continue to read the data
+                    switch (ch) {
+                        case ']':
+                            bappend(']');
+                            break;
+
+                        case '>':
+                            bflash();
+                            st = -1;
+                            break;
+
+                        default:
+                            bappend(']');
+                            bappend(']');
+                            bappend(ch);
+                            st = 3;
+                            break;
+                    }
+                    break;
+
+                default:
+                    panic(FAULT);
+            }
+        }
+    }
+
+    /**
+     * Reads a xml name.
+     *
+     * The xml name must conform "Namespaces in XML" specification. Therefore
+     * the ':' character is not allowed in the name. This method should be used
+     * for PI and entity names which may not have a namespace according to the
+     * specification mentioned above.
+     *
+     * @param ns The true value turns namespace conformance on.
+     * @return The name has been read.
+     * @exception Exception When incorrect character appear in the name.
+     * @exception IOException
+     */
+    protected String name(boolean ns)
+            throws Exception {
+        mBuffIdx = -1;
+        bname(ns);
+        return new String(mBuff, 1, mBuffIdx);
+    }
+
+    /**
+     * Reads a qualified xml name.
+     *
+     * The characters of a qualified name is an array of characters. The first
+     * (chars[0]) character is the index of the colon character which separates
+     * the prefix from the local name. If the index is zero, the name does not
+     * contain separator or the parser works in the namespace unaware mode. The
+     * length of qualified name is the length of the array minus one.
+     *
+     * @param ns The true value turns namespace conformance on.
+     * @return The characters of a qualified name.
+     * @exception Exception When incorrect character appear in the name.
+     * @exception IOException
+     */
+    protected char[] qname(boolean ns)
+            throws Exception {
+        mBuffIdx = -1;
+        bname(ns);
+        char chars[] = new char[mBuffIdx + 1];
+        System.arraycopy(mBuff, 0, chars, 0, mBuffIdx + 1);
+        return chars;
+    }
+
+    /**
+     * Reads the public or/and system identifiers.
+     *
+     * @param inp The input object.
+     * @exception Exception is parser specific exception form panic method.
+     * @exception IOException
+     */
+    private void pubsys(Input inp)
+            throws Exception {
+        Pair pair = pubsys(' ');
+        inp.pubid = pair.name;
+        inp.sysid = pair.value;
+        del(pair);
+    }
+
+    /**
+     * Reads the public or/and system identifiers.
+     *
+     * @param flag The 'N' allows public id be without system id.
+     * @return The public or/and system identifiers pair.
+     * @exception Exception is parser specific exception form panic method.
+     * @exception IOException
+     */
+    @SuppressWarnings("fallthrough")
+    private Pair pubsys(char flag) throws Exception {
+        Pair ids = pair(null);
+        String str = name(false);
+        if ("PUBLIC".equals(str) == true) {
+            bqstr('i');  // non-CDATA normalization [#4.2.2]
+            ids.name = new String(mBuff, 1, mBuffIdx);
+            switch (wsskip()) {
+                case '\"':
+                case '\'':
+                    bqstr(' ');
+                    ids.value = new String(mBuff, 1, mBuffIdx);
+                    break;
+
+                case EOS:
+                    panic(FAULT);
+
+                default:
+                    if (flag != 'N') // [#4.7]
+                    {
+                        panic(FAULT);
+                    }
+                    ids.value = null;
+                    break;
+            }
+            return ids;
+        } else if ("SYSTEM".equals(str) == true) {
+            ids.name = null;
+            bqstr(' ');
+            ids.value = new String(mBuff, 1, mBuffIdx);
+            return ids;
+        }
+        panic(FAULT);
+        return null;
+    }
+
+    /**
+     * Reads an attribute value.
+     *
+     * The grammar which this method can read is:<br />
+     * <code>eqstr := S &quot;=&quot; qstr</code><br />
+     * <code>qstr  := S (&quot;'&quot; string &quot;'&quot;) |
+     *  ('&quot;' string '&quot;')</code><br /> This method resolves entities
+     * inside a string unless the parser parses DTD.
+     *
+     * @param flag The '=' character forces the method to accept the '='
+     * character before quoted string and read the following string as not an
+     * attribute ('-'), 'c' - CDATA, 'i' - non CDATA, ' ' - no normalization;
+     * '-' - not an attribute value; 'd' - in DTD context.
+     * @return The content of the quoted strign as a string.
+     * @exception Exception is parser specific exception form panic method.
+     * @exception IOException
+     */
+    protected String eqstr(char flag) throws Exception {
+        if (flag == '=') {
+            wsskip();
+            if (getch() != '=') {
+                panic(FAULT);
+            }
+        }
+        bqstr((flag == '=') ? '-' : flag);
+        return new String(mBuff, 1, mBuffIdx);
+    }
+
+    /**
+     * Resoves an entity.
+     *
+     * This method resolves built-in and character entity references. It is also
+     * reports external entities to the application.
+     *
+     * @param flag The 'x' character forces the method to report a skipped
+     * entity; 'i' character - indicates non-CDATA normalization.
+     * @return Name of unresolved entity or <code>null</code> if entity had been
+     * resolved successfully.
+     * @exception Exception is parser specific exception form panic method.
+     * @exception IOException
+     */
+    @SuppressWarnings("fallthrough")
+    private String ent(char flag) throws Exception {
+        char ch;
+        int idx = mBuffIdx + 1;
+        Input inp = null;
+        String str = null;
+        mESt = 0x100;  // reset the built-in entity recognizer
+        bappend('&');
+        for (short st = 0; st >= 0;) {
+            ch = (mChIdx < mChLen) ? mChars[mChIdx++] : getch();
+            switch (st) {
+                case 0:     // the first character of the entity name
+                case 1:     // read built-in entity name
+                    switch (chtyp(ch)) {
+                        case 'd':
+                        case '.':
+                        case '-':
+                            if (st != 1) {
+                                panic(FAULT);
+                            }
+                        case 'a':
+                        case 'A':
+                        case '_':
+                        case 'X':
+                            bappend(ch);
+                            eappend(ch);
+                            st = 1;
+                            break;
+
+                        case ':':
+                            if (mIsNSAware != false) {
+                                panic(FAULT);
+                            }
+                            bappend(ch);
+                            eappend(ch);
+                            st = 1;
+                            break;
+
+                        case ';':
+                            if (mESt < 0x100) {
+                                //              The entity is a built-in entity
+                                mBuffIdx = idx - 1;
+                                bappend(mESt);
+                                st = -1;
+                                break;
+                            } else if (mPh == PH_DTD) {
+                                //              In DTD entity declaration has to resolve character
+                                //              entities and include "as is" others. [#4.4.7]
+                                bappend(';');
+                                st = -1;
+                                break;
+                            }
+                            //          Convert an entity name to a string
+                            str = new String(mBuff, idx + 1, mBuffIdx - idx);
+                            inp = mEnt.get(str);
+                            //          Restore the buffer offset
+                            mBuffIdx = idx - 1;
+                            if (inp != null) {
+                                if (inp.chars == null) {
+                                    //          External entity
+                                    InputSource is = resolveEnt(str, inp.pubid, inp.sysid);
+                                    if (is != null) {
+                                        push(new Input(BUFFSIZE_READER));
+                                        setinp(is);
+                                        mInp.pubid = inp.pubid;
+                                        mInp.sysid = inp.sysid;
+                                        str = null;  // the entity is resolved
+                                    } else {
+                                        //              Unresolved external entity
+                                        if (flag != 'x') {
+                                            panic(FAULT);  // unknown entity within marckup
+                                        }                                                               //              str is name of unresolved entity
+                                    }
+                                } else {
+                                    //          Internal entity
+                                    push(inp);
+                                    str = null;  // the entity is resolved
+                                }
+                            } else {
+                                //              Unknown or general unparsed entity
+                                if (flag != 'x') {
+                                    panic(FAULT);  // unknown entity within marckup
+                                }                                               //              str is name of unresolved entity
+                            }
+                            st = -1;
+                            break;
+
+                        case '#':
+                            if (st != 0) {
+                                panic(FAULT);
+                            }
+                            st = 2;
+                            break;
+
+                        default:
+                            panic(FAULT);
+                    }
+                    break;
+
+                case 2:     // read character entity
+                    switch (chtyp(ch)) {
+                        case 'd':
+                            bappend(ch);
+                            break;
+
+                        case ';':
+                            //          Convert the character entity to a character
+                            try {
+                                int i = Integer.parseInt(
+                                        new String(mBuff, idx + 1, mBuffIdx - idx), 10);
+                                if (i >= 0xffff) {
+                                    panic(FAULT);
+                                }
+                                ch = (char) i;
+                            } catch (NumberFormatException nfe) {
+                                panic(FAULT);
+                            }
+                            //          Restore the buffer offset
+                            mBuffIdx = idx - 1;
+                            if (ch == ' ' || mInp.next != null) {
+                                bappend(ch, flag);
+                            } else {
+                                bappend(ch);
+                            }
+                            st = -1;
+                            break;
+
+                        case 'a':
+                            //          If the entity buffer is empty and ch == 'x'
+                            if ((mBuffIdx == idx) && (ch == 'x')) {
+                                st = 3;
+                                break;
+                            }
+                        default:
+                            panic(FAULT);
+                    }
+                    break;
+
+                case 3:     // read hex character entity
+                    switch (chtyp(ch)) {
+                        case 'A':
+                        case 'a':
+                        case 'd':
+                            bappend(ch);
+                            break;
+
+                        case ';':
+                            //          Convert the character entity to a character
+                            try {
+                                int i = Integer.parseInt(
+                                        new String(mBuff, idx + 1, mBuffIdx - idx), 16);
+                                if (i >= 0xffff) {
+                                    panic(FAULT);
+                                }
+                                ch = (char) i;
+                            } catch (NumberFormatException nfe) {
+                                panic(FAULT);
+                            }
+                            //          Restore the buffer offset
+                            mBuffIdx = idx - 1;
+                            if (ch == ' ' || mInp.next != null) {
+                                bappend(ch, flag);
+                            } else {
+                                bappend(ch);
+                            }
+                            st = -1;
+                            break;
+
+                        default:
+                            panic(FAULT);
+                    }
+                    break;
+
+                default:
+                    panic(FAULT);
+            }
+        }
+
+        return str;
+    }
+
+    /**
+     * Resoves a parameter entity.
+     *
+     * This method resolves a parameter entity references. It is also reports
+     * external entities to the application.
+     *
+     * @param flag The '-' instruct the method to do not set up surrounding
+     * spaces [#4.4.8].
+     * @exception Exception is parser specific exception form panic method.
+     * @exception IOException
+     */
+    @SuppressWarnings("fallthrough")
+    private void pent(char flag) throws Exception {
+        char ch;
+        int idx = mBuffIdx + 1;
+        Input inp = null;
+        String str = null;
+        bappend('%');
+        if (mPh != PH_DTD) // the DTD internal subset
+        {
+            return;         // Not Recognized [#4.4.1]
+        }               //              Read entity name
+        bname(false);
+        str = new String(mBuff, idx + 2, mBuffIdx - idx - 1);
+        if (getch() != ';') {
+            panic(FAULT);
+        }
+        inp = mPEnt.get(str);
+        //              Restore the buffer offset
+        mBuffIdx = idx - 1;
+        if (inp != null) {
+            if (inp.chars == null) {
+                //              External parameter entity
+                InputSource is = resolveEnt(str, inp.pubid, inp.sysid);
+                if (is != null) {
+                    if (flag != '-') {
+                        bappend(' ');  // tail space
+                    }
+                    push(new Input(BUFFSIZE_READER));
+                    // BUG: there is no leading space! [#4.4.8]
+                    setinp(is);
+                    mInp.pubid = inp.pubid;
+                    mInp.sysid = inp.sysid;
+                } else {
+                    //          Unresolved external parameter entity
+                    skippedEnt("%" + str);
+                }
+            } else {
+                //              Internal parameter entity
+                if (flag == '-') {
+                    //          No surrounding spaces
+                    inp.chIdx = 1;
+                } else {
+                    //          Insert surrounding spaces
+                    bappend(' ');  // tail space
+                    inp.chIdx = 0;
+                }
+                push(inp);
+            }
+        } else {
+            //          Unknown parameter entity
+            skippedEnt("%" + str);
+        }
+    }
+
+    /**
+     * Recognizes and handles a namespace declaration.
+     *
+     * This method identifies a type of namespace declaration if any and puts
+     * new mapping on top of prefix stack.
+     *
+     * @param name The attribute qualified name (<code>name.value</code> is a
+     * <code>String</code> object which represents the attribute prefix).
+     * @param value The attribute value.
+     * @return <code>true</code> if a namespace declaration is recognized.
+     */
+    private boolean isdecl(Pair name, String value) {
+        if (name.chars[0] == 0) {
+            if ("xmlns".equals(name.name) == true) {
+                //              New default namespace declaration
+                mPref = pair(mPref);
+                mPref.list = mElm;  // prefix owner element
+                mPref.value = value;
+                mPref.name = "";
+                mPref.chars = NONS;
+                mElm.num++;  // namespace counter
+                return true;
+            }
+        } else {
+            if (name.eqpref(XMLNS) == true) {
+                //              New prefix declaration
+                int len = name.name.length();
+                mPref = pair(mPref);
+                mPref.list = mElm;  // prefix owner element
+                mPref.value = value;
+                mPref.name = name.name;
+                mPref.chars = new char[len + 1];
+                mPref.chars[0] = (char) (len + 1);
+                name.name.getChars(0, len, mPref.chars, 1);
+                mElm.num++;  // namespace counter
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Resolves a prefix.
+     *
+     * @return The namespace assigned to the prefix.
+     * @exception Exception When mapping for specified prefix is not found.
+     */
+    private String rslv(char[] qname)
+            throws Exception {
+        for (Pair pref = mPref; pref != null; pref = pref.next) {
+            if (pref.eqpref(qname) == true) {
+                return pref.value;
+            }
+        }
+        if (qname[0] == 1) {  // QNames like ':local'
+            for (Pair pref = mPref; pref != null; pref = pref.next) {
+                if (pref.chars[0] == 0) {
+                    return pref.value;
+                }
+            }
+        }
+        panic(FAULT);
+        return null;
+    }
+
+    /**
+     * Skips xml white space characters.
+     *
+     * This method skips white space characters (' ', '\t', '\n', '\r') and
+     * looks ahead not white space character.
+     *
+     * @return The first not white space look ahead character.
+     * @exception IOException
+     */
+    protected char wsskip()
+            throws IOException {
+        char ch;
+        while (true) {
+            //          Read next character
+            ch = (mChIdx < mChLen) ? mChars[mChIdx++] : getch();
+            if (ch < 0x80) {
+                if (nmttyp[ch] != 3) // [ \t\n\r]
+                {
+                    break;
+                }
+            } else {
+                break;
+            }
+        }
+        mChIdx--;  // bkch();
+        return ch;
+    }
+
+    /**
+     * Reports document type.
+     *
+     * @param name The name of the entity.
+     * @param pubid The public identifier of the entity or <code>null</code>.
+     * @param sysid The system identifier of the entity or <code>null</code>.
+     */
+    protected abstract void docType(String name, String pubid, String sysid)
+            throws SAXException;
+
+    /**
+     * Reports a comment.
+     *
+     * @param text The comment text starting from first charcater.
+     * @param length The number of characters in comment.
+     */
+    protected abstract void comm(char[] text, int length);
+
+    /**
+     * Reports a processing instruction.
+     *
+     * @param target The processing instruction target name.
+     * @param body The processing instruction body text.
+     */
+    protected abstract void pi(String target, String body)
+            throws Exception;
+
+    /**
+     * Reports new namespace prefix. The Namespace prefix (
+     * <code>mPref.name</code>) being declared and the Namespace URI (
+     * <code>mPref.value</code>) the prefix is mapped to. An empty string is
+     * used for the default element namespace, which has no prefix.
+     */
+    protected abstract void newPrefix()
+            throws Exception;
+
+    /**
+     * Reports skipped entity name.
+     *
+     * @param name The entity name.
+     */
+    protected abstract void skippedEnt(String name)
+            throws Exception;
+
+    /**
+     * Returns an
+     * <code>InputSource</code> for specified entity or
+     * <code>null</code>.
+     *
+     * @param name The name of the entity.
+     * @param pubid The public identifier of the entity.
+     * @param sysid The system identifier of the entity.
+     */
+    protected abstract InputSource resolveEnt(
+            String name, String pubid, String sysid)
+            throws Exception;
+
+    /**
+     * Reports notation declaration.
+     *
+     * @param name The notation's name.
+     * @param pubid The notation's public identifier, or null if none was given.
+     * @param sysid The notation's system identifier, or null if none was given.
+     */
+    protected abstract void notDecl(String name, String pubid, String sysid)
+            throws Exception;
+
+    /**
+     * Reports unparsed entity name.
+     *
+     * @param name The unparsed entity's name.
+     * @param pubid The entity's public identifier, or null if none was given.
+     * @param sysid The entity's system identifier.
+     * @param notation The name of the associated notation.
+     */
+    protected abstract void unparsedEntDecl(
+            String name, String pubid, String sysid, String notation)
+            throws Exception;
+
+    /**
+     * Notifies the handler about fatal parsing error.
+     *
+     * @param msg The problem description message.
+     */
+    protected abstract void panic(String msg)
+            throws Exception;
+
+    /**
+     * Reads a qualified xml name.
+     *
+     * This is low level routine which leaves a qName in the buffer. The
+     * characters of a qualified name is an array of characters. The first
+     * (chars[0]) character is the index of the colon character which separates
+     * the prefix from the local name. If the index is zero, the name does not
+     * contain separator or the parser works in the namespace unaware mode. The
+     * length of qualified name is the length of the array minus one.
+     *
+     * @param ns The true value turns namespace conformance on.
+     * @exception Exception is parser specific exception form panic method.
+     * @exception IOException
+     */
+    private void bname(boolean ns)
+            throws Exception {
+        char ch;
+        char type;
+        mBuffIdx++;  // allocate a char for colon offset
+        int bqname = mBuffIdx;
+        int bcolon = bqname;
+        int bchidx = bqname + 1;
+        int bstart = bchidx;
+        int cstart = mChIdx;
+        short st = (short) ((ns == true) ? 0 : 2);
+        while (true) {
+            //          Read next character
+            if (mChIdx >= mChLen) {
+                bcopy(cstart, bstart);
+                getch();
+                mChIdx--;  // bkch();
+                cstart = mChIdx;
+                bstart = bchidx;
+            }
+            ch = mChars[mChIdx++];
+            type = (char) 0;  // [X]
+            if (ch < 0x80) {
+                type = (char) nmttyp[ch];
+            } else if (ch == EOS) {
+                panic(FAULT);
+            }
+            //          Parse QName
+            switch (st) {
+                case 0:     // read the first char of the prefix
+                case 2:     // read the first char of the suffix
+                    switch (type) {
+                        case 0:  // [aA_X]
+                            bchidx++;  // append char to the buffer
+                            st++;      // (st == 0)? 1: 3;
+                            break;
+
+                        case 1:  // [:]
+                            mChIdx--;  // bkch();
+                            st++;      // (st == 0)? 1: 3;
+                            break;
+
+                        default:
+                            panic(FAULT);
+                    }
+                    break;
+
+                case 1:     // read the prefix
+                case 3:     // read the suffix
+                    switch (type) {
+                        case 0:  // [aA_X]
+                        case 2:  // [.-d]
+                            bchidx++;  // append char to the buffer
+                            break;
+
+                        case 1:  // [:]
+                            bchidx++;  // append char to the buffer
+                            if (ns == true) {
+                                if (bcolon != bqname) {
+                                    panic(FAULT);  // it must be only one colon
+                                }
+                                bcolon = bchidx - 1;
+                                if (st == 1) {
+                                    st = 2;
+                                }
+                            }
+                            break;
+
+                        default:
+                            mChIdx--;  // bkch();
+                            bcopy(cstart, bstart);
+                            mBuff[bqname] = (char) (bcolon - bqname);
+                            return;
+                    }
+                    break;
+
+                default:
+                    panic(FAULT);
+            }
+        }
+    }
+
+    /**
+     * Reads a nmtoken.
+     *
+     * This is low level routine which leaves a nmtoken in the buffer.
+     *
+     * @exception Exception is parser specific exception form panic method.
+     * @exception IOException
+     */
+    @SuppressWarnings("fallthrough")
+    private void bntok() throws Exception {
+        char ch;
+        mBuffIdx = -1;
+        bappend((char) 0);  // default offset to the colon char
+        while (true) {
+            ch = getch();
+            switch (chtyp(ch)) {
+                case 'a':
+                case 'A':
+                case 'd':
+                case '.':
+                case ':':
+                case '-':
+                case '_':
+                case 'X':
+                    bappend(ch);
+                    break;
+
+                case 'Z':
+                    panic(FAULT);
+
+                default:
+                    bkch();
+                    return;
+            }
+        }
+    }
+
+    /**
+     * Recognizes a keyword.
+     *
+     * This is low level routine which recognizes one of keywords in the buffer.
+     * Keyword Id ID - i IDREF - r IDREFS - R ENTITY - n ENTITIES - N NMTOKEN -
+     * t NMTOKENS - T ELEMENT - e ATTLIST - a NOTATION - o CDATA - c REQUIRED -
+     * Q IMPLIED - I FIXED - F
+     *
+     * @return an id of a keyword or '?'.
+     * @exception Exception is parser specific exception form panic method.
+     * @exception IOException
+     */
+    private char bkeyword()
+            throws Exception {
+        String str = new String(mBuff, 1, mBuffIdx);
+        switch (str.length()) {
+            case 2:  // ID
+                return ("ID".equals(str) == true) ? 'i' : '?';
+
+            case 5:  // IDREF, CDATA, FIXED
+                switch (mBuff[1]) {
+                    case 'I':
+                        return ("IDREF".equals(str) == true) ? 'r' : '?';
+                    case 'C':
+                        return ("CDATA".equals(str) == true) ? 'c' : '?';
+                    case 'F':
+                        return ("FIXED".equals(str) == true) ? 'F' : '?';
+                    default:
+                        break;
+                }
+                break;
+
+            case 6:  // IDREFS, ENTITY
+                switch (mBuff[1]) {
+                    case 'I':
+                        return ("IDREFS".equals(str) == true) ? 'R' : '?';
+                    case 'E':
+                        return ("ENTITY".equals(str) == true) ? 'n' : '?';
+                    default:
+                        break;
+                }
+                break;
+
+            case 7:  // NMTOKEN, IMPLIED, ATTLIST, ELEMENT
+                switch (mBuff[1]) {
+                    case 'I':
+                        return ("IMPLIED".equals(str) == true) ? 'I' : '?';
+                    case 'N':
+                        return ("NMTOKEN".equals(str) == true) ? 't' : '?';
+                    case 'A':
+                        return ("ATTLIST".equals(str) == true) ? 'a' : '?';
+                    case 'E':
+                        return ("ELEMENT".equals(str) == true) ? 'e' : '?';
+                    default:
+                        break;
+                }
+                break;
+
+            case 8:  // ENTITIES, NMTOKENS, NOTATION, REQUIRED
+                switch (mBuff[2]) {
+                    case 'N':
+                        return ("ENTITIES".equals(str) == true) ? 'N' : '?';
+                    case 'M':
+                        return ("NMTOKENS".equals(str) == true) ? 'T' : '?';
+                    case 'O':
+                        return ("NOTATION".equals(str) == true) ? 'o' : '?';
+                    case 'E':
+                        return ("REQUIRED".equals(str) == true) ? 'Q' : '?';
+                    default:
+                        break;
+                }
+                break;
+
+            default:
+                break;
+        }
+        return '?';
+    }
+
+    /**
+     * Reads a single or double quotted string in to the buffer.
+     *
+     * This method resolves entities inside a string unless the parser parses
+     * DTD.
+     *
+     * @param flag 'c' - CDATA, 'i' - non CDATA, ' ' - no normalization; '-' -
+     * not an attribute value; 'd' - in DTD context.
+     * @exception Exception is parser specific exception form panic method.
+     * @exception IOException
+     */
+    @SuppressWarnings("fallthrough")
+    private void bqstr(char flag) throws Exception {
+        Input inp = mInp;  // remember the original input
+        mBuffIdx = -1;
+        bappend((char) 0);  // default offset to the colon char
+        char ch;
+        for (short st = 0; st >= 0;) {
+            ch = (mChIdx < mChLen) ? mChars[mChIdx++] : getch();
+            switch (st) {
+                case 0:     // read a single or double quote
+                    switch (ch) {
+                        case ' ':
+                        case '\n':
+                        case '\r':
+                        case '\t':
+                            break;
+
+                        case '\'':
+                            st = 2;  // read a single quoted string
+                            break;
+
+                        case '\"':
+                            st = 3;  // read a double quoted string
+                            break;
+
+                        default:
+                            panic(FAULT);
+                            break;
+                    }
+                    break;
+
+                case 2:     // read a single quoted string
+                case 3:     // read a double quoted string
+                    switch (ch) {
+                        case '\'':
+                            if ((st == 2) && (mInp == inp)) {
+                                st = -1;
+                            } else {
+                                bappend(ch);
+                            }
+                            break;
+
+                        case '\"':
+                            if ((st == 3) && (mInp == inp)) {
+                                st = -1;
+                            } else {
+                                bappend(ch);
+                            }
+                            break;
+
+                        case '&':
+                            if (flag != 'd') {
+                                ent(flag);
+                            } else {
+                                bappend(ch);
+                            }
+                            break;
+
+                        case '%':
+                            if (flag == 'd') {
+                                pent('-');
+                            } else {
+                                bappend(ch);
+                            }
+                            break;
+
+                        case '<':
+                            if ((flag == '-') || (flag == 'd')) {
+                                bappend(ch);
+                            } else {
+                                panic(FAULT);
+                            }
+                            break;
+
+                        case EOS:               // EOS before single/double quote
+                            panic(FAULT);
+
+                        case '\r':     // EOL processing [#2.11 & #3.3.3]
+                            if (flag != ' ' && mInp.next == null) {
+                                if (getch() != '\n') {
+                                    bkch();
+                                }
+                                ch = '\n';
+                            }
+                        default:
+                            bappend(ch, flag);
+                            break;
+                    }
+                    break;
+
+                default:
+                    panic(FAULT);
+            }
+        }
+        //              There is maximum one space at the end of the string in
+        //              i-mode (non CDATA normalization) and it has to be removed.
+        if ((flag == 'i') && (mBuff[mBuffIdx] == ' ')) {
+            mBuffIdx -= 1;
+        }
+    }
+
+    /**
+     * Reports characters and empties the parser's buffer. This method is called
+     * only if parser is going to return control to the main loop. This means
+     * that this method may use parser buffer to report white space without
+     * copeing characters to temporary buffer.
+     */
+    protected abstract void bflash()
+            throws Exception;
+
+    /**
+     * Reports white space characters and empties the parser's buffer. This
+     * method is called only if parser is going to return control to the main
+     * loop. This means that this method may use parser buffer to report white
+     * space without copeing characters to temporary buffer.
+     */
+    protected abstract void bflash_ws()
+            throws Exception;
+
+    /**
+     * Appends a character to parser's buffer with normalization.
+     *
+     * @param ch The character to append to the buffer.
+     * @param mode The normalization mode.
+     */
+    private void bappend(char ch, char mode) {
+        //              This implements attribute value normalization as
+        //              described in the XML specification [#3.3.3].
+        switch (mode) {
+            case 'i':  // non CDATA normalization
+                switch (ch) {
+                    case ' ':
+                    case '\n':
+                    case '\r':
+                    case '\t':
+                        if ((mBuffIdx > 0) && (mBuff[mBuffIdx] != ' ')) {
+                            bappend(' ');
+                        }
+                        return;
+
+                    default:
+                        break;
+                }
+                break;
+
+            case 'c':  // CDATA normalization
+                switch (ch) {
+                    case '\n':
+                    case '\r':
+                    case '\t':
+                        ch = ' ';
+                        break;
+
+                    default:
+                        break;
+                }
+                break;
+
+            default:  // no normalization
+                break;
+        }
+        mBuffIdx++;
+        if (mBuffIdx < mBuff.length) {
+            mBuff[mBuffIdx] = ch;
+        } else {
+            mBuffIdx--;
+            bappend(ch);
+        }
+    }
+
+    /**
+     * Appends a character to parser's buffer.
+     *
+     * @param ch The character to append to the buffer.
+     */
+    private void bappend(char ch) {
+        try {
+            mBuff[++mBuffIdx] = ch;
+        } catch (Exception exp) {
+            //          Double the buffer size
+            char buff[] = new char[mBuff.length << 1];
+            System.arraycopy(mBuff, 0, buff, 0, mBuff.length);
+            mBuff = buff;
+            mBuff[mBuffIdx] = ch;
+        }
+    }
+
+    /**
+     * Appends (mChIdx - cidx) characters from character buffer (mChars) to
+     * parser's buffer (mBuff).
+     *
+     * @param cidx The character buffer (mChars) start index.
+     * @param bidx The parser buffer (mBuff) start index.
+     */
+    private void bcopy(int cidx, int bidx) {
+        int length = mChIdx - cidx;
+        if ((bidx + length + 1) >= mBuff.length) {
+            //          Expand the buffer
+            char buff[] = new char[mBuff.length + length];
+            System.arraycopy(mBuff, 0, buff, 0, mBuff.length);
+            mBuff = buff;
+        }
+        System.arraycopy(mChars, cidx, mBuff, bidx, length);
+        mBuffIdx += length;
+    }
+
+    /**
+     * Recognizes the built-in entities <i>lt</i>, <i>gt</i>, <i>amp</i>,
+     * <i>apos</i>, <i>quot</i>. The initial state is 0x100. Any state belowe
+     * 0x100 is a built-in entity replacement character.
+     *
+     * @param ch the next character of an entity name.
+     */
+    @SuppressWarnings("fallthrough")
+    private void eappend(char ch) {
+        switch (mESt) {
+            case 0x100:  // "l" or "g" or "a" or "q"
+                switch (ch) {
+                    case 'l':
+                        mESt = 0x101;
+                        break;
+                    case 'g':
+                        mESt = 0x102;
+                        break;
+                    case 'a':
+                        mESt = 0x103;
+                        break;
+                    case 'q':
+                        mESt = 0x107;
+                        break;
+                    default:
+                        mESt = 0x200;
+                        break;
+                }
+                break;
+
+            case 0x101:  // "lt"
+                mESt = (ch == 't') ? '<' : (char) 0x200;
+                break;
+
+            case 0x102:  // "gt"
+                mESt = (ch == 't') ? '>' : (char) 0x200;
+                break;
+
+            case 0x103:  // "am" or "ap"
+                switch (ch) {
+                    case 'm':
+                        mESt = 0x104;
+                        break;
+                    case 'p':
+                        mESt = 0x105;
+                        break;
+                    default:
+                        mESt = 0x200;
+                        break;
+                }
+                break;
+
+            case 0x104:  // "amp"
+                mESt = (ch == 'p') ? '&' : (char) 0x200;
+                break;
+
+            case 0x105:  // "apo"
+                mESt = (ch == 'o') ? (char) 0x106 : (char) 0x200;
+                break;
+
+            case 0x106:  // "apos"
+                mESt = (ch == 's') ? '\'' : (char) 0x200;
+                break;
+
+            case 0x107:  // "qu"
+                mESt = (ch == 'u') ? (char) 0x108 : (char) 0x200;
+                break;
+
+            case 0x108:  // "quo"
+                mESt = (ch == 'o') ? (char) 0x109 : (char) 0x200;
+                break;
+
+            case 0x109:  // "quot"
+                mESt = (ch == 't') ? '\"' : (char) 0x200;
+                break;
+
+            case '<':   // "lt"
+            case '>':   // "gt"
+            case '&':   // "amp"
+            case '\'':  // "apos"
+            case '\"':  // "quot"
+                mESt = 0x200;
+            default:
+                break;
+        }
+    }
+
+    /**
+     * Sets up a new input source on the top of the input stack. Note, the first
+     * byte returned by the entity's byte stream has to be the first byte in the
+     * entity. However, the parser does not expect the byte order mask in both
+     * cases when encoding is provided by the input source.
+     *
+     * @param is A new input source to set up.
+     * @exception IOException If any IO errors occur.
+     * @exception Exception is parser specific exception form panic method.
+     */
+    protected void setinp(InputSource is)
+            throws Exception {
+        Reader reader = null;
+        mChIdx = 0;
+        mChLen = 0;
+        mChars = mInp.chars;
+        mInp.src = null;
+        if (mPh < PH_DOC_START) {
+            mIsSAlone = false;  // default [#2.9]
+        }
+        mIsSAloneSet = false;
+        if (is.getCharacterStream() != null) {
+            //          Ignore encoding in the xml text decl.
+            reader = is.getCharacterStream();
+            xml(reader);
+        } else if (is.getByteStream() != null) {
+            String expenc;
+            if (is.getEncoding() != null) {
+                //              Ignore encoding in the xml text decl.
+                expenc = is.getEncoding().toUpperCase();
+                if (expenc.equals("UTF-16")) {
+                    reader = bom(is.getByteStream(), 'U');  // UTF-16 [#4.3.3]
+                } else {
+                    reader = enc(expenc, is.getByteStream());
+                }
+                xml(reader);
+            } else {
+                //              Get encoding from BOM or the xml text decl.
+                reader = bom(is.getByteStream(), ' ');
+                if (reader == null) {
+                    //          Encoding is defined by the xml text decl.
+                    reader = enc("UTF-8", is.getByteStream());
+                    expenc = xml(reader);
+                    if (expenc.startsWith("UTF-16")) {
+                        panic(FAULT);  // UTF-16 must have BOM [#4.3.3]
+                    }
+                    reader = enc(expenc, is.getByteStream());
+                } else {
+                    //          Encoding is defined by the BOM.
+                    xml(reader);
+                }
+            }
+        } else {
+            //          There is no support for public/system identifiers.
+            panic(FAULT);
+        }
+        mInp.src = reader;
+        mInp.pubid = is.getPublicId();
+        mInp.sysid = is.getSystemId();
+    }
+
+    /**
+     * Determines the entity encoding.
+     *
+     * This method gets encoding from Byte Order Mask [#4.3.3] if any. Note, the
+     * first byte returned by the entity's byte stream has to be the first byte
+     * in the entity. Also, there is no support for UCS-4.
+     *
+     * @param is A byte stream of the entity.
+     * @param hint An encoding hint, character U means UTF-16.
+     * @return a reader constructed from the BOM or UTF-8 by default.
+     * @exception Exception is parser specific exception form panic method.
+     * @exception IOException
+     */
+    private Reader bom(InputStream is, char hint)
+            throws Exception {
+        int val = is.read();
+        switch (val) {
+            case 0xef:     // UTF-8
+                if (hint == 'U') // must be UTF-16
+                {
+                    panic(FAULT);
+                }
+                if (is.read() != 0xbb) {
+                    panic(FAULT);
+                }
+                if (is.read() != 0xbf) {
+                    panic(FAULT);
+                }
+                return new ReaderUTF8(is);
+
+            case 0xfe:     // UTF-16, big-endian
+                if (is.read() != 0xff) {
+                    panic(FAULT);
+                }
+                return new ReaderUTF16(is, 'b');
+
+            case 0xff:     // UTF-16, little-endian
+                if (is.read() != 0xfe) {
+                    panic(FAULT);
+                }
+                return new ReaderUTF16(is, 'l');
+
+            case -1:
+                mChars[mChIdx++] = EOS;
+                return new ReaderUTF8(is);
+
+            default:
+                if (hint == 'U') // must be UTF-16
+                {
+                    panic(FAULT);
+                }
+                //              Read the rest of UTF-8 character
+                switch (val & 0xf0) {
+                    case 0xc0:
+                    case 0xd0:
+                        mChars[mChIdx++] = (char) (((val & 0x1f) << 6) | (is.read() & 0x3f));
+                        break;
+
+                    case 0xe0:
+                        mChars[mChIdx++] = (char) (((val & 0x0f) << 12)
+                                | ((is.read() & 0x3f) << 6) | (is.read() & 0x3f));
+                        break;
+
+                    case 0xf0:  // UCS-4 character
+                        throw new UnsupportedEncodingException();
+
+                    default:
+                        mChars[mChIdx++] = (char) val;
+                        break;
+                }
+                return null;
+        }
+    }
+
+    /**
+     * Parses the xml text declaration.
+     *
+     * This method gets encoding from the xml text declaration [#4.3.1] if any.
+     * The method assumes the buffer (mChars) is big enough to accomodate whole
+     * xml text declaration.
+     *
+     * @param reader is entity reader.
+     * @return The xml text declaration encoding or default UTF-8 encoding.
+     * @exception Exception is parser specific exception form panic method.
+     * @exception IOException
+     */
+    private String xml(Reader reader)
+            throws Exception {
+        String str = null;
+        String enc = "UTF-8";
+        char ch;
+        int val;
+        short st;
+        //              Read the xml text declaration into the buffer
+        if (mChIdx != 0) {
+            //          The bom method have read ONE char into the buffer.
+            st = (short) ((mChars[0] == '<') ? 1 : -1);
+        } else {
+            st = 0;
+        }
+        while (st >= 0 && mChIdx < mChars.length) {
+            ch = ((val = reader.read()) >= 0) ? (char) val : EOS;
+            mChars[mChIdx++] = ch;
+            switch (st) {
+                case 0:     // read '<' of xml declaration
+                    switch (ch) {
+                        case '<':
+                            st = 1;
+                            break;
+
+                        case 0xfeff:    // the byte order mask
+                            ch = ((val = reader.read()) >= 0) ? (char) val : EOS;
+                            mChars[mChIdx - 1] = ch;
+                            st = (short) ((ch == '<') ? 1 : -1);
+                            break;
+
+                        default:
+                            st = -1;
+                            break;
+                    }
+                    break;
+
+                case 1:     // read '?' of xml declaration [#4.3.1]
+                    st = (short) ((ch == '?') ? 2 : -1);
+                    break;
+
+                case 2:     // read 'x' of xml declaration [#4.3.1]
+                    st = (short) ((ch == 'x') ? 3 : -1);
+                    break;
+
+                case 3:     // read 'm' of xml declaration [#4.3.1]
+                    st = (short) ((ch == 'm') ? 4 : -1);
+                    break;
+
+                case 4:     // read 'l' of xml declaration [#4.3.1]
+                    st = (short) ((ch == 'l') ? 5 : -1);
+                    break;
+
+                case 5:     // read white space after 'xml'
+                    switch (ch) {
+                        case ' ':
+                        case '\t':
+                        case '\r':
+                        case '\n':
+                            st = 6;
+                            break;
+
+                        default:
+                            st = -1;
+                            break;
+                    }
+                    break;
+
+                case 6:     // read content of xml declaration
+                    switch (ch) {
+                        case '?':
+                            st = 7;
+                            break;
+
+                        case EOS:
+                            st = -2;
+                            break;
+
+                        default:
+                            break;
+                    }
+                    break;
+
+                case 7:     // read '>' after '?' of xml declaration
+                    switch (ch) {
+                        case '>':
+                        case EOS:
+                            st = -2;
+                            break;
+
+                        default:
+                            st = 6;
+                            break;
+                    }
+                    break;
+
+                default:
+                    panic(FAULT);
+                    break;
+            }
+        }
+        mChLen = mChIdx;
+        mChIdx = 0;
+        //              If there is no xml text declaration, the encoding is default.
+        if (st == -1) {
+            return enc;
+        }
+        mChIdx = 5;  // the first white space after "<?xml"
+        //              Parse the xml text declaration
+        for (st = 0; st >= 0;) {
+            ch = getch();
+            switch (st) {
+                case 0:     // skip spaces after the xml declaration name
+                    if (chtyp(ch) != ' ') {
+                        bkch();
+                        st = 1;
+                    }
+                    break;
+
+                case 1:     // read xml declaration version
+                case 2:     // read xml declaration encoding or standalone
+                case 3:     // read xml declaration standalone
+                    switch (chtyp(ch)) {
+                        case 'a':
+                        case 'A':
+                        case '_':
+                            bkch();
+                            str = name(false).toLowerCase();
+                            if ("version".equals(str) == true) {
+                                if (st != 1) {
+                                    panic(FAULT);
+                                }
+                                if ("1.0".equals(eqstr('=')) != true) {
+                                    panic(FAULT);
+                                }
+                                mInp.xmlver = 0x0100;
+                                st = 2;
+                            } else if ("encoding".equals(str) == true) {
+                                if (st != 2) {
+                                    panic(FAULT);
+                                }
+                                mInp.xmlenc = eqstr('=').toUpperCase();
+                                enc = mInp.xmlenc;
+                                st = 3;
+                            } else if ("standalone".equals(str) == true) {
+                                if ((st == 1) || (mPh >= PH_DOC_START)) // [#4.3.1]
+                                {
+                                    panic(FAULT);
+                                }
+                                str = eqstr('=').toLowerCase();
+                                //              Check the 'standalone' value and use it [#5.1]
+                                if (str.equals("yes") == true) {
+                                    mIsSAlone = true;
+                                } else if (str.equals("no") == true) {
+                                    mIsSAlone = false;
+                                } else {
+                                    panic(FAULT);
+                                }
+                                mIsSAloneSet = true;
+                                st = 4;
+                            } else {
+                                panic(FAULT);
+                            }
+                            break;
+
+                        case ' ':
+                            break;
+
+                        case '?':
+                            if (st == 1) {
+                                panic(FAULT);
+                            }
+                            bkch();
+                            st = 4;
+                            break;
+
+                        default:
+                            panic(FAULT);
+                    }
+                    break;
+
+                case 4:     // end of xml declaration
+                    switch (chtyp(ch)) {
+                        case '?':
+                            if (getch() != '>') {
+                                panic(FAULT);
+                            }
+                            if (mPh <= PH_DOC_START) {
+                                mPh = PH_MISC_DTD;  // misc before DTD
+                            }
+                            st = -1;
+                            break;
+
+                        case ' ':
+                            break;
+
+                        default:
+                            panic(FAULT);
+                    }
+                    break;
+
+                default:
+                    panic(FAULT);
+            }
+        }
+        return enc;
+    }
+
+    /**
+     * Sets up the document reader.
+     *
+     * @param name an encoding name.
+     * @param is the document byte input stream.
+     * @return a reader constructed from encoding name and input stream.
+     * @exception UnsupportedEncodingException
+     */
+    private Reader enc(String name, InputStream is)
+            throws UnsupportedEncodingException {
+        //              DO NOT CLOSE current reader if any!
+        if (name.equals("UTF-8")) {
+            return new ReaderUTF8(is);
+        } else if (name.equals("UTF-16LE")) {
+            return new ReaderUTF16(is, 'l');
+        } else if (name.equals("UTF-16BE")) {
+            return new ReaderUTF16(is, 'b');
+        } else {
+            return new InputStreamReader(is, name);
+        }
+    }
+
+    /**
+     * Sets up current input on the top of the input stack.
+     *
+     * @param inp A new input to set up.
+     */
+    protected void push(Input inp) {
+        mInp.chLen = mChLen;
+        mInp.chIdx = mChIdx;
+        inp.next = mInp;
+        mInp = inp;
+        mChars = inp.chars;
+        mChLen = inp.chLen;
+        mChIdx = inp.chIdx;
+    }
+
+    /**
+     * Restores previous input on the top of the input stack.
+     */
+    protected void pop() {
+        if (mInp.src != null) {
+            try {
+                mInp.src.close();
+            } catch (IOException ioe) {
+            }
+            mInp.src = null;
+        }
+        mInp = mInp.next;
+        if (mInp != null) {
+            mChars = mInp.chars;
+            mChLen = mInp.chLen;
+            mChIdx = mInp.chIdx;
+        } else {
+            mChars = null;
+            mChLen = 0;
+            mChIdx = 0;
+        }
+    }
+
+    /**
+     * Maps a character to it's type.
+     *
+     * Possible character type values are:<br /> - ' ' for any kind of white
+     * space character;<br /> - 'a' for any lower case alphabetical character
+     * value;<br /> - 'A' for any upper case alphabetical character value;<br />
+     * - 'd' for any decimal digit character value;<br /> - 'z' for any
+     * character less then ' ' except '\t', '\n', '\r';<br /> - 'X' for any not
+     * ASCII character;<br /> - 'Z' for EOS character.<br /> An ASCII (7 bit)
+     * character which does not fall in any category listed above is mapped to
+     * it self.
+     *
+     * @param ch The character to map.
+     * @return The type of character.
+     */
+    protected char chtyp(char ch) {
+        if (ch < 0x80) {
+            return (char) asctyp[ch];
+        }
+        return (ch != EOS) ? 'X' : 'Z';
+    }
+
+    /**
+     * Retrives the next character in the document.
+     *
+     * @return The next character in the document.
+     */
+    protected char getch()
+            throws IOException {
+        if (mChIdx >= mChLen) {
+            if (mInp.src == null) {
+                pop();  // remove internal entity
+                return getch();
+            }
+            //          Read new portion of the document characters
+            int Num = mInp.src.read(mChars, 0, mChars.length);
+            if (Num < 0) {
+                if (mInp != mDoc) {
+                    pop();  // restore the previous input
+                    return getch();
+                } else {
+                    mChars[0] = EOS;
+                    mChLen = 1;
+                }
+            } else {
+                mChLen = Num;
+            }
+            mChIdx = 0;
+        }
+        return mChars[mChIdx++];
+    }
+
+    /**
+     * Puts back the last read character.
+     *
+     * This method <strong>MUST NOT</strong> be called more then once after each
+     * call of {@link #getch getch} method.
+     */
+    protected void bkch()
+            throws Exception {
+        if (mChIdx <= 0) {
+            panic(FAULT);
+        }
+        mChIdx--;
+    }
+
+    /**
+     * Sets the current character.
+     *
+     * @param ch The character to set.
+     */
+    protected void setch(char ch) {
+        mChars[mChIdx] = ch;
+    }
+
+    /**
+     * Finds a pair in the pair chain by a qualified name.
+     *
+     * @param chain The first element of the chain of pairs.
+     * @param qname The qualified name.
+     * @return A pair with the specified qualified name or null.
+     */
+    protected Pair find(Pair chain, char[] qname) {
+        for (Pair pair = chain; pair != null; pair = pair.next) {
+            if (pair.eqname(qname) == true) {
+                return pair;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Provedes an instance of a pair.
+     *
+     * @param next The reference to a next pair.
+     * @return An instance of a pair.
+     */
+    protected Pair pair(Pair next) {
+        Pair pair;
+
+        if (mDltd != null) {
+            pair = mDltd;
+            mDltd = pair.next;
+        } else {
+            pair = new Pair();
+        }
+        pair.next = next;
+
+        return pair;
+    }
+
+    /**
+     * Deletes an instance of a pair.
+     *
+     * @param pair The pair to delete.
+     * @return A reference to the next pair in a chain.
+     */
+    protected Pair del(Pair pair) {
+        Pair next = pair.next;
+
+        pair.name = null;
+        pair.value = null;
+        pair.chars = null;
+        pair.list = null;
+        pair.next = mDltd;
+        mDltd = pair;
+
+        return next;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/jdk/internal/util/xml/impl/ParserSAX.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,695 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.util.xml.impl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import jdk.internal.org.xml.sax.ContentHandler;
+import jdk.internal.org.xml.sax.DTDHandler;
+import jdk.internal.org.xml.sax.EntityResolver;
+import jdk.internal.org.xml.sax.ErrorHandler;
+import jdk.internal.org.xml.sax.InputSource;
+import jdk.internal.org.xml.sax.Locator;
+import jdk.internal.org.xml.sax.SAXException;
+import jdk.internal.org.xml.sax.SAXParseException;
+import jdk.internal.org.xml.sax.XMLReader;
+import jdk.internal.org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * XML non-validating push parser.
+ *
+ * This non-validating parser conforms to <a href="http://www.w3.org/TR/REC-xml"
+ * >Extensible Markup Language (XML) 1.0</a> and <a
+ * href="http://www.w3.org/TR/REC-xml-names" >"Namespaces in XML"</a>
+ * specifications. The API supported by the parser are <a
+ * href="http://java.sun.com/aboutJava/communityprocess/final/jsr030/index.html">CLDC
+ * 1.0</a> and <a href="http://www.jcp.org/en/jsr/detail?id=280">JSR-280</a>, a
+ * JavaME subset of <a href="http://java.sun.com/xml/jaxp/index.html">JAXP</a>
+ * and <a href="http://www.saxproject.org/">SAX2</a>.
+ *
+ * @see org.xml.sax.XMLReader
+ */
+
+final class ParserSAX
+    extends Parser implements XMLReader, Locator
+{
+    public final static String FEATURE_NS =
+            "http://xml.org/sax/features/namespaces";
+    public final static String FEATURE_PREF =
+            "http://xml.org/sax/features/namespace-prefixes";
+    //          SAX feature flags
+    private boolean mFNamespaces;
+    private boolean mFPrefixes;
+    //          SAX handlers
+    private DefaultHandler mHand;      // the default handler
+    private ContentHandler mHandCont;  // the content handler
+    private DTDHandler mHandDtd;   // the DTD handler
+    private ErrorHandler mHandErr;   // the error handler
+    private EntityResolver mHandEnt;   // the entity resolver
+
+    /**
+     * Constructor.
+     */
+    public ParserSAX() {
+        super();
+
+        //              SAX feature defaut values
+        mFNamespaces = true;
+        mFPrefixes = false;
+
+        //              Default handler which will be used in case the application
+        //              do not set one of handlers.
+        mHand = new DefaultHandler();
+        mHandCont = mHand;
+        mHandDtd = mHand;
+        mHandErr = mHand;
+        mHandEnt = mHand;
+    }
+
+    /**
+     * Return the current content handler.
+     *
+     * @return The current content handler, or null if none has been registered.
+     * @see #setContentHandler
+     */
+    public ContentHandler getContentHandler() {
+        return (mHandCont != mHand) ? mHandCont : null;
+    }
+
+    /**
+     * Allow an application to register a content event handler.
+     *
+     * <p>If the application does not register a content handler, all content
+     * events reported by the SAX parser will be silently ignored.</p>
+     *
+     * <p>Applications may register a new or different handler in the middle of
+     * a parse, and the SAX parser must begin using the new handler
+     * immediately.</p>
+     *
+     * @param handler The content handler.
+     * @exception java.lang.NullPointerException If the handler argument is
+     * null.
+     * @see #getContentHandler
+     */
+    public void setContentHandler(ContentHandler handler) {
+        if (handler == null) {
+            throw new NullPointerException();
+        }
+        mHandCont = handler;
+    }
+
+    /**
+     * Return the current DTD handler.
+     *
+     * @return The current DTD handler, or null if none has been registered.
+     * @see #setDTDHandler
+     */
+    public DTDHandler getDTDHandler() {
+        return (mHandDtd != mHand) ? mHandDtd : null;
+    }
+
+    /**
+     * Allow an application to register a DTD event handler.
+     *
+     * <p>If the application does not register a DTD handler, all DTD events
+     * reported by the SAX parser will be silently ignored.</p>
+     *
+     * <p>Applications may register a new or different handler in the middle of
+     * a parse, and the SAX parser must begin using the new handler
+     * immediately.</p>
+     *
+     * @param handler The DTD handler.
+     * @exception java.lang.NullPointerException If the handler argument is
+     * null.
+     * @see #getDTDHandler
+     */
+    public void setDTDHandler(DTDHandler handler) {
+        if (handler == null) {
+            throw new NullPointerException();
+        }
+        mHandDtd = handler;
+    }
+
+    /**
+     * Return the current error handler.
+     *
+     * @return The current error handler, or null if none has been registered.
+     * @see #setErrorHandler
+     */
+    public ErrorHandler getErrorHandler() {
+        return (mHandErr != mHand) ? mHandErr : null;
+    }
+
+    /**
+     * Allow an application to register an error event handler.
+     *
+     * <p>If the application does not register an error handler, all error
+     * events reported by the SAX parser will be silently ignored; however,
+     * normal processing may not continue. It is highly recommended that all SAX
+     * applications implement an error handler to avoid unexpected bugs.</p>
+     *
+     * <p>Applications may register a new or different handler in the middle of
+     * a parse, and the SAX parser must begin using the new handler
+     * immediately.</p>
+     *
+     * @param handler The error handler.
+     * @exception java.lang.NullPointerException If the handler argument is
+     * null.
+     * @see #getErrorHandler
+     */
+    public void setErrorHandler(ErrorHandler handler) {
+        if (handler == null) {
+            throw new NullPointerException();
+        }
+        mHandErr = handler;
+    }
+
+    /**
+     * Return the current entity resolver.
+     *
+     * @return The current entity resolver, or null if none has been registered.
+     * @see #setEntityResolver
+     */
+    public EntityResolver getEntityResolver() {
+        return (mHandEnt != mHand) ? mHandEnt : null;
+    }
+
+    /**
+     * Allow an application to register an entity resolver.
+     *
+     * <p>If the application does not register an entity resolver, the XMLReader
+     * will perform its own default resolution.</p>
+     *
+     * <p>Applications may register a new or different resolver in the middle of
+     * a parse, and the SAX parser must begin using the new resolver
+     * immediately.</p>
+     *
+     * @param resolver The entity resolver.
+     * @exception java.lang.NullPointerException If the resolver argument is
+     * null.
+     * @see #getEntityResolver
+     */
+    public void setEntityResolver(EntityResolver resolver) {
+        if (resolver == null) {
+            throw new NullPointerException();
+        }
+        mHandEnt = resolver;
+    }
+
+    /**
+     * Return the public identifier for the current document event.
+     *
+     * <p>The return value is the public identifier of the document entity or of
+     * the external parsed entity in which the markup triggering the event
+     * appears.</p>
+     *
+     * @return A string containing the public identifier, or null if none is
+     * available.
+     *
+     * @see #getSystemId
+     */
+    public String getPublicId() {
+        return (mInp != null) ? mInp.pubid : null;
+    }
+
+    /**
+     * Return the system identifier for the current document event.
+     *
+     * <p>The return value is the system identifier of the document entity or of
+     * the external parsed entity in which the markup triggering the event
+     * appears.</p>
+     *
+     * <p>If the system identifier is a URL, the parser must resolve it fully
+     * before passing it to the application.</p>
+     *
+     * @return A string containing the system identifier, or null if none is
+     * available.
+     *
+     * @see #getPublicId
+     */
+    public String getSystemId() {
+        return (mInp != null) ? mInp.sysid : null;
+    }
+
+    /**
+     * Return the line number where the current document event ends.
+     *
+     * @return Always returns -1 indicating the line number is not available.
+     *
+     * @see #getColumnNumber
+     */
+    public int getLineNumber() {
+        return -1;
+    }
+
+    /**
+     * Return the column number where the current document event ends.
+     *
+     * @return Always returns -1 indicating the column number is not available.
+     *
+     * @see #getLineNumber
+     */
+    public int getColumnNumber() {
+        return -1;
+    }
+
+    /**
+     * Parse an XML document from a system identifier (URI).
+     *
+     * <p>This method is a shortcut for the common case of reading a document
+     * from a system identifier. It is the exact equivalent of the
+     * following:</p>
+     *
+     * <pre>
+     * parse(new InputSource(systemId));
+     * </pre>
+     *
+     * <p>If the system identifier is a URL, it must be fully resolved by the
+     * application before it is passed to the parser.</p>
+     *
+     * @param systemId The system identifier (URI).
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly wrapping
+     * another exception.
+     * @exception java.io.IOException An IO exception from the parser, possibly
+     * from a byte stream or character stream supplied by the application.
+     * @see #parse(org.xml.sax.InputSource)
+     */
+    public void parse(String systemId) throws IOException, SAXException {
+        parse(new InputSource(systemId));
+    }
+
+    /**
+     * Parse an XML document.
+     *
+     * <p>The application can use this method to instruct the XML reader to
+     * begin parsing an XML document from any valid input source (a character
+     * stream, a byte stream, or a URI).</p>
+     *
+     * <p>Applications may not invoke this method while a parse is in progress
+     * (they should create a new XMLReader instead for each nested XML
+     * document). Once a parse is complete, an application may reuse the same
+     * XMLReader object, possibly with a different input source.</p>
+     *
+     * <p>During the parse, the XMLReader will provide information about the XML
+     * document through the registered event handlers.</p>
+     *
+     * <p>This method is synchronous: it will not return until parsing has
+     * ended. If a client application wants to terminate parsing early, it
+     * should throw an exception.</p>
+     *
+     * @param is The input source for the top-level of the XML document.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly wrapping
+     * another exception.
+     * @exception java.io.IOException An IO exception from the parser, possibly
+     * from a byte stream or character stream supplied by the application.
+     * @see org.xml.sax.InputSource
+     * @see #parse(java.lang.String)
+     * @see #setEntityResolver
+     * @see #setDTDHandler
+     * @see #setContentHandler
+     * @see #setErrorHandler
+     */
+    public void parse(InputSource is) throws IOException, SAXException {
+        if (is == null) {
+            throw new IllegalArgumentException("");
+        }
+        //              Set up the document
+        mInp = new Input(BUFFSIZE_READER);
+        mPh = PH_BEFORE_DOC;  // before parsing
+        try {
+            setinp(is);
+        } catch (SAXException saxe) {
+            throw saxe;
+        } catch (IOException ioe) {
+            throw ioe;
+        } catch (RuntimeException rte) {
+            throw rte;
+        } catch (Exception e) {
+            panic(e.toString());
+        }
+        parse();
+    }
+
+    /**
+     * Parse the content of the given {@link java.io.InputStream} instance as
+     * XML using the specified {@link org.xml.sax.helpers.DefaultHandler}.
+     *
+     * @param src InputStream containing the content to be parsed.
+     * @param handler The SAX DefaultHandler to use.
+     * @exception IOException If any IO errors occur.
+     * @exception IllegalArgumentException If the given InputStream or handler
+     * is null.
+     * @exception SAXException If the underlying parser throws a SAXException
+     * while parsing.
+     * @see org.xml.sax.helpers.DefaultHandler
+     */
+    public void parse(InputStream src, DefaultHandler handler)
+            throws SAXException, IOException {
+        if ((src == null) || (handler == null)) {
+            throw new IllegalArgumentException("");
+        }
+        parse(new InputSource(src), handler);
+    }
+
+    /**
+     * Parse the content given {@link org.xml.sax.InputSource} as XML using the
+     * specified {@link org.xml.sax.helpers.DefaultHandler}.
+     *
+     * @param is The InputSource containing the content to be parsed.
+     * @param handler The SAX DefaultHandler to use.
+     * @exception IOException If any IO errors occur.
+     * @exception IllegalArgumentException If the InputSource or handler is
+     * null.
+     * @exception SAXException If the underlying parser throws a SAXException
+     * while parsing.
+     * @see org.xml.sax.helpers.DefaultHandler
+     */
+    public void parse(InputSource is, DefaultHandler handler)
+        throws SAXException, IOException
+    {
+        if ((is == null) || (handler == null)) {
+            throw new IllegalArgumentException("");
+        }
+        //              Set up the handler
+        mHandCont = handler;
+        mHandDtd = handler;
+        mHandErr = handler;
+        mHandEnt = handler;
+        //              Set up the document
+        mInp = new Input(BUFFSIZE_READER);
+        mPh = PH_BEFORE_DOC;  // before parsing
+        try {
+            setinp(is);
+        } catch (SAXException | IOException | RuntimeException saxe) {
+            throw saxe;
+        } catch (Exception e) {
+            panic(e.toString());
+        }
+        parse();
+    }
+
+    /**
+     * Parse the XML document content using specified handlers and an input
+     * source.
+     *
+     * @exception IOException If any IO errors occur.
+     * @exception SAXException If the underlying parser throws a SAXException
+     * while parsing.
+     */
+    @SuppressWarnings("fallthrough")
+    private void parse() throws SAXException, IOException {
+        init();
+        try {
+            mHandCont.setDocumentLocator(this);
+            mHandCont.startDocument();
+
+            if (mPh != PH_MISC_DTD) {
+                mPh = PH_MISC_DTD;  // misc before DTD
+            }
+            int evt = EV_NULL;
+            //          XML document prolog
+            do {
+                wsskip();
+                switch (evt = step()) {
+                    case EV_ELM:
+                    case EV_ELMS:
+                        mPh = PH_DOCELM;
+                        break;
+
+                    case EV_COMM:
+                    case EV_PI:
+                        break;
+
+                    case EV_DTD:
+                        if (mPh >= PH_DTD_MISC) {
+                            panic(FAULT);
+                        }
+                        mPh = PH_DTD_MISC;  // misc after DTD
+                        break;
+
+                    default:
+                        panic(FAULT);
+                }
+            } while (mPh < PH_DOCELM);  // misc before DTD
+            //          XML document starting with document's element
+            do {
+                switch (evt) {
+                    case EV_ELM:
+                    case EV_ELMS:
+                        //              Report the element
+                        if (mIsNSAware == true) {
+                            mHandCont.startElement(
+                                    mElm.value,
+                                    mElm.name,
+                                    "",
+                                    mAttrs);
+                        } else {
+                            mHandCont.startElement(
+                                    "",
+                                    "",
+                                    mElm.name,
+                                    mAttrs);
+                        }
+                        if (evt == EV_ELMS) {
+                            evt = step();
+                            break;
+                        }
+
+                    case EV_ELME:
+                        //              Report the end of element
+                        if (mIsNSAware == true) {
+                            mHandCont.endElement(mElm.value, mElm.name, "");
+                        } else {
+                            mHandCont.endElement("", "", mElm.name);
+                        }
+                        //              Restore the top of the prefix stack
+                        while (mPref.list == mElm) {
+                            mHandCont.endPrefixMapping(mPref.name);
+                            mPref = del(mPref);
+                        }
+                        //              Remove the top element tag
+                        mElm = del(mElm);
+                        if (mElm == null) {
+                            mPh = PH_DOCELM_MISC;
+                        } else {
+                            evt = step();
+                        }
+                        break;
+
+                    case EV_TEXT:
+                    case EV_WSPC:
+                    case EV_CDAT:
+                    case EV_COMM:
+                    case EV_PI:
+                    case EV_ENT:
+                        evt = step();
+                        break;
+
+                    default:
+                        panic(FAULT);
+                }
+            } while (mPh == PH_DOCELM);
+            //          Misc after document's element
+            do {
+                if (wsskip() == EOS) {
+                    break;
+                }
+
+                switch (step()) {
+                    case EV_COMM:
+                    case EV_PI:
+                        break;
+
+                    default:
+                        panic(FAULT);
+                }
+            } while (mPh == PH_DOCELM_MISC);
+            mPh = PH_AFTER_DOC;  // parsing is completed
+
+        } catch (SAXException saxe) {
+            throw saxe;
+        } catch (IOException ioe) {
+            throw ioe;
+        } catch (RuntimeException rte) {
+            throw rte;
+        } catch (Exception e) {
+            panic(e.toString());
+        } finally {
+            mHandCont.endDocument();
+            cleanup();
+        }
+    }
+
+    /**
+     * Reports document type.
+     *
+     * @param name The name of the entity.
+     * @param pubid The public identifier of the entity or <code>null</code>.
+     * @param sysid The system identifier of the entity or <code>null</code>.
+     */
+    protected void docType(String name, String pubid, String sysid) throws SAXException {
+        mHandDtd.notationDecl(name, pubid, sysid);
+    }
+
+    /**
+     * Reports a comment.
+     *
+     * @param text The comment text starting from first charcater.
+     * @param length The number of characters in comment.
+     */
+    protected void comm(char[] text, int length) {
+    }
+
+    /**
+     * Reports a processing instruction.
+     *
+     * @param target The processing instruction target name.
+     * @param body The processing instruction body text.
+     */
+    protected void pi(String target, String body) throws SAXException {
+        mHandCont.processingInstruction(target, body);
+    }
+
+    /**
+     * Reports new namespace prefix. The Namespace prefix (
+     * <code>mPref.name</code>) being declared and the Namespace URI (
+     * <code>mPref.value</code>) the prefix is mapped to. An empty string is
+     * used for the default element namespace, which has no prefix.
+     */
+    protected void newPrefix() throws SAXException {
+        mHandCont.startPrefixMapping(mPref.name, mPref.value);
+    }
+
+    /**
+     * Reports skipped entity name.
+     *
+     * @param name The entity name.
+     */
+    protected void skippedEnt(String name) throws SAXException {
+        mHandCont.skippedEntity(name);
+    }
+
+    /**
+     * Returns an
+     * <code>InputSource</code> for specified entity or
+     * <code>null</code>.
+     *
+     * @param name The name of the entity.
+     * @param pubid The public identifier of the entity.
+     * @param sysid The system identifier of the entity.
+     */
+    protected InputSource resolveEnt(String name, String pubid, String sysid)
+        throws SAXException, IOException
+    {
+        return mHandEnt.resolveEntity(pubid, sysid);
+    }
+
+    /**
+     * Reports notation declaration.
+     *
+     * @param name The notation's name.
+     * @param pubid The notation's public identifier, or null if none was given.
+     * @param sysid The notation's system identifier, or null if none was given.
+     */
+    protected void notDecl(String name, String pubid, String sysid)
+        throws SAXException
+    {
+        mHandDtd.notationDecl(name, pubid, sysid);
+    }
+
+    /**
+     * Reports unparsed entity name.
+     *
+     * @param name The unparsed entity's name.
+     * @param pubid The entity's public identifier, or null if none was given.
+     * @param sysid The entity's system identifier.
+     * @param notation The name of the associated notation.
+     */
+    protected void unparsedEntDecl(String name, String pubid, String sysid, String notation)
+        throws SAXException
+    {
+        mHandDtd.unparsedEntityDecl(name, pubid, sysid, notation);
+    }
+
+    /**
+     * Notifies the handler about fatal parsing error.
+     *
+     * @param msg The problem description message.
+     */
+    protected void panic(String msg) throws SAXException {
+        SAXParseException spe = new SAXParseException(msg, this);
+        mHandErr.fatalError(spe);
+        throw spe;  // [#1.2] fatal error definition
+    }
+
+    /**
+     * Reports characters and empties the parser's buffer. This method is called
+     * only if parser is going to return control to the main loop. This means
+     * that this method may use parser buffer to report white space without
+     * copeing characters to temporary buffer.
+     */
+    protected void bflash() throws SAXException {
+        if (mBuffIdx >= 0) {
+            //          Textual data has been read
+            mHandCont.characters(mBuff, 0, (mBuffIdx + 1));
+            mBuffIdx = -1;
+        }
+    }
+
+    /**
+     * Reports white space characters and empties the parser's buffer. This
+     * method is called only if parser is going to return control to the main
+     * loop. This means that this method may use parser buffer to report white
+     * space without copeing characters to temporary buffer.
+     */
+    protected void bflash_ws() throws SAXException {
+        if (mBuffIdx >= 0) {
+            // BUG: With additional info from DTD and xml:space attr [#2.10]
+            // the following call can be supported:
+            // mHandCont.ignorableWhitespace(mBuff, 0, (mBuffIdx + 1));
+
+            //          Textual data has been read
+            mHandCont.characters(mBuff, 0, (mBuffIdx + 1));
+            mBuffIdx = -1;
+        }
+    }
+
+    public boolean getFeature(String name) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    public void setFeature(String name, boolean value) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    public Object getProperty(String name) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    public void setProperty(String name, Object value) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/jdk/internal/util/xml/impl/ReaderUTF16.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.util.xml.impl;
+
+import java.io.Reader;
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * UTF-16 encoded stream reader.
+ */
+public class ReaderUTF16 extends Reader {
+
+    private InputStream is;
+    private char bo;
+
+    /**
+     * Constructor.
+     *
+     * Byte order argument can be: 'l' for little-endian or 'b' for big-endian.
+     *
+     * @param is A byte input stream.
+     * @param bo A byte order in the input stream.
+     */
+    public ReaderUTF16(InputStream is, char bo) {
+        switch (bo) {
+            case 'l':
+                break;
+
+            case 'b':
+                break;
+
+            default:
+                throw new IllegalArgumentException("");
+        }
+        this.bo = bo;
+        this.is = is;
+    }
+
+    /**
+     * Reads characters into a portion of an array.
+     *
+     * @param cbuf Destination buffer.
+     * @param off Offset at which to start storing characters.
+     * @param len Maximum number of characters to read.
+     * @exception IOException If any IO errors occur.
+     */
+    public int read(char[] cbuf, int off, int len) throws IOException {
+        int num = 0;
+        int val;
+        if (bo == 'b') {
+            while (num < len) {
+                if ((val = is.read()) < 0) {
+                    return (num != 0) ? num : -1;
+                }
+                cbuf[off++] = (char) ((val << 8) | (is.read() & 0xff));
+                num++;
+            }
+        } else {
+            while (num < len) {
+                if ((val = is.read()) < 0) {
+                    return (num != 0) ? num : -1;
+                }
+                cbuf[off++] = (char) ((is.read() << 8) | (val & 0xff));
+                num++;
+            }
+        }
+        return num;
+    }
+
+    /**
+     * Reads a single character.
+     *
+     * @return The character read, as an integer in the range 0 to 65535
+     *  (0x0000-0xffff), or -1 if the end of the stream has been reached.
+     * @exception IOException If any IO errors occur.
+     */
+    public int read() throws IOException {
+        int val;
+        if ((val = is.read()) < 0) {
+            return -1;
+        }
+        if (bo == 'b') {
+            val = (char) ((val << 8) | (is.read() & 0xff));
+        } else {
+            val = (char) ((is.read() << 8) | (val & 0xff));
+        }
+        return val;
+    }
+
+    /**
+     * Closes the stream.
+     *
+     * @exception IOException If any IO errors occur.
+     */
+    public void close() throws IOException {
+        is.close();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/jdk/internal/util/xml/impl/ReaderUTF8.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.util.xml.impl;
+
+import java.io.Reader;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+
+/**
+ * UTF-8 transformed UCS-2 character stream reader.
+ *
+ * This reader converts UTF-8 transformed UCS-2 characters to Java characters.
+ * The UCS-2 subset of UTF-8 transformation is described in RFC-2279 #2
+ * "UTF-8 definition":
+ *  0000 0000-0000 007F   0xxxxxxx
+ *  0000 0080-0000 07FF   110xxxxx 10xxxxxx
+ *  0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
+ *
+ * This reader will return incorrect last character on broken UTF-8 stream.
+ */
+public class ReaderUTF8 extends Reader {
+
+    private InputStream is;
+
+    /**
+     * Constructor.
+     *
+     * @param is A byte input stream.
+     */
+    public ReaderUTF8(InputStream is) {
+        this.is = is;
+    }
+
+    /**
+     * Reads characters into a portion of an array.
+     *
+     * @param cbuf Destination buffer.
+     * @param off Offset at which to start storing characters.
+     * @param len Maximum number of characters to read.
+     * @exception IOException If any IO errors occur.
+     * @exception UnsupportedEncodingException If UCS-4 character occur in the stream.
+     */
+    public int read(char[] cbuf, int off, int len) throws IOException {
+        int num = 0;
+        int val;
+        while (num < len) {
+            if ((val = is.read()) < 0) {
+                return (num != 0) ? num : -1;
+            }
+            switch (val & 0xf0) {
+                case 0xc0:
+                case 0xd0:
+                    cbuf[off++] = (char) (((val & 0x1f) << 6) | (is.read() & 0x3f));
+                    break;
+
+                case 0xe0:
+                    cbuf[off++] = (char) (((val & 0x0f) << 12)
+                            | ((is.read() & 0x3f) << 6) | (is.read() & 0x3f));
+                    break;
+
+                case 0xf0:      // UCS-4 character
+                    throw new UnsupportedEncodingException("UTF-32 (or UCS-4) encoding not supported.");
+
+                default:
+                    cbuf[off++] = (char) val;
+                    break;
+            }
+            num++;
+        }
+        return num;
+    }
+
+    /**
+     * Reads a single character.
+     *
+     * @return The character read, as an integer in the range 0 to 65535
+     *  (0x00-0xffff), or -1 if the end of the stream has been reached.
+     * @exception IOException If any IO errors occur.
+     * @exception UnsupportedEncodingException If UCS-4 character occur in the stream.
+     */
+    public int read() throws IOException {
+        int val;
+        if ((val = is.read()) < 0) {
+            return -1;
+        }
+        switch (val & 0xf0) {
+            case 0xc0:
+            case 0xd0:
+                val = ((val & 0x1f) << 6) | (is.read() & 0x3f);
+                break;
+
+            case 0xe0:
+                val = ((val & 0x0f) << 12)
+                        | ((is.read() & 0x3f) << 6) | (is.read() & 0x3f);
+                break;
+
+            case 0xf0:  // UCS-4 character
+                throw new UnsupportedEncodingException();
+
+            default:
+                break;
+        }
+        return val;
+    }
+
+    /**
+     * Closes the stream.
+     *
+     * @exception IOException If any IO errors occur.
+     */
+    public void close() throws IOException {
+        is.close();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/jdk/internal/util/xml/impl/SAXParserImpl.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.util.xml.impl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import jdk.internal.org.xml.sax.InputSource;
+import jdk.internal.org.xml.sax.SAXException;
+import jdk.internal.org.xml.sax.XMLReader;
+import jdk.internal.org.xml.sax.helpers.DefaultHandler;
+import jdk.internal.util.xml.SAXParser;
+
+public class SAXParserImpl extends SAXParser {
+
+    private ParserSAX parser;
+
+    public SAXParserImpl() {
+        super();
+        parser = new ParserSAX();
+    }
+
+    /**
+     * Returns the {@link org.xml.sax.XMLReader} that is encapsulated by the
+     * implementation of this class.
+     *
+     * @return The XMLReader that is encapsulated by the
+     *         implementation of this class.
+     *
+     * @throws SAXException If any SAX errors occur during processing.
+     */
+    public XMLReader getXMLReader()
+            throws SAXException {
+        return parser;
+    }
+
+    /**
+     * Indicates whether or not this parser is configured to
+     * understand namespaces.
+     *
+     * @return true if this parser is configured to
+     *         understand namespaces; false otherwise.
+     */
+    public boolean isNamespaceAware() {
+        return parser.mIsNSAware;
+    }
+
+    /**
+     * Indicates whether or not this parser is configured to validate
+     * XML documents.
+     *
+     * @return true if this parser is configured to validate XML
+     *          documents; false otherwise.
+     */
+    public boolean isValidating() {
+        return false;
+    }
+
+    /**
+     * Parse the content of the given {@link java.io.InputStream}
+     * instance as XML using the specified
+     * {@link org.xml.sax.helpers.DefaultHandler}.
+     *
+     * @param src InputStream containing the content to be parsed.
+     * @param handler The SAX DefaultHandler to use.
+     * @exception IOException If any IO errors occur.
+     * @exception IllegalArgumentException If the given InputStream or handler is null.
+     * @exception SAXException If the underlying parser throws a
+     * SAXException while parsing.
+     * @see org.xml.sax.helpers.DefaultHandler
+     */
+    public void parse(InputStream src, DefaultHandler handler)
+        throws SAXException, IOException
+    {
+        parser.parse(src, handler);
+    }
+
+    /**
+     * Parse the content given {@link org.xml.sax.InputSource}
+     * as XML using the specified
+     * {@link org.xml.sax.helpers.DefaultHandler}.
+     *
+     * @param is The InputSource containing the content to be parsed.
+     * @param handler The SAX DefaultHandler to use.
+     * @exception IOException If any IO errors occur.
+     * @exception IllegalArgumentException If the InputSource or handler is null.
+     * @exception SAXException If the underlying parser throws a
+     * SAXException while parsing.
+     * @see org.xml.sax.helpers.DefaultHandler
+     */
+    public void parse(InputSource is, DefaultHandler handler)
+        throws SAXException, IOException
+    {
+        parser.parse(is, handler);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/jdk/internal/util/xml/impl/XMLStreamWriterImpl.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,633 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.util.xml.impl;
+
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.UnsupportedCharsetException;
+import jdk.internal.util.xml.XMLStreamException;
+import jdk.internal.util.xml.XMLStreamWriter;
+
+/**
+ * Implementation of a reduced version of XMLStreamWriter
+ *
+ * @author Joe Wang
+ */
+public class XMLStreamWriterImpl implements XMLStreamWriter {
+    //Document state
+
+    static final int STATE_XML_DECL = 1;
+    static final int STATE_PROLOG = 2;
+    static final int STATE_DTD_DECL = 3;
+    static final int STATE_ELEMENT = 4;
+    //Element state
+    static final int ELEMENT_STARTTAG_OPEN = 10;
+    static final int ELEMENT_STARTTAG_CLOSE = 11;
+    static final int ELEMENT_ENDTAG_OPEN = 12;
+    static final int ELEMENT_ENDTAG_CLOSE = 13;
+    public static final char CLOSE_START_TAG = '>';
+    public static final char OPEN_START_TAG = '<';
+    public static final String OPEN_END_TAG = "</";
+    public static final char CLOSE_END_TAG = '>';
+    public static final String START_CDATA = "<![CDATA[";
+    public static final String END_CDATA = "]]>";
+    public static final String CLOSE_EMPTY_ELEMENT = "/>";
+    public static final String ENCODING_PREFIX = "&#x";
+    public static final char SPACE = ' ';
+    public static final char AMPERSAND = '&';
+    public static final char DOUBLEQUOT = '"';
+    public static final char SEMICOLON = ';';
+    //current state
+    private int _state = 0;
+    private Element _currentEle;
+    private XMLWriter _writer;
+    private String _encoding;
+    /**
+     * This flag can be used to turn escaping off for content. It does
+     * not apply to attribute content.
+     */
+    boolean _escapeCharacters = true;
+    //pretty print by default
+    private boolean _doIndent = true;
+    //The system line separator for writing out line breaks.
+    private char[] _lineSep =
+            System.getProperty("line.separator").toCharArray();
+
+    public XMLStreamWriterImpl(OutputStream os) throws XMLStreamException {
+        this(os, XMLStreamWriter.DEFAULT_ENCODING);
+    }
+
+    public XMLStreamWriterImpl(OutputStream os, String encoding)
+        throws XMLStreamException
+    {
+        Charset cs = null;
+        if (encoding == null) {
+            _encoding = XMLStreamWriter.DEFAULT_ENCODING;
+        } else {
+            try {
+                cs = getCharset(encoding);
+            } catch (UnsupportedEncodingException e) {
+                throw new XMLStreamException(e);
+            }
+
+            this._encoding = encoding;
+        }
+
+        _writer = new XMLWriter(os, encoding, cs);
+    }
+
+    /**
+     * Write the XML Declaration. Defaults the XML version to 1.0, and the
+     * encoding to utf-8.
+     *
+     * @throws XMLStreamException
+     */
+    public void writeStartDocument() throws XMLStreamException {
+        writeStartDocument(_encoding, XMLStreamWriter.DEFAULT_XML_VERSION);
+    }
+
+    /**
+     * Write the XML Declaration. Defaults the encoding to utf-8
+     *
+     * @param version version of the xml document
+     * @throws XMLStreamException
+     */
+    public void writeStartDocument(String version) throws XMLStreamException {
+        writeStartDocument(_encoding, version, null);
+    }
+
+    /**
+     * Write the XML Declaration. Note that the encoding parameter does not set
+     * the actual encoding of the underlying output. That must be set when the
+     * instance of the XMLStreamWriter is created
+     *
+     * @param encoding encoding of the xml declaration
+     * @param version version of the xml document
+     * @throws XMLStreamException If given encoding does not match encoding of the
+     * underlying stream
+     */
+    public void writeStartDocument(String encoding, String version) throws XMLStreamException {
+        writeStartDocument(encoding, version, null);
+    }
+
+    /**
+     * Write the XML Declaration. Note that the encoding parameter does not set
+     * the actual encoding of the underlying output. That must be set when the
+     * instance of the XMLStreamWriter is created
+     *
+     * @param encoding encoding of the xml declaration
+     * @param version version of the xml document
+     * @param standalone indicate if the xml document is standalone
+     * @throws XMLStreamException If given encoding does not match encoding of the
+     * underlying stream
+     */
+    public void writeStartDocument(String encoding, String version, String standalone)
+        throws XMLStreamException
+    {
+        if (_state > 0) {
+            throw new XMLStreamException("XML declaration must be as the first line in the XML document.");
+        }
+        _state = STATE_XML_DECL;
+        String enc = encoding;
+        if (enc == null) {
+            enc = _encoding;
+        } else {
+            //check if the encoding is supported
+            try {
+                getCharset(encoding);
+            } catch (UnsupportedEncodingException e) {
+                throw new XMLStreamException(e);
+            }
+        }
+
+        if (version == null) {
+            version = XMLStreamWriter.DEFAULT_XML_VERSION;
+        }
+
+        _writer.write("<?xml version=\"");
+        _writer.write(version);
+        _writer.write(DOUBLEQUOT);
+
+        if (enc != null) {
+            _writer.write(" encoding=\"");
+            _writer.write(enc);
+            _writer.write(DOUBLEQUOT);
+        }
+
+        if (standalone != null) {
+            _writer.write(" standalone=\"");
+            _writer.write(standalone);
+            _writer.write(DOUBLEQUOT);
+        }
+        _writer.write("?>");
+        writeLineSeparator();
+    }
+
+    /**
+     * Write a DTD section.  This string represents the entire doctypedecl production
+     * from the XML 1.0 specification.
+     *
+     * @param dtd the DTD to be written
+     * @throws XMLStreamException
+     */
+    public void writeDTD(String dtd) throws XMLStreamException {
+        if (_currentEle != null && _currentEle.getState() == ELEMENT_STARTTAG_OPEN) {
+            closeStartTag();
+        }
+        _writer.write(dtd);
+        writeLineSeparator();
+    }
+
+    /**
+     * Writes a start tag to the output.
+     * @param localName local name of the tag, may not be null
+     * @throws XMLStreamException
+     */
+    public void writeStartElement(String localName) throws XMLStreamException {
+        if (localName == null || localName.length() == 0) {
+            throw new XMLStreamException("Local Name cannot be null or empty");
+        }
+
+        _state = STATE_ELEMENT;
+        if (_currentEle != null && _currentEle.getState() == ELEMENT_STARTTAG_OPEN) {
+            closeStartTag();
+        }
+
+        _currentEle = new Element(_currentEle, localName, false);
+        openStartTag();
+
+        _writer.write(localName);
+    }
+
+    /**
+     * Writes an empty element tag to the output
+     * @param localName local name of the tag, may not be null
+     * @throws XMLStreamException
+     */
+    public void writeEmptyElement(String localName) throws XMLStreamException {
+        if (_currentEle != null && _currentEle.getState() == ELEMENT_STARTTAG_OPEN) {
+            closeStartTag();
+        }
+
+        _currentEle = new Element(_currentEle, localName, true);
+
+        openStartTag();
+        _writer.write(localName);
+    }
+
+    /**
+     * Writes an attribute to the output stream without a prefix.
+     * @param localName the local name of the attribute
+     * @param value the value of the attribute
+     * @throws IllegalStateException if the current state does not allow Attribute writing
+     * @throws XMLStreamException
+     */
+    public void writeAttribute(String localName, String value) throws XMLStreamException {
+        if (_currentEle.getState() != ELEMENT_STARTTAG_OPEN) {
+            throw new XMLStreamException(
+                    "Attribute not associated with any element");
+        }
+
+        _writer.write(SPACE);
+        _writer.write(localName);
+        _writer.write("=\"");
+        writeXMLContent(
+                value,
+                true, // true = escapeChars
+                true);  // true = escapeDoubleQuotes
+        _writer.write(DOUBLEQUOT);
+    }
+
+    public void writeEndDocument() throws XMLStreamException {
+        if (_currentEle != null && _currentEle.getState() == ELEMENT_STARTTAG_OPEN) {
+            closeStartTag();
+        }
+
+        /**
+         * close unclosed elements if any
+         */
+        while (_currentEle != null) {
+
+            if (!_currentEle.isEmpty()) {
+                _writer.write(OPEN_END_TAG);
+                _writer.write(_currentEle.getLocalName());
+                _writer.write(CLOSE_END_TAG);
+            }
+
+            _currentEle = _currentEle.getParent();
+        }
+    }
+
+    public void writeEndElement() throws XMLStreamException {
+        if (_currentEle != null && _currentEle.getState() == ELEMENT_STARTTAG_OPEN) {
+            closeStartTag();
+        }
+
+        if (_currentEle == null) {
+            throw new XMLStreamException("No element was found to write");
+        }
+
+        if (_currentEle.isEmpty()) {
+            return;
+        }
+
+        _writer.write(OPEN_END_TAG);
+        _writer.write(_currentEle.getLocalName());
+        _writer.write(CLOSE_END_TAG);
+        writeLineSeparator();
+
+        _currentEle = _currentEle.getParent();
+    }
+
+    public void writeCData(String cdata) throws XMLStreamException {
+        if (cdata == null) {
+            throw new XMLStreamException("cdata cannot be null");
+        }
+
+        if (_currentEle != null && _currentEle.getState() == ELEMENT_STARTTAG_OPEN) {
+            closeStartTag();
+        }
+
+        _writer.write(START_CDATA);
+        _writer.write(cdata);
+        _writer.write(END_CDATA);
+    }
+
+    public void writeCharacters(String data) throws XMLStreamException {
+        if (_currentEle != null && _currentEle.getState() == ELEMENT_STARTTAG_OPEN) {
+            closeStartTag();
+        }
+
+        writeXMLContent(data);
+    }
+
+    public void writeCharacters(char[] data, int start, int len)
+            throws XMLStreamException {
+        if (_currentEle != null && _currentEle.getState() == ELEMENT_STARTTAG_OPEN) {
+            closeStartTag();
+        }
+
+        writeXMLContent(data, start, len, _escapeCharacters);
+    }
+
+    /**
+     * Close this XMLStreamWriter by closing underlying writer.
+     */
+    public void close() throws XMLStreamException {
+        if (_writer != null) {
+            _writer.close();
+        }
+        _writer = null;
+        _currentEle = null;
+        _state = 0;
+    }
+
+    /**
+     * Flush this XMLStreamWriter by flushing underlying writer.
+     */
+    public void flush() throws XMLStreamException {
+        if (_writer != null) {
+            _writer.flush();
+        }
+    }
+
+    /**
+     * Set the flag to indicate if the writer should add line separator
+     * @param doIndent
+     */
+    public void setDoIndent(boolean doIndent) {
+        _doIndent = doIndent;
+    }
+
+    /**
+     * Writes XML content to underlying writer. Escapes characters unless
+     * escaping character feature is turned off.
+     */
+    private void writeXMLContent(char[] content, int start, int length, boolean escapeChars)
+        throws XMLStreamException
+    {
+        if (!escapeChars) {
+            _writer.write(content, start, length);
+            return;
+        }
+
+        // Index of the next char to be written
+        int startWritePos = start;
+
+        final int end = start + length;
+
+        for (int index = start; index < end; index++) {
+            char ch = content[index];
+
+            if (!_writer.canEncode(ch)) {
+                _writer.write(content, startWritePos, index - startWritePos);
+
+                // Escape this char as underlying encoder cannot handle it
+                _writer.write(ENCODING_PREFIX);
+                _writer.write(Integer.toHexString(ch));
+                _writer.write(SEMICOLON);
+                startWritePos = index + 1;
+                continue;
+            }
+
+            switch (ch) {
+                case OPEN_START_TAG:
+                    _writer.write(content, startWritePos, index - startWritePos);
+                    _writer.write("&lt;");
+                    startWritePos = index + 1;
+
+                    break;
+
+                case AMPERSAND:
+                    _writer.write(content, startWritePos, index - startWritePos);
+                    _writer.write("&amp;");
+                    startWritePos = index + 1;
+
+                    break;
+
+                case CLOSE_START_TAG:
+                    _writer.write(content, startWritePos, index - startWritePos);
+                    _writer.write("&gt;");
+                    startWritePos = index + 1;
+
+                    break;
+            }
+        }
+
+        // Write any pending data
+        _writer.write(content, startWritePos, end - startWritePos);
+    }
+
+    private void writeXMLContent(String content) throws XMLStreamException {
+        if ((content != null) && (content.length() > 0)) {
+            writeXMLContent(content,
+                    _escapeCharacters, // boolean = escapeChars
+                    false);             // false = escapeDoubleQuotes
+        }
+    }
+
+    /**
+     * Writes XML content to underlying writer. Escapes characters unless
+     * escaping character feature is turned off.
+     */
+    private void writeXMLContent(
+            String content,
+            boolean escapeChars,
+            boolean escapeDoubleQuotes)
+        throws XMLStreamException
+    {
+
+        if (!escapeChars) {
+            _writer.write(content);
+
+            return;
+        }
+
+        // Index of the next char to be written
+        int startWritePos = 0;
+
+        final int end = content.length();
+
+        for (int index = 0; index < end; index++) {
+            char ch = content.charAt(index);
+
+            if (!_writer.canEncode(ch)) {
+                _writer.write(content, startWritePos, index - startWritePos);
+
+                // Escape this char as underlying encoder cannot handle it
+                _writer.write(ENCODING_PREFIX);
+                _writer.write(Integer.toHexString(ch));
+                _writer.write(SEMICOLON);
+                startWritePos = index + 1;
+                continue;
+            }
+
+            switch (ch) {
+                case OPEN_START_TAG:
+                    _writer.write(content, startWritePos, index - startWritePos);
+                    _writer.write("&lt;");
+                    startWritePos = index + 1;
+
+                    break;
+
+                case AMPERSAND:
+                    _writer.write(content, startWritePos, index - startWritePos);
+                    _writer.write("&amp;");
+                    startWritePos = index + 1;
+
+                    break;
+
+                case CLOSE_START_TAG:
+                    _writer.write(content, startWritePos, index - startWritePos);
+                    _writer.write("&gt;");
+                    startWritePos = index + 1;
+
+                    break;
+
+                case DOUBLEQUOT:
+                    _writer.write(content, startWritePos, index - startWritePos);
+                    if (escapeDoubleQuotes) {
+                        _writer.write("&quot;");
+                    } else {
+                        _writer.write(DOUBLEQUOT);
+                    }
+                    startWritePos = index + 1;
+
+                    break;
+            }
+        }
+
+        // Write any pending data
+        _writer.write(content, startWritePos, end - startWritePos);
+    }
+
+    /**
+     * marks open of start tag and writes the same into the writer.
+     */
+    private void openStartTag() throws XMLStreamException {
+        _currentEle.setState(ELEMENT_STARTTAG_OPEN);
+        _writer.write(OPEN_START_TAG);
+    }
+
+    /**
+     * marks close of start tag and writes the same into the writer.
+     */
+    private void closeStartTag() throws XMLStreamException {
+        if (_currentEle.isEmpty()) {
+            _writer.write(CLOSE_EMPTY_ELEMENT);
+        } else {
+            _writer.write(CLOSE_START_TAG);
+
+        }
+
+        if (_currentEle.getParent() == null) {
+            writeLineSeparator();
+        }
+
+        _currentEle.setState(ELEMENT_STARTTAG_CLOSE);
+
+    }
+
+    /**
+     * Write a line separator
+     * @throws XMLStreamException
+     */
+    private void writeLineSeparator() throws XMLStreamException {
+        if (_doIndent) {
+            _writer.write(_lineSep, 0, _lineSep.length);
+        }
+    }
+
+    /**
+     * Returns a charset object for the specified encoding
+     * @param encoding
+     * @return a charset object
+     * @throws UnsupportedEncodingException if the encoding is not supported
+     */
+    private Charset getCharset(String encoding) throws UnsupportedEncodingException {
+        if (encoding.equalsIgnoreCase("UTF-32")) {
+            throw new UnsupportedEncodingException("The basic XMLWriter does "
+                    + "not support " + encoding);
+        }
+
+        Charset cs;
+        try {
+            cs = Charset.forName(encoding);
+        } catch (IllegalCharsetNameException | UnsupportedCharsetException ex) {
+            throw new UnsupportedEncodingException(encoding);
+        }
+        return cs;
+    }
+
+    /*
+     * Start of Internal classes.
+     *
+     */
+    protected class Element {
+
+        /**
+         * the parent element
+         */
+        protected Element _parent;
+        /**
+         * The size of the stack.
+         */
+        protected short _Depth;
+        /**
+         * indicate if an element is an empty one
+         */
+        boolean _isEmptyElement = false;
+        String _localpart;
+        int _state;
+
+        /**
+         * Default constructor.
+         */
+        public Element() {
+        }
+
+        /**
+         * @param parent the parent of the element
+         * @param localpart name of the element
+         * @param isEmpty indicate if the element is an empty one
+         */
+        public Element(Element parent, String localpart, boolean isEmpty) {
+            _parent = parent;
+            _localpart = localpart;
+            _isEmptyElement = isEmpty;
+        }
+
+        public Element getParent() {
+            return _parent;
+        }
+
+        public String getLocalName() {
+            return _localpart;
+        }
+
+        /**
+         * get the state of the element
+         */
+        public int getState() {
+            return _state;
+        }
+
+        /**
+         * Set the state of the element
+         *
+         * @param state the state of the element
+         */
+        public void setState(int state) {
+            _state = state;
+        }
+
+        public boolean isEmpty() {
+            return _isEmptyElement;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/jdk/internal/util/xml/impl/XMLWriter.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.util.xml.impl;
+
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import jdk.internal.util.xml.XMLStreamException;
+
+/**
+ *
+ * @author huizwang
+ */
+public class XMLWriter {
+
+    private Writer _writer;
+    /**
+     * In some cases, this charset encoder is used to determine if a char is
+     * encodable by underlying writer. For example, an 8-bit char from the
+     * extended ASCII set is not encodable by 7-bit ASCII encoder. Unencodable
+     * chars are escaped using XML numeric entities.
+     */
+    private CharsetEncoder _encoder = null;
+
+    public XMLWriter(OutputStream os, String encoding, Charset cs) throws XMLStreamException {
+        _encoder = cs.newEncoder();
+        try {
+            _writer = getWriter(os, encoding, cs);
+        } catch (UnsupportedEncodingException ex) {
+            throw new XMLStreamException(ex);
+        }
+
+    }
+
+    public boolean canEncode(char ch) {
+        if (_encoder == null) {
+            return false;
+        }
+        return (_encoder.canEncode(ch));
+    }
+
+    public void write(String s)
+            throws XMLStreamException {
+        try {
+            _writer.write(s.toCharArray());
+//            _writer.write(s.getBytes(Charset.forName(_encoding)));
+        } catch (IOException e) {
+            throw new XMLStreamException("I/O error", e);
+        }
+    }
+
+    public void write(String str, int off, int len)
+            throws XMLStreamException {
+        try {
+            _writer.write(str, off, len);
+        } catch (IOException e) {
+            throw new XMLStreamException("I/O error", e);
+        }
+
+    }
+
+    public void write(char[] cbuf, int off, int len)
+            throws XMLStreamException {
+        try {
+            _writer.write(cbuf, off, len);
+        } catch (IOException e) {
+            throw new XMLStreamException("I/O error", e);
+        }
+
+    }
+
+    void write(int b)
+            throws XMLStreamException {
+        try {
+            _writer.write(b);
+        } catch (IOException e) {
+            throw new XMLStreamException("I/O error", e);
+        }
+    }
+
+    void flush() throws XMLStreamException {
+        try {
+            _writer.flush();
+        } catch (IOException ex) {
+            throw new XMLStreamException(ex);
+        }
+    }
+
+    void close() throws XMLStreamException {
+        try {
+            _writer.close();
+        } catch (IOException ex) {
+            throw new XMLStreamException(ex);
+        }
+    }
+
+    private void nl() throws XMLStreamException {
+        String lineEnd = System.getProperty("line.separator");
+        try {
+            _writer.write(lineEnd);
+        } catch (IOException e) {
+            throw new XMLStreamException("I/O error", e);
+        }
+    }
+
+    /**
+     * Returns a writer for the specified encoding based on an output stream.
+     *
+     * @param output The output stream
+     * @param encoding The encoding
+     * @return A suitable writer
+     * @throws UnsupportedEncodingException There is no convertor to support
+     * this encoding
+     */
+    private Writer getWriter(OutputStream output, String encoding, Charset cs)
+        throws XMLStreamException, UnsupportedEncodingException
+    {
+        if (cs != null) {
+            return (new OutputStreamWriter(new BufferedOutputStream(output), cs));
+        }
+
+        return new OutputStreamWriter(new BufferedOutputStream(output), encoding);
+    }
+}
--- a/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMS.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMS.java	Wed Jul 05 18:34:47 2017 +0200
@@ -53,7 +53,9 @@
     public static native long getProfileID(ICC_Profile profile);
 
     public static native long createNativeTransform(
-        long[] profileIDs, int renderType, int inFormatter, int outFormatter,
+        long[] profileIDs, int renderType,
+        int inFormatter, boolean isInIntPacked,
+        int outFormatter, boolean isOutIntPacked,
         Object disposerRef);
 
    /**
--- a/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java	Wed Jul 05 18:34:47 2017 +0200
@@ -196,7 +196,8 @@
             case BufferedImage.TYPE_4BYTE_ABGR:
                 byteRaster = (ByteComponentRaster)image.getRaster();
                 nextRowOffset = byteRaster.getScanlineStride();
-                offset = byteRaster.getDataOffset(0);
+                int firstBand = image.getSampleModel().getNumBands() - 1;
+                offset = byteRaster.getDataOffset(firstBand);
                 dataArray = byteRaster.getDataStorage();
                 dataType = DT_BYTE;
                 break;
--- a/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java	Wed Jul 05 18:34:47 2017 +0200
@@ -55,8 +55,10 @@
 
 public class LCMSTransform implements ColorTransform {
     long ID;
-    private int inFormatter;
-    private int outFormatter;
+    private int inFormatter = 0;
+    private boolean isInIntPacked = false;
+    private int outFormatter = 0;
+    private boolean isOutIntPacked = false;
 
     ICC_Profile[] profiles;
     long [] profileIDs;
@@ -135,18 +137,23 @@
                                           LCMSImageLayout out) {
         // update native transfrom if needed
         if (ID == 0L ||
-            inFormatter != in.pixelType ||
-            outFormatter != out.pixelType) {
+            inFormatter != in.pixelType || isInIntPacked != in.isIntPacked ||
+            outFormatter != out.pixelType || isOutIntPacked != out.isIntPacked)
+        {
 
             if (ID != 0L) {
                 // Disposer will destroy forgotten transform
                 disposerReferent = new Object();
             }
             inFormatter = in.pixelType;
+            isInIntPacked = in.isIntPacked;
+
             outFormatter = out.pixelType;
+            isOutIntPacked = out.isIntPacked;
 
             ID = LCMS.createNativeTransform(profileIDs, renderType,
-                                            inFormatter, outFormatter,
+                                            inFormatter, isInIntPacked,
+                                            outFormatter, isOutIntPacked,
                                             disposerReferent);
         }
 
--- a/jdk/src/share/classes/sun/net/www/http/KeepAliveStream.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/sun/net/www/http/KeepAliveStream.java	Wed Jul 05 18:34:47 2017 +0200
@@ -83,11 +83,8 @@
             if (expected > count) {
                 long nskip = expected - count;
                 if (nskip <= available()) {
-                    long n = 0;
-                    while (n < nskip) {
-                        nskip = nskip - n;
-                        n = skip(nskip);
-                    }
+                    do {} while ((nskip = (expected - count)) > 0L
+                                 && skip(Math.min(nskip, available())) > 0L);
                 } else if (expected <= KeepAliveStreamCleaner.MAX_DATA_REMAINING && !hurried) {
                     //put this KeepAliveStream on the queue so that the data remaining
                     //on the socket can be cleanup asyncronously.
--- a/jdk/src/share/classes/sun/security/krb5/EncryptionKey.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/sun/security/krb5/EncryptionKey.java	Wed Jul 05 18:34:47 2017 +0200
@@ -555,6 +555,12 @@
 
         int ktype;
         boolean etypeFound = false;
+
+        // When no matched kvno is found, returns tke key of the same
+        // etype with the highest kvno
+        int kvno_found = 0;
+        EncryptionKey key_found = null;
+
         for (int i = 0; i < keys.length; i++) {
             ktype = keys[i].getEType();
             if (EType.isSupported(ktype)) {
@@ -563,6 +569,10 @@
                     etypeFound = true;
                     if (versionMatches(kvno, kv)) {
                         return keys[i];
+                    } else if (kv > kvno_found) {
+                        // kv is not null
+                        key_found = keys[i];
+                        kvno_found = kv;
                     }
                 }
             }
@@ -580,12 +590,17 @@
                     etypeFound = true;
                     if (versionMatches(kvno, kv)) {
                         return new EncryptionKey(etype, keys[i].getBytes());
+                    } else if (kv > kvno_found) {
+                        key_found = new EncryptionKey(etype, keys[i].getBytes());
+                        kvno_found = kv;
                     }
                 }
             }
         }
         if (etypeFound) {
-            throw new KrbException(Krb5.KRB_AP_ERR_BADKEYVER);
+            return key_found;
+            // For compatibility, will not fail here.
+            //throw new KrbException(Krb5.KRB_AP_ERR_BADKEYVER);
         }
         return null;
     }
--- a/jdk/src/share/classes/sun/security/provider/ConfigSpiFile.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/sun/security/provider/ConfigSpiFile.java	Wed Jul 05 18:34:47 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,81 +25,668 @@
 
 package sun.security.provider;
 
+import java.io.*;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.security.Security;
 import java.security.URIParameter;
-
+import java.text.MessageFormat;
+import java.util.*;
+import javax.security.auth.AuthPermission;
+import javax.security.auth.login.AppConfigurationEntry;
 import javax.security.auth.login.Configuration;
 import javax.security.auth.login.ConfigurationSpi;
-import javax.security.auth.login.AppConfigurationEntry;
-
-import com.sun.security.auth.login.ConfigFile;
+import sun.security.util.Debug;
+import sun.security.util.PropertyExpander;
+import sun.security.util.ResourcesMgr;
 
 /**
- * This class wraps the ConfigFile subclass implementation of Configuration
- * inside a ConfigurationSpi implementation that is available from the
- * SUN provider via the Configuration.getInstance calls.
+ * This class represents a default implementation for
+ * {@code javax.security.auth.login.Configuration}.
+ *
+ * <p> This object stores the runtime login configuration representation,
+ * and is the amalgamation of multiple static login
+ * configurations that resides in files.
+ * The algorithm for locating the login configuration file(s) and reading their
+ * information into this {@code Configuration} object is:
+ *
+ * <ol>
+ * <li>
+ *   Loop through the security properties,
+ *   <i>login.config.url.1</i>, <i>login.config.url.2</i>, ...,
+ *   <i>login.config.url.X</i>.
+ *   Each property value specifies a <code>URL</code> pointing to a
+ *   login configuration file to be loaded.  Read in and load
+ *   each configuration.
  *
+ * <li>
+ *   The {@code java.lang.System} property
+ *   <i>java.security.auth.login.config</i>
+ *   may also be set to a {@code URL} pointing to another
+ *   login configuration file
+ *   (which is the case when a user uses the -D switch at runtime).
+ *   If this property is defined, and its use is allowed by the
+ *   security property file (the Security property,
+ *   <i>policy.allowSystemProperty</i> is set to <i>true</i>),
+ *   also load that login configuration.
+ *
+ * <li>
+ *   If the <i>java.security.auth.login.config</i> property is defined using
+ *   "==" (rather than "="), then ignore all other specified
+ *   login configurations and only load this configuration.
+ *
+ * <li>
+ *   If no system or security properties were set, try to read from the file,
+ *   ${user.home}/.java.login.config, where ${user.home} is the value
+ *   represented by the "user.home" System property.
+ * </ol>
+ *
+ * <p> The configuration syntax supported by this implementation
+ * is exactly that syntax specified in the
+ * {@code javax.security.auth.login.Configuration} class.
+ *
+ * @see javax.security.auth.login.LoginContext
+ * @see java.security.Security security properties
  */
 public final class ConfigSpiFile extends ConfigurationSpi {
 
-    private ConfigFile cf;
+    private URL url;
+    private boolean expandProp = true;
+    private Map<String, List<AppConfigurationEntry>> configuration;
+    private int linenum;
+    private StreamTokenizer st;
+    private int lookahead;
+
+    private static Debug debugConfig = Debug.getInstance("configfile");
+    private static Debug debugParser = Debug.getInstance("configparser");
+
+    /**
+     * Create a new {@code Configuration} object.
+     *
+     * @throws SecurityException if the {@code Configuration} can not be
+     *                           initialized
+     */
+    public ConfigSpiFile() {
+        try {
+            init();
+        } catch (IOException ioe) {
+            throw new SecurityException(ioe);
+        }
+    }
+
+    /**
+     * Create a new {@code Configuration} object from the specified {@code URI}.
+     *
+     * @param uri the {@code URI}
+     * @throws SecurityException if the {@code Configuration} can not be
+     *                           initialized
+     * @throws NullPointerException if {@code uri} is null
+     */
+    public ConfigSpiFile(URI uri) {
+        // only load config from the specified URI
+        try {
+            url = uri.toURL();
+            init();
+        } catch (IOException ioe) {
+            throw new SecurityException(ioe);
+        }
+    }
 
     public ConfigSpiFile(final Configuration.Parameters params)
-        throws java.io.IOException {
+        throws IOException {
 
         // call in a doPrivileged
         //
         // we have already passed the Configuration.getInstance
         // security check.  also this class is not freely accessible
         // (it is in the "sun" package).
-        //
-        // we can not put doPrivileged calls into
-        // ConfigFile because it is a public com.sun class
 
         try {
-            AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
+                public Void run() throws IOException {
+                    if (params == null) {
+                        init();
+                    } else {
+                        if (!(params instanceof URIParameter)) {
+                            throw new IllegalArgumentException
+                                    ("Unrecognized parameter: " + params);
+                        }
+                        URIParameter uriParam = (URIParameter)params;
+                        url = uriParam.getURI().toURL();
+                        init();
+                    }
+                    return null;
+                }
+            });
+        } catch (PrivilegedActionException pae) {
+            throw (IOException)pae.getException();
+        }
+
+        // if init() throws some other RuntimeException,
+        // let it percolate up naturally.
+    }
+
+    /**
+     * Read and initialize the entire login Configuration from the configured
+     * URL.
+     *
+     * @throws IOException if the Configuration can not be initialized
+     * @throws SecurityException if the caller does not have permission
+     *                           to initialize the Configuration
+     */
+    private void init() throws IOException {
+
+        boolean initialized = false;
+
+        // For policy.expandProperties, check if either a security or system
+        // property is set to false (old code erroneously checked the system
+        // prop so we must check both to preserve compatibility).
+        String expand = Security.getProperty("policy.expandProperties");
+        if (expand == null) {
+            expand = System.getProperty("policy.expandProperties");
+        }
+        if ("false".equals(expand)) {
+            expandProp = false;
+        }
+
+        // new configuration
+        Map<String, List<AppConfigurationEntry>> newConfig = new HashMap<>();
+
+        if (url != null) {
+            /**
+             * If the caller specified a URI via Configuration.getInstance,
+             * we only read from that URI
+             */
+            if (debugConfig != null) {
+                debugConfig.println("reading " + url);
+            }
+            init(url, newConfig);
+            configuration = newConfig;
+            return;
+        }
+
+        /**
+         * Caller did not specify URI via Configuration.getInstance.
+         * Read from URLs listed in the java.security properties file.
+         */
+        String allowSys = Security.getProperty("policy.allowSystemProperty");
+
+        if ("true".equalsIgnoreCase(allowSys)) {
+            String extra_config = System.getProperty
+                                        ("java.security.auth.login.config");
+            if (extra_config != null) {
+                boolean overrideAll = false;
+                if (extra_config.startsWith("=")) {
+                    overrideAll = true;
+                    extra_config = extra_config.substring(1);
+                }
+                try {
+                    extra_config = PropertyExpander.expand(extra_config);
+                } catch (PropertyExpander.ExpandException peee) {
+                    MessageFormat form = new MessageFormat
+                        (ResourcesMgr.getString
+                                ("Unable.to.properly.expand.config",
+                                "sun.security.util.AuthResources"));
+                    Object[] source = {extra_config};
+                    throw new IOException(form.format(source));
+                }
+
+                URL configURL = null;
+                try {
+                    configURL = new URL(extra_config);
+                } catch (MalformedURLException mue) {
+                    File configFile = new File(extra_config);
+                    if (configFile.exists()) {
+                        configURL = configFile.toURI().toURL();
+                    } else {
+                        MessageFormat form = new MessageFormat
+                            (ResourcesMgr.getString
+                                ("extra.config.No.such.file.or.directory.",
+                                "sun.security.util.AuthResources"));
+                        Object[] source = {extra_config};
+                        throw new IOException(form.format(source));
+                    }
+                }
+
+                if (debugConfig != null) {
+                    debugConfig.println("reading "+configURL);
+                }
+                init(configURL, newConfig);
+                initialized = true;
+                if (overrideAll) {
+                    if (debugConfig != null) {
+                        debugConfig.println("overriding other policies!");
+                    }
+                    configuration = newConfig;
+                    return;
+                }
+            }
+        }
+
+        int n = 1;
+        String config_url;
+        while ((config_url = Security.getProperty
+                                        ("login.config.url."+n)) != null) {
+            try {
+                config_url = PropertyExpander.expand
+                        (config_url).replace(File.separatorChar, '/');
+                if (debugConfig != null) {
+                    debugConfig.println("\tReading config: " + config_url);
+                }
+                init(new URL(config_url), newConfig);
+                initialized = true;
+            } catch (PropertyExpander.ExpandException peee) {
+                MessageFormat form = new MessageFormat
+                        (ResourcesMgr.getString
+                                ("Unable.to.properly.expand.config",
+                                "sun.security.util.AuthResources"));
+                Object[] source = {config_url};
+                throw new IOException(form.format(source));
+            }
+            n++;
+        }
+
+        if (initialized == false && n == 1 && config_url == null) {
+
+            // get the config from the user's home directory
+            if (debugConfig != null) {
+                debugConfig.println("\tReading Policy " +
+                                "from ~/.java.login.config");
+            }
+            config_url = System.getProperty("user.home");
+            String userConfigFile = config_url +
+                      File.separatorChar + ".java.login.config";
+
+            // No longer throws an exception when there's no config file
+            // at all. Returns an empty Configuration instead.
+            if (new File(userConfigFile).exists()) {
+                init(new File(userConfigFile).toURI().toURL(),
+                     newConfig);
+            }
+        }
+
+        configuration = newConfig;
+    }
+
+    private void init(URL config,
+                      Map<String, List<AppConfigurationEntry>> newConfig)
+                      throws IOException {
+
+        try (InputStreamReader isr
+                = new InputStreamReader(getInputStream(config), "UTF-8")) {
+            readConfig(isr, newConfig);
+        } catch (FileNotFoundException fnfe) {
+            if (debugConfig != null) {
+                debugConfig.println(fnfe.toString());
+            }
+            throw new IOException(ResourcesMgr.getString
+                    ("Configuration.Error.No.such.file.or.directory",
+                    "sun.security.util.AuthResources"));
+        }
+    }
+
+    /**
+     * Retrieve an entry from the Configuration using an application name
+     * as an index.
+     *
+     * @param applicationName the name used to index the Configuration.
+     * @return an array of AppConfigurationEntries which correspond to
+     *         the stacked configuration of LoginModules for this
+     *         application, or null if this application has no configured
+     *         LoginModules.
+     */
+    @Override
+    public AppConfigurationEntry[] engineGetAppConfigurationEntry
+        (String applicationName) {
+
+        List<AppConfigurationEntry> list = null;
+        synchronized (configuration) {
+            list = configuration.get(applicationName);
+        }
+
+        if (list == null || list.size() == 0)
+            return null;
+
+        AppConfigurationEntry[] entries =
+                                new AppConfigurationEntry[list.size()];
+        Iterator<AppConfigurationEntry> iterator = list.iterator();
+        for (int i = 0; iterator.hasNext(); i++) {
+            AppConfigurationEntry e = iterator.next();
+            entries[i] = new AppConfigurationEntry(e.getLoginModuleName(),
+                                                   e.getControlFlag(),
+                                                   e.getOptions());
+        }
+        return entries;
+    }
+
+    /**
+     * Refresh and reload the Configuration by re-reading all of the
+     * login configurations.
+     *
+     * @throws SecurityException if the caller does not have permission
+     *                           to refresh the Configuration.
+     */
+    @Override
+    public synchronized void engineRefresh() {
+
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null)
+            sm.checkPermission(new AuthPermission("refreshLoginConfiguration"));
+
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
             public Void run() {
-                if (params == null) {
-                    cf = new ConfigFile();
-                } else {
-                    if (!(params instanceof URIParameter)) {
-                        throw new IllegalArgumentException
-                                ("Unrecognized parameter: " + params);
-                    }
-                    URIParameter uriParam = (URIParameter)params;
-
-                    cf = new ConfigFile(uriParam.getURI());
+                try {
+                    init();
+                } catch (IOException ioe) {
+                    throw new SecurityException(ioe.getLocalizedMessage(), ioe);
                 }
                 return null;
             }
-            });
-        } catch (SecurityException se) {
+        });
+    }
+
+    private void readConfig(Reader reader,
+        Map<String, List<AppConfigurationEntry>> newConfig)
+        throws IOException {
+
+        linenum = 1;
+
+        if (!(reader instanceof BufferedReader))
+            reader = new BufferedReader(reader);
+
+        st = new StreamTokenizer(reader);
+        st.quoteChar('"');
+        st.wordChars('$', '$');
+        st.wordChars('_', '_');
+        st.wordChars('-', '-');
+        st.lowerCaseMode(false);
+        st.slashSlashComments(true);
+        st.slashStarComments(true);
+        st.eolIsSignificant(true);
+
+        lookahead = nextToken();
+        while (lookahead != StreamTokenizer.TT_EOF) {
+            parseLoginEntry(newConfig);
+        }
+    }
+
+    private void parseLoginEntry(
+        Map<String, List<AppConfigurationEntry>> newConfig)
+        throws IOException {
+
+        List<AppConfigurationEntry> configEntries = new LinkedList<>();
+
+        // application name
+        String appName = st.sval;
+        lookahead = nextToken();
+
+        if (debugParser != null) {
+            debugParser.println("\tReading next config entry: " + appName);
+        }
+
+        match("{");
 
-            // if ConfigFile threw a standalone SecurityException
-            // (no cause), re-throw it.
-            //
-            // ConfigFile chains checked IOExceptions to SecurityException.
+        // get the modules
+        while (peek("}") == false) {
+            // get the module class name
+            String moduleClass = match("module class name");
 
-            Throwable cause = se.getCause();
-            if (cause != null && cause instanceof java.io.IOException) {
-                throw (java.io.IOException)cause;
+            // controlFlag (required, optional, etc)
+            AppConfigurationEntry.LoginModuleControlFlag controlFlag;
+            String sflag = match("controlFlag").toUpperCase();
+            switch (sflag) {
+                case "REQUIRED":
+                    controlFlag =
+                        AppConfigurationEntry.LoginModuleControlFlag.REQUIRED;
+                    break;
+                case "REQUISITE":
+                    controlFlag =
+                        AppConfigurationEntry.LoginModuleControlFlag.REQUISITE;
+                    break;
+                case "SUFFICIENT":
+                    controlFlag =
+                        AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT;
+                    break;
+                case "OPTIONAL":
+                    controlFlag =
+                        AppConfigurationEntry.LoginModuleControlFlag.OPTIONAL;
+                    break;
+                default:
+                    MessageFormat form = new MessageFormat(
+                        ResourcesMgr.getString
+                        ("Configuration.Error.Invalid.control.flag.flag",
+                        "sun.security.util.AuthResources"));
+                    Object[] source = {sflag};
+                    throw new IOException(form.format(source));
+            }
+
+            // get the args
+            Map<String, String> options = new HashMap<>();
+            while (peek(";") == false) {
+                String key = match("option key");
+                match("=");
+                try {
+                    options.put(key, expand(match("option value")));
+                } catch (PropertyExpander.ExpandException peee) {
+                    throw new IOException(peee.getLocalizedMessage());
+                }
             }
 
-            // unrecognized cause
-            throw se;
+            lookahead = nextToken();
+
+            // create the new element
+            if (debugParser != null) {
+                debugParser.println("\t\t" + moduleClass + ", " + sflag);
+                for (String key : options.keySet()) {
+                    debugParser.println("\t\t\t" + key +
+                                        "=" + options.get(key));
+                }
+            }
+            configEntries.add(new AppConfigurationEntry(moduleClass,
+                                                        controlFlag, options));
         }
 
-        // if ConfigFile throws some other RuntimeException,
-        // let it percolate up naturally.
+        match("}");
+        match(";");
+
+        // add this configuration entry
+        if (newConfig.containsKey(appName)) {
+            MessageFormat form = new MessageFormat(ResourcesMgr.getString
+                ("Configuration.Error.Can.not.specify.multiple.entries.for.appName",
+                "sun.security.util.AuthResources"));
+            Object[] source = {appName};
+            throw new IOException(form.format(source));
+        }
+        newConfig.put(appName, configEntries);
     }
 
-    protected AppConfigurationEntry[] engineGetAppConfigurationEntry
-                (String name) {
-        return cf.getAppConfigurationEntry(name);
+    private String match(String expect) throws IOException {
+
+        String value = null;
+
+        switch(lookahead) {
+        case StreamTokenizer.TT_EOF:
+
+            MessageFormat form1 = new MessageFormat(ResourcesMgr.getString
+                ("Configuration.Error.expected.expect.read.end.of.file.",
+                "sun.security.util.AuthResources"));
+            Object[] source1 = {expect};
+            throw new IOException(form1.format(source1));
+
+        case '"':
+        case StreamTokenizer.TT_WORD:
+
+            if (expect.equalsIgnoreCase("module class name") ||
+                expect.equalsIgnoreCase("controlFlag") ||
+                expect.equalsIgnoreCase("option key") ||
+                expect.equalsIgnoreCase("option value")) {
+                value = st.sval;
+                lookahead = nextToken();
+            } else {
+                MessageFormat form = new MessageFormat(ResourcesMgr.getString
+                        ("Configuration.Error.Line.line.expected.expect.found.value.",
+                        "sun.security.util.AuthResources"));
+                Object[] source = {new Integer(linenum), expect, st.sval};
+                throw new IOException(form.format(source));
+            }
+            break;
+
+        case '{':
+
+            if (expect.equalsIgnoreCase("{")) {
+                lookahead = nextToken();
+            } else {
+                MessageFormat form = new MessageFormat(ResourcesMgr.getString
+                        ("Configuration.Error.Line.line.expected.expect.",
+                        "sun.security.util.AuthResources"));
+                Object[] source = {new Integer(linenum), expect, st.sval};
+                throw new IOException(form.format(source));
+            }
+            break;
+
+        case ';':
+
+            if (expect.equalsIgnoreCase(";")) {
+                lookahead = nextToken();
+            } else {
+                MessageFormat form = new MessageFormat(ResourcesMgr.getString
+                        ("Configuration.Error.Line.line.expected.expect.",
+                        "sun.security.util.AuthResources"));
+                Object[] source = {new Integer(linenum), expect, st.sval};
+                throw new IOException(form.format(source));
+            }
+            break;
+
+        case '}':
+
+            if (expect.equalsIgnoreCase("}")) {
+                lookahead = nextToken();
+            } else {
+                MessageFormat form = new MessageFormat(ResourcesMgr.getString
+                        ("Configuration.Error.Line.line.expected.expect.",
+                        "sun.security.util.AuthResources"));
+                Object[] source = {new Integer(linenum), expect, st.sval};
+                throw new IOException(form.format(source));
+            }
+            break;
+
+        case '=':
+
+            if (expect.equalsIgnoreCase("=")) {
+                lookahead = nextToken();
+            } else {
+                MessageFormat form = new MessageFormat(ResourcesMgr.getString
+                        ("Configuration.Error.Line.line.expected.expect.",
+                        "sun.security.util.AuthResources"));
+                Object[] source = {new Integer(linenum), expect, st.sval};
+                throw new IOException(form.format(source));
+            }
+            break;
+
+        default:
+            MessageFormat form = new MessageFormat(ResourcesMgr.getString
+                        ("Configuration.Error.Line.line.expected.expect.found.value.",
+                        "sun.security.util.AuthResources"));
+            Object[] source = {new Integer(linenum), expect, st.sval};
+            throw new IOException(form.format(source));
+        }
+        return value;
     }
 
-    protected void engineRefresh() {
-        cf.refresh();
+    private boolean peek(String expect) {
+        boolean found = false;
+
+        switch (lookahead) {
+        case ',':
+            if (expect.equalsIgnoreCase(","))
+                found = true;
+            break;
+        case ';':
+            if (expect.equalsIgnoreCase(";"))
+                found = true;
+            break;
+        case '{':
+            if (expect.equalsIgnoreCase("{"))
+                found = true;
+            break;
+        case '}':
+            if (expect.equalsIgnoreCase("}"))
+                found = true;
+            break;
+        default:
+        }
+        return found;
+    }
+
+    private int nextToken() throws IOException {
+        int tok;
+        while ((tok = st.nextToken()) == StreamTokenizer.TT_EOL) {
+            linenum++;
+        }
+        return tok;
+    }
+
+    private InputStream getInputStream(URL url) throws IOException {
+        if ("file".equalsIgnoreCase(url.getProtocol())) {
+            // Compatibility notes:
+            //
+            // Code changed from
+            //   String path = url.getFile().replace('/', File.separatorChar);
+            //   return new FileInputStream(path);
+            //
+            // The original implementation would search for "/tmp/a%20b"
+            // when url is "file:///tmp/a%20b". This is incorrect. The
+            // current codes fix this bug and searches for "/tmp/a b".
+            // For compatibility reasons, when the file "/tmp/a b" does
+            // not exist, the file named "/tmp/a%20b" will be tried.
+            //
+            // This also means that if both file exists, the behavior of
+            // this method is changed, and the current codes choose the
+            // correct one.
+            try {
+                return url.openStream();
+            } catch (Exception e) {
+                String file = url.getPath();
+                if (url.getHost().length() > 0) {  // For Windows UNC
+                    file = "//" + url.getHost() + file;
+                }
+                if (debugConfig != null) {
+                    debugConfig.println("cannot read " + url +
+                                        ", try " + file);
+                }
+                return new FileInputStream(file);
+            }
+        } else {
+            return url.openStream();
+        }
+    }
+
+    private String expand(String value)
+        throws PropertyExpander.ExpandException, IOException {
+
+        if (value.isEmpty()) {
+            return value;
+        }
+
+        if (expandProp) {
+
+            String s = PropertyExpander.expand(value);
+
+            if (s == null || s.length() == 0) {
+                MessageFormat form = new MessageFormat(ResourcesMgr.getString
+                        ("Configuration.Error.Line.line.system.property.value.expanded.to.empty.value",
+                        "sun.security.util.AuthResources"));
+                Object[] source = {new Integer(linenum), value};
+                throw new IOException(form.format(source));
+            }
+            return s;
+        } else {
+            return value;
+        }
     }
 }
--- a/jdk/src/share/classes/sun/text/bidi/BidiBase.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/sun/text/bidi/BidiBase.java	Wed Jul 05 18:34:47 2017 +0200
@@ -3251,10 +3251,9 @@
     {
         verifyValidParaOrLine();
         BidiLine.getRuns(this);
-        if (runCount == 1) {
+        if (run < 0 || run >= runCount) {
             return getParaLevel();
         }
-        verifyIndex(run, 0, runCount);
         getLogicalToVisualRunsMap();
         return runs[logicalToVisualRunsMap[run]].level;
     }
--- a/jdk/src/share/classes/sun/util/resources/TimeZoneNamesBundle.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNamesBundle.java	Wed Jul 05 18:34:47 2017 +0200
@@ -104,7 +104,7 @@
         if (contents == null) {
             return null;
         }
-        int clen = Math.min(n, contents.length);
+        int clen = Math.min(n - 1, contents.length);
         String[] tmpobj = new String[clen+1];
         tmpobj[0] = key;
         System.arraycopy(contents, 0, tmpobj, 1, clen);
--- a/jdk/src/share/demo/java2d/J2DBench/build.xml	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/demo/java2d/J2DBench/build.xml	Wed Jul 05 18:34:47 2017 +0200
@@ -49,7 +49,7 @@
   <target name="compile" depends="init"
         description="compile the source " >
     <!-- Compile the java code from ${src} into ${build} -->
-    <javac debug="false" source="1.2" target="1.2" srcdir="${src}" destdir="${build}"/>
+    <javac debug="flase" source="1.5" target="1.5" srcdir="${src}" destdir="${build}"/>
   </target>
 
   <target name="run" depends="dist" 
--- a/jdk/src/share/demo/java2d/J2DBench/src/j2dbench/J2DBench.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/demo/java2d/J2DBench/src/j2dbench/J2DBench.java	Wed Jul 05 18:34:47 2017 +0200
@@ -69,6 +69,7 @@
 import j2dbench.tests.RenderTests;
 import j2dbench.tests.PixelTests;
 import j2dbench.tests.iio.IIOTests;
+import j2dbench.tests.cmm.CMMTests;
 import j2dbench.tests.text.TextConstructionTests;
 import j2dbench.tests.text.TextMeasureTests;
 import j2dbench.tests.text.TextRenderTests;
@@ -199,6 +200,7 @@
         TextMeasureTests.init();
         TextConstructionTests.init();
         IIOTests.init();
+        CMMTests.init();
 
         boolean gui = true;
         boolean showresults = true;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/demo/java2d/J2DBench/src/j2dbench/tests/cmm/CMMTests.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This source code is provided to illustrate the usage of a given feature
+ * or technique and has been deliberately simplified. Additional steps
+ * required for a production-quality application, such as security checks,
+ * input validation and proper error handling, might not be present in
+ * this sample code.
+ */
+
+package j2dbench.tests.cmm;
+
+import j2dbench.Group;
+import j2dbench.Option;
+import j2dbench.Result;
+import j2dbench.Test;
+import j2dbench.TestEnvironment;
+import java.awt.color.ColorSpace;
+import java.awt.color.ICC_ColorSpace;
+import java.awt.color.ICC_Profile;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class CMMTests extends Test {
+
+    protected static Group cmmRoot;
+    protected static Group cmmOptRoot;
+    protected static Option csList;
+    protected static Option usePlatfromProfiles;
+
+    public static void init() {
+        cmmRoot = new Group("cmm", "Color Management Benchmarks");
+        cmmRoot.setTabbed();
+
+        cmmOptRoot = new Group(cmmRoot, "opts", "General Options");
+
+        /*
+        usePlatfromProfiles =
+                new Option.Enable(cmmOptRoot, "csPlatfrom",
+                        "Use Platfrom Profiles", false);
+        */
+        int[] colorspaces = new int[] {
+            ColorSpace.CS_sRGB,
+            ColorSpace.CS_GRAY,
+            ColorSpace.CS_LINEAR_RGB,
+            ColorSpace.CS_CIEXYZ
+        };
+
+        String[] csNames = new String[]{
+            "CS_sRGB",
+            "CS_GRAY",
+            "CS_LINEAR_RGB",
+            "CS_CIEXYZ"
+        };
+
+        csList = new Option.IntList(cmmOptRoot,
+                "profiles", "Color Profiles",
+                colorspaces, csNames, csNames, 0x8);
+
+        ColorConversionTests.init();
+        ProfileTests.init();
+    }
+
+    protected static ColorSpace getColorSpace(TestEnvironment env) {
+        ColorSpace cs;
+        Boolean usePlatfrom = true; //(Boolean)env.getModifier(usePlatfromProfiles);
+
+        int cs_code = env.getIntValue(csList);
+        if (usePlatfrom) {
+            cs = ColorSpace.getInstance(cs_code);
+        } else {
+            String resource = "profiles/";
+            switch (cs_code) {
+                case ColorSpace.CS_CIEXYZ:
+                    resource += "CIEXYZ.pf";
+                    break;
+                case ColorSpace.CS_GRAY:
+                    resource += "GRAY.pf";
+                    break;
+                case ColorSpace.CS_LINEAR_RGB:
+                    resource += "LINEAR_RGB.pf";
+                    break;
+                case ColorSpace.CS_PYCC:
+                    resource += "PYCC.pf";
+                    break;
+                case ColorSpace.CS_sRGB:
+                    resource += "sRGB.pf";
+                    break;
+                default:
+                    throw new RuntimeException("Unknown color space: " + cs_code);
+            }
+
+            try {
+                InputStream is = CMMTests.class.getResourceAsStream(resource);
+                ICC_Profile p = ICC_Profile.getInstance(is);
+
+                cs = new ICC_ColorSpace(p);
+            } catch (IOException e) {
+                throw new RuntimeException("Unable load profile from resource " + resource, e);
+            }
+        }
+        return cs;
+    }
+
+    protected CMMTests(Group parent, String nodeName, String description) {
+        super(parent, nodeName, description);
+        addDependencies(cmmOptRoot, true);
+    }
+
+    @Override
+    public Object initTest(TestEnvironment te, Result result) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public void runTest(Object o, int i) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public void cleanupTest(TestEnvironment te, Object o) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/demo/java2d/J2DBench/src/j2dbench/tests/cmm/ColorConversionTests.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This source code is provided to illustrate the usage of a given feature
+ * or technique and has been deliberately simplified. Additional steps
+ * required for a production-quality application, such as security checks,
+ * input validation and proper error handling, might not be present in
+ * this sample code.
+ */
+
+package j2dbench.tests.cmm;
+
+import j2dbench.Group;
+
+public class ColorConversionTests extends CMMTests {
+
+    protected static Group colorConvRoot;
+
+    public static void init() {
+        colorConvRoot = new Group(cmmRoot, "colorconv", "Color Conversion Benchmarks");
+        colorConvRoot.setTabbed();
+
+        DataConversionTests.init();
+        ColorConvertOpTests.init();
+    }
+
+    protected ColorConversionTests(Group parent, String nodeName, String description) {
+        super(parent, nodeName, description);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/demo/java2d/J2DBench/src/j2dbench/tests/cmm/ColorConvertOpTests.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,383 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This source code is provided to illustrate the usage of a given feature
+ * or technique and has been deliberately simplified. Additional steps
+ * required for a production-quality application, such as security checks,
+ * input validation and proper error handling, might not be present in
+ * this sample code.
+ */
+
+package j2dbench.tests.cmm;
+
+import j2dbench.Group;
+import j2dbench.Option;
+import j2dbench.Result;
+import j2dbench.TestEnvironment;
+import j2dbench.tests.iio.IIOTests;
+import java.awt.AlphaComposite;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.color.ColorSpace;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorConvertOp;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+import javax.imageio.ImageIO;
+
+public class ColorConvertOpTests extends ColorConversionTests {
+
+    private static enum ImageContent {
+        BLANK("bank", "Blank (opaque black)"),
+        RANDOM("random", "Random"),
+        VECTOR("vector", "Vector Art"),
+        PHOTO("photo", "Photograph");
+
+        public final String name;
+        public final String descr;
+
+        private ImageContent(String name, String descr) {
+            this.name = name;
+            this.descr = descr;
+        }
+    }
+
+    private static enum ImageType {
+        INT_ARGB(BufferedImage.TYPE_INT_ARGB, "INT_ARGB", "TYPE_INT_ARGB"),
+        INT_RGB(BufferedImage.TYPE_INT_RGB, "INT_RGB", "TYPE_INT_RGB"),
+        INT_BGR(BufferedImage.TYPE_INT_BGR, "INT_BGR", "TYPE_INT_BGR"),
+        BYTE_3BYTE_BGR(BufferedImage.TYPE_3BYTE_BGR, "3BYTE_BGR", "TYPE_3BYTE_BGR"),
+        BYTE_4BYTE_ABGR(BufferedImage.TYPE_4BYTE_ABGR, "4BYTE_BGR", "TYPE_4BYTE_BGR"),
+        COMPATIBLE_DST(0, "Compatible", "Compatible destination");
+
+        private ImageType(int type, String abbr, String descr) {
+            this.type = type;
+            this.abbrev = abbr;
+            this.descr = descr;
+        }
+
+        public final int type;
+        public final String abbrev;
+        public final String descr;
+    }
+
+    private static enum ListType {
+        SRC("srcType", "Source Images"),
+        DST("dstType", "Destination Images");
+
+        private ListType(String name, String description) {
+            this.name = name;
+            this.description = description;
+        }
+        public final String name;
+        public final String description;
+    }
+
+    public static Option createImageTypeList(ListType listType) {
+
+        ImageType[] allTypes = ImageType.values();
+
+        int num = allTypes.length;
+        if (listType == ListType.SRC) {
+            num -= 1; // exclude compatible destination
+        }
+
+        ImageType[] t = new ImageType[num];
+        String[] names = new String[num];
+        String[] abbrev = new String[num];
+        String[] descr = new String[num];
+
+        for (int i = 0; i < num; i++) {
+            t[i] = allTypes[i];
+            names[i] = t[i].toString();
+            abbrev[i] = t[i].abbrev;
+            descr[i] = t[i].descr;
+        }
+
+        Option list = new Option.ObjectList(opOptionsRoot,
+                listType.name, listType.description,
+                names, t, abbrev, descr, 1);
+        return list;
+    }
+
+    protected static Group opConvRoot;
+
+    protected static Group opOptionsRoot;
+    protected static Option sizeList;
+    protected static Option contentList;
+
+    protected static Option sourceType;
+
+    protected static Option destinationType;
+
+    public static void init() {
+        opConvRoot = new Group(colorConvRoot, "ccop", "ColorConvertOp Tests");
+
+        opOptionsRoot = new Group(opConvRoot, "ccopOptions", "Options");
+
+        // size list
+        int[] sizes = new int[] {1, 20, 250, 1000, 4000};
+        String[] sizeStrs = new String[] {
+            "1x1", "20x20", "250x250", "1000x1000", "4000x4000"
+        };
+        String[] sizeDescs = new String[] {
+            "Tiny Images (1x1)",
+            "Small Images (20x20)",
+            "Medium Images (250x250)",
+            "Large Images (1000x1000)",
+            "Huge Images (4000x4000)",
+        };
+        sizeList = new Option.IntList(opOptionsRoot,
+                                      "size", "Image Size",
+                                      sizes, sizeStrs, sizeDescs, 0x4);
+        ((Option.ObjectList) sizeList).setNumRows(5);
+
+        // image content
+        ImageContent[] c = ImageContent.values();
+
+        String[] contentStrs = new String[c.length];
+        String[] contentDescs = new String[c.length];
+
+        for (int i = 0; i < c.length; i++) {
+            contentStrs[i] = c[i].name;
+            contentDescs[i] = c[i].descr;
+        };
+
+        contentList = new Option.ObjectList(opOptionsRoot,
+                                            "content", "Image Content",
+                                            contentStrs, c,
+                                            contentStrs, contentDescs,
+                                            0x8);
+
+        sourceType = createImageTypeList(ListType.SRC);
+
+        destinationType = createImageTypeList(ListType.DST);
+
+        new ConvertImageTest();
+        new ConvertRasterTest();
+        new DrawImageTest();
+    }
+
+    public ColorConvertOpTests(Group parent, String nodeName, String description) {
+        super(parent, nodeName, description);
+        addDependencies(opOptionsRoot, true);
+    }
+
+    public Object initTest(TestEnvironment env, Result res) {
+        return new Context(env, res);
+    }
+
+    public void cleanupTest(TestEnvironment env, Object o) {
+        Context ctx = (Context)o;
+        ctx.cs = null;
+        ctx.op_img = null;
+        ctx.op_rst = null;
+        ctx.dst = null;
+        ctx.src = null;
+        ctx.graphics = null;
+    }
+
+    private static class Context {
+        ColorSpace cs;
+        Graphics2D graphics;
+        ColorConvertOp op_img;
+        ColorConvertOp op_rst;
+
+        BufferedImage src;
+        BufferedImage dst;
+
+        WritableRaster rsrc;
+        WritableRaster rdst;
+
+        public Context(TestEnvironment env, Result res) {
+
+            graphics = (Graphics2D)env.getGraphics();
+            cs = getColorSpace(env);
+
+            // TODO: provide rendering hints
+            op_img = new ColorConvertOp(cs, null);
+            ColorSpace sRGB = ColorSpace.getInstance(ColorSpace.CS_sRGB);
+            op_rst = new ColorConvertOp(sRGB, cs, null);
+
+            int size = env.getIntValue(sizeList);
+
+            ImageContent content = (ImageContent)env.getModifier(contentList);
+            ImageType srcType = (ImageType)env.getModifier(sourceType);
+
+            src = createBufferedImage(size, size, content, srcType.type);
+            rsrc = src.getRaster();
+
+            ImageType dstType = (ImageType)env.getModifier(destinationType);
+            if (dstType == ImageType.COMPATIBLE_DST) {
+                dst = op_img.createCompatibleDestImage(src, null);
+            } else {
+                dst = createBufferedImage(size, size, content, dstType.type);
+            }
+            // raster always has to be comatible
+            rdst = op_rst.createCompatibleDestRaster(rsrc);
+        }
+    }
+
+    private static class ConvertImageTest extends ColorConvertOpTests {
+        public ConvertImageTest() {
+            super(opConvRoot, "op_img", "op.filetr(BufferedImage)");
+        }
+
+        public void runTest(Object octx, int numReps) {
+            final Context ctx = (Context)octx;
+            final ColorConvertOp op = ctx.op_img;
+
+            final BufferedImage src = ctx.src;
+            BufferedImage dst = ctx.dst;
+            do {
+                try {
+                    dst = op.filter(src, dst);
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            } while (--numReps >= 0);
+        }
+    }
+
+    private static class ConvertRasterTest extends ColorConvertOpTests {
+        public ConvertRasterTest() {
+            super(opConvRoot, "op_rst", "op.filetr(Raster)");
+        }
+
+        public void runTest(Object octx, int numReps) {
+            final Context ctx = (Context)octx;
+            final ColorConvertOp op = ctx.op_rst;
+
+            final Raster src = ctx.rsrc;
+            WritableRaster dst = ctx.rdst;
+            do {
+                try {
+                    dst = op.filter(src, dst);
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            } while (--numReps >= 0);
+        }
+    }
+
+    private static class DrawImageTest extends ColorConvertOpTests {
+        public DrawImageTest() {
+            super(opConvRoot, "op_draw", "drawImage(ColorConvertOp)");
+        }
+
+        public void runTest(Object octx, int numReps) {
+            final Context ctx = (Context)octx;
+            final ColorConvertOp op = ctx.op_img;
+
+            final Graphics2D g = ctx.graphics;
+
+            final BufferedImage src = ctx.src;
+
+            do {
+                g.drawImage(src, op, 0, 0);
+            } while (--numReps >= 0);
+        }
+    }
+
+    /**************************************************************************
+     ******                    Helper routines
+     *************************************************************************/
+    protected static BufferedImage createBufferedImage(int width,
+                                                       int height,
+                                                       ImageContent contentType,
+                                                       int type)
+    {
+        BufferedImage image;
+        image = new BufferedImage(width, height, type);
+        boolean hasAlpha = image.getColorModel().hasAlpha();
+        switch (contentType) {
+            case RANDOM:
+                for (int y = 0; y < height; y++) {
+                    for (int x = 0; x < width; x++) {
+                        int rgb = (int)(Math.random() * 0xffffff);
+                        if (hasAlpha) {
+                            rgb |= 0x7f000000;
+                        }
+                        image.setRGB(x, y, rgb);
+                    }
+                }
+                break;
+            case VECTOR:
+                {
+                    Graphics2D g = image.createGraphics();
+                    if (hasAlpha) {
+                        // fill background with a translucent color
+                        g.setComposite(AlphaComposite.getInstance(
+                                           AlphaComposite.SRC, 0.5f));
+                    }
+                    g.setColor(Color.blue);
+                    g.fillRect(0, 0, width, height);
+                    g.setComposite(AlphaComposite.Src);
+                    g.setColor(Color.yellow);
+                    g.fillOval(2, 2, width-4, height-4);
+                    g.setColor(Color.red);
+                    g.fillOval(4, 4, width-8, height-8);
+                    g.setColor(Color.green);
+                    g.fillRect(8, 8, width-16, height-16);
+                    g.setColor(Color.white);
+                    g.drawLine(0, 0, width, height);
+                    g.drawLine(0, height, width, 0);
+                    g.dispose();
+                    break;
+                }
+            case PHOTO:
+                {
+                    Image photo = null;
+                    try {
+                        photo = ImageIO.read(
+                            IIOTests.class.getResourceAsStream("images/photo.jpg"));
+                    } catch (Exception e) {
+                        System.err.println("error loading photo");
+                        e.printStackTrace();
+                    }
+                    Graphics2D g = image.createGraphics();
+                    if (hasAlpha) {
+                        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC,
+                                                                  0.5f));
+                    }
+                    g.drawImage(photo, 0, 0, width, height, null);
+                    g.dispose();
+                    break;
+                }
+            default:
+                break;
+        }
+
+        return image;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/demo/java2d/J2DBench/src/j2dbench/tests/cmm/DataConversionTests.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This source code is provided to illustrate the usage of a given feature
+ * or technique and has been deliberately simplified. Additional steps
+ * required for a production-quality application, such as security checks,
+ * input validation and proper error handling, might not be present in
+ * this sample code.
+ */
+
+package j2dbench.tests.cmm;
+
+import j2dbench.Group;
+import j2dbench.Result;
+import j2dbench.TestEnvironment;
+import java.awt.color.ColorSpace;
+
+public class DataConversionTests extends ColorConversionTests {
+
+    protected static Group dataConvRoot;
+
+    public static void init() {
+        dataConvRoot = new Group(colorConvRoot, "data", "Data Conversoion Tests");
+
+        new FromRGBTest();
+        new ToRGBTest();
+        new FromCIEXYZTest();
+        new ToCIEXYZTest();
+    }
+
+    public DataConversionTests(Group parent, String nodeName, String description) {
+        super(parent, nodeName, description);
+    }
+
+    protected static class Context {
+
+        ColorSpace cs;
+        int numComponents;
+        float[] val;
+        float[] rgb;
+        float[] cie;
+        TestEnvironment env;
+        Result res;
+
+        public Context(TestEnvironment env, Result result, ColorSpace cs) {
+            this.cs = cs;
+            this.env = env;
+            this.res = result;
+
+            numComponents = cs.getNumComponents();
+
+            val = new float[numComponents];
+
+            for (int i = 0; i < numComponents; i++) {
+                float min = cs.getMinValue(i);
+                float max = cs.getMaxValue(i);
+
+                val[i] = 0.5f * (max - min);
+            }
+
+            rgb = new float[]{0.5f, 0.5f, 0.5f};
+            cie = new float[]{0.5f, 0.5f, 0.5f};
+        }
+    }
+
+    @Override
+    public Object initTest(TestEnvironment env, Result result) {
+        ColorSpace cs = getColorSpace(env);
+        return new Context(env, result, cs);
+    }
+
+    @Override
+    public void cleanupTest(TestEnvironment te, Object o) {
+    }
+
+    private static class FromRGBTest extends DataConversionTests {
+
+        public FromRGBTest() {
+            super(dataConvRoot,
+                    "fromRGB",
+                    "ColorSpace.fromRGB()");
+        }
+
+        public void runTest(Object ctx, int numReps) {
+            final Context ictx = (Context) ctx;
+            final ColorSpace cs = ictx.cs;
+
+            final float[] rgb = ictx.rgb;
+            do {
+                try {
+                    cs.fromRGB(rgb);
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            } while (--numReps >= 0);
+        }
+    }
+
+    private static class FromCIEXYZTest extends DataConversionTests {
+
+        public FromCIEXYZTest() {
+            super(dataConvRoot,
+                    "fromCIEXYZ",
+                    "ColorSpace.fromCIEXYZ()");
+        }
+
+        public void runTest(Object ctx, int numReps) {
+            final Context ictx = (Context) ctx;
+            final ColorSpace cs = ictx.cs;
+
+            final float[] val = ictx.cie;
+            do {
+                try {
+                    cs.fromCIEXYZ(val);
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            } while (--numReps >= 0);
+        }
+    }
+
+    private static class ToCIEXYZTest extends DataConversionTests {
+
+        public ToCIEXYZTest() {
+            super(dataConvRoot,
+                    "toCIEXYZ",
+                    "ColorSpace.toCIEXYZ()");
+        }
+
+        public void runTest(Object ctx, int numReps) {
+            final Context ictx = (Context) ctx;
+            final ColorSpace cs = ictx.cs;
+
+            final float[] val = ictx.val;
+
+            do {
+                try {
+                    cs.toCIEXYZ(val);
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            } while (--numReps >= 0);
+        }
+    }
+
+    private static class ToRGBTest extends DataConversionTests {
+
+        public ToRGBTest() {
+            super(dataConvRoot,
+                    "toRGB",
+                    "ColorSpace.toRGB()");
+        }
+
+        public void runTest(Object ctx, int numReps) {
+            final Context ictx = (Context) ctx;
+            final ColorSpace cs = ictx.cs;
+
+            final float[] val = ictx.val;
+
+            do {
+                try {
+                    cs.toRGB(val);
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            } while (--numReps >= 0);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/demo/java2d/J2DBench/src/j2dbench/tests/cmm/ProfileTests.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This source code is provided to illustrate the usage of a given feature
+ * or technique and has been deliberately simplified. Additional steps
+ * required for a production-quality application, such as security checks,
+ * input validation and proper error handling, might not be present in
+ * this sample code.
+ */
+package j2dbench.tests.cmm;
+
+import j2dbench.Group;
+import j2dbench.Result;
+import j2dbench.TestEnvironment;
+import java.awt.color.ColorSpace;
+import java.awt.color.ICC_ColorSpace;
+import java.awt.color.ICC_Profile;
+
+public class ProfileTests extends CMMTests {
+
+    protected static Group profileRoot;
+
+    public static void init() {
+        profileRoot = new Group(cmmRoot, "profiles", "Profile Handling Benchmarks");
+
+        new ReadHeaderTest();
+        new GetNumComponentsTest();
+    }
+
+    protected ProfileTests(Group parent, String nodeName, String description) {
+        super(parent, nodeName, description);
+    }
+
+    protected static class Context {
+
+        ICC_Profile profile;
+        TestEnvironment env;
+        Result res;
+
+        public Context(ICC_Profile profile, TestEnvironment env, Result res) {
+            this.profile = profile;
+            this.env = env;
+            this.res = res;
+        }
+    }
+
+    @Override
+    public Object initTest(TestEnvironment env, Result res) {
+        ICC_ColorSpace cs = (ICC_ColorSpace) getColorSpace(env);
+        return new Context(cs.getProfile(), env, res);
+    }
+
+    @Override
+    public void cleanupTest(TestEnvironment env, Object o) {
+    }
+
+    private static class ReadHeaderTest extends ProfileTests {
+
+        public ReadHeaderTest() {
+            super(profileRoot,
+                    "getHeader",
+                    "getData(icSigHead)");
+        }
+
+        @Override
+        public void runTest(Object ctx, int numReps) {
+            final Context ictx = (Context) ctx;
+            final ICC_Profile profile = ictx.profile;
+
+            byte[] data = null;
+            do {
+                try {
+                    data = profile.getData(ICC_Profile.icSigHead);
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            } while (--numReps >= 0);
+        }
+    }
+
+    private static class GetNumComponentsTest extends ProfileTests {
+
+        public GetNumComponentsTest() {
+            super(profileRoot,
+                    "getNumComponents",
+                    "getNumComponents");
+        }
+
+        @Override
+        public void runTest(Object ctx, int numReps) {
+            final Context ictx = (Context) ctx;
+            final ICC_Profile profile = ictx.profile;
+
+            do {
+                try {
+                    int num = profile.getNumComponents();
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            } while (--numReps >= 0);
+        }
+    }
+}
--- a/jdk/src/share/lib/security/java.security-linux	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/lib/security/java.security-linux	Wed Jul 05 18:34:47 2017 +0200
@@ -371,7 +371,7 @@
 #   jdk.certpath.disabledAlgorithms=MD2, DSA, RSA keySize < 2048
 #
 #
-jdk.certpath.disabledAlgorithms=MD2
+jdk.certpath.disabledAlgorithms=MD2, RSA keySize < 1024
 
 # Algorithm restrictions for Secure Socket Layer/Transport Layer Security
 # (SSL/TLS) processing
--- a/jdk/src/share/lib/security/java.security-macosx	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/lib/security/java.security-macosx	Wed Jul 05 18:34:47 2017 +0200
@@ -372,7 +372,7 @@
 #   jdk.certpath.disabledAlgorithms=MD2, DSA, RSA keySize < 2048
 #
 #
-jdk.certpath.disabledAlgorithms=MD2
+jdk.certpath.disabledAlgorithms=MD2, RSA keySize < 1024
 
 # Algorithm restrictions for Secure Socket Layer/Transport Layer Security
 # (SSL/TLS) processing
--- a/jdk/src/share/lib/security/java.security-solaris	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/lib/security/java.security-solaris	Wed Jul 05 18:34:47 2017 +0200
@@ -373,7 +373,7 @@
 #   jdk.certpath.disabledAlgorithms=MD2, DSA, RSA keySize < 2048
 #
 #
-jdk.certpath.disabledAlgorithms=MD2
+jdk.certpath.disabledAlgorithms=MD2, RSA keySize < 1024
 
 # Algorithm restrictions for Secure Socket Layer/Transport Layer Security
 # (SSL/TLS) processing
--- a/jdk/src/share/lib/security/java.security-windows	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/lib/security/java.security-windows	Wed Jul 05 18:34:47 2017 +0200
@@ -372,7 +372,7 @@
 #   jdk.certpath.disabledAlgorithms=MD2, DSA, RSA keySize < 2048
 #
 #
-jdk.certpath.disabledAlgorithms=MD2
+jdk.certpath.disabledAlgorithms=MD2, RSA keySize < 1024
 
 # Algorithm restrictions for Secure Socket Layer/Transport Layer Security
 # (SSL/TLS) processing
--- a/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c	Wed Jul 05 18:34:47 2017 +0200
@@ -159,7 +159,8 @@
  */
 JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_createNativeTransform
   (JNIEnv *env, jclass cls, jlongArray profileIDs, jint renderType,
-   jint inFormatter, jint outFormatter, jobject disposerRef)
+   jint inFormatter, jboolean isInIntPacked,
+   jint outFormatter, jboolean isOutIntPacked, jobject disposerRef)
 {
     cmsHPROFILE _iccArray[DF_ICC_BUF_SIZE];
     cmsHPROFILE *iccArray = &_iccArray[0];
@@ -170,6 +171,16 @@
     size = (*env)->GetArrayLength (env, profileIDs);
     ids = (*env)->GetPrimitiveArrayCritical(env, profileIDs, 0);
 
+#ifdef _LITTLE_ENDIAN
+    /* Reversing data packed into int for LE archs */
+    if (isInIntPacked) {
+        inFormatter ^= DOSWAP_SH(1);
+    }
+    if (isOutIntPacked) {
+        outFormatter ^= DOSWAP_SH(1);
+    }
+#endif
+
     if (DF_ICC_BUF_SIZE < size*2) {
         iccArray = (cmsHPROFILE*) malloc(
             size*2*sizeof(cmsHPROFILE));
@@ -567,7 +578,7 @@
   (JNIEnv *env, jclass obj, jobject trans, jobject src, jobject dst)
 {
     storeID_t sTrans;
-    int inFmt, outFmt, srcDType, dstDType;
+    int srcDType, dstDType;
     int srcOffset, srcNextRowOffset, dstOffset, dstNextRowOffset;
     int width, height, i;
     void* inputBuffer;
@@ -576,23 +587,13 @@
     char* outputRow;
     jobject srcData, dstData;
 
-    inFmt = (*env)->GetIntField (env, src, IL_pixelType_fID);
-    outFmt = (*env)->GetIntField (env, dst, IL_pixelType_fID);
     srcOffset = (*env)->GetIntField (env, src, IL_offset_fID);
     srcNextRowOffset = (*env)->GetIntField (env, src, IL_nextRowOffset_fID);
     dstOffset = (*env)->GetIntField (env, dst, IL_offset_fID);
     dstNextRowOffset = (*env)->GetIntField (env, dst, IL_nextRowOffset_fID);
     width = (*env)->GetIntField (env, src, IL_width_fID);
     height = (*env)->GetIntField (env, src, IL_height_fID);
-#ifdef _LITTLE_ENDIAN
-    /* Reversing data packed into int for LE archs */
-    if ((*env)->GetBooleanField (env, src, IL_isIntPacked_fID) == JNI_TRUE) {
-        inFmt ^= DOSWAP_SH(1);
-    }
-    if ((*env)->GetBooleanField (env, dst, IL_isIntPacked_fID) == JNI_TRUE) {
-        outFmt ^= DOSWAP_SH(1);
-    }
-#endif
+
     sTrans.j = (*env)->GetLongField (env, trans, Trans_ID_fID);
 
     if (sTrans.xf == NULL) {
--- a/jdk/src/solaris/classes/sun/awt/X11/XBaseWindow.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/solaris/classes/sun/awt/X11/XBaseWindow.java	Wed Jul 05 18:34:47 2017 +0200
@@ -994,10 +994,7 @@
             return;
         }
         int buttonState = 0;
-        final int buttonsNumber = ((SunToolkit)(Toolkit.getDefaultToolkit())).getNumberOfButtons();
-        for (int i = 0; i<buttonsNumber; i++){
-            buttonState |= (xbe.get_state() & XConstants.buttonsMask[i]);
-        }
+        buttonState = xbe.get_state() & XConstants.ALL_BUTTONS_MASK;
         switch (xev.get_type()) {
         case XConstants.ButtonPress:
             if (buttonState == 0) {
@@ -1034,12 +1031,12 @@
      * Checks ButtonRelease released all Mouse buttons
      */
     static boolean isFullRelease(int buttonState, int button) {
-        final int buttonsNumber = ((SunToolkit)(Toolkit.getDefaultToolkit())).getNumberOfButtons();
+        final int buttonsNumber = XToolkit.getNumberOfButtonsForMask();
 
         if (button < 0 || button > buttonsNumber) {
             return buttonState == 0;
         } else {
-            return buttonState == XConstants.buttonsMask[button - 1];
+            return buttonState == XlibUtil.getButtonMask(button);
         }
     }
 
--- a/jdk/src/solaris/classes/sun/awt/X11/XConstants.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/solaris/classes/sun/awt/X11/XConstants.java	Wed Jul 05 18:34:47 2017 +0200
@@ -130,6 +130,9 @@
     public static final long ColormapChangeMask = (1L<<23) ;
     public static final long OwnerGrabButtonMask = (1L<<24) ;
 
+    public static final int MAX_BUTTONS = 5;
+    public static final int ALL_BUTTONS_MASK = (int) (Button1MotionMask | Button2MotionMask | Button3MotionMask | Button4MotionMask | Button5MotionMask);
+
     /* Event names.  Used in "type" field in XEvent structures.  Not to be
     confused with event masks above.  They start from 2 because 0 and 1
     are reserved in the protocol for errors and replies. */
@@ -194,34 +197,6 @@
     public static final int Mod4MapIndex = 6 ;
     public static final int Mod5MapIndex = 7 ;
 
-
-    /* button masks.  Used in same manner as Key masks above. Not to be confused
-       with button names below. */
-    public static final int [] buttonsMask = new int []{ 1<<8,
-                                                         1<<9,
-                                                         1<<10,
-                                                         1<<11,
-                                                         1<<12,
-                                                         1<<13,
-                                                         1<<14,
-                                                         1<<15,
-                                                         1<<16,
-                                                         1<<17,
-                                                         1<<18,
-                                                         1<<19,
-                                                         1<<20,
-                                                         1<<21,
-                                                         1<<22,
-                                                         1<<23,
-                                                         1<<24,
-                                                         1<<25,
-                                                         1<<26,
-                                                         1<<27,
-                                                         1<<28,
-                                                         1<<29,
-                                                         1<<30,
-                                                         1<<31 };
-
     public static final int AnyModifier = (1<<15) ; /* used in GrabButton, GrabKey */
 
 
--- a/jdk/src/solaris/classes/sun/awt/X11/XToolkit.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/solaris/classes/sun/awt/X11/XToolkit.java	Wed Jul 05 18:34:47 2017 +0200
@@ -1543,6 +1543,10 @@
         }
     }
 
+    static int getNumberOfButtonsForMask() {
+        return Math.min(XConstants.MAX_BUTTONS, ((SunToolkit) (Toolkit.getDefaultToolkit())).getNumberOfButtons());
+    }
+
     private final static String prefix  = "DnD.Cursor.";
     private final static String postfix = ".32x32";
     private static final String dndPrefix  = "DnD.";
--- a/jdk/src/solaris/classes/sun/awt/X11/XWindow.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/solaris/classes/sun/awt/X11/XWindow.java	Wed Jul 05 18:34:47 2017 +0200
@@ -596,12 +596,12 @@
         /* this is an attempt to refactor button IDs in : MouseEvent, InputEvent, XlibWrapper and XWindow.*/
 
         //reflects a button number similar to MouseEvent.BUTTON1, 2, 3 etc.
-        for (int i = 0; i < XConstants.buttonsMask.length; i ++){
+        for (int i = 0; i < XConstants.buttons.length; i ++){
             //modifier should be added if :
             // 1) current button is now still in PRESSED state (means that user just pressed mouse but not released yet) or
             // 2) if Xsystem reports that "state" represents that button was just released. This only happens on RELEASE with 1,2,3 buttons.
             // ONLY one of these conditions should be TRUE to add that modifier.
-            if (((state & XConstants.buttonsMask[i]) != 0) != (button == XConstants.buttons[i])){
+            if (((state & XlibUtil.getButtonMask(i + 1)) != 0) != (button == XConstants.buttons[i])){
                 //exclude wheel buttons from adding their numbers as modifiers
                 if (!wheel_mouse) {
                     modifiers |= InputEvent.getMaskForButton(i+1);
@@ -689,7 +689,7 @@
 
         if (type == XConstants.ButtonPress) {
             //Allow this mouse button to generate CLICK event on next ButtonRelease
-            mouseButtonClickAllowed |= XConstants.buttonsMask[lbutton];
+            mouseButtonClickAllowed |= XlibUtil.getButtonMask(lbutton);
             XWindow lastWindow = (lastWindowRef != null) ? ((XWindow)lastWindowRef.get()):(null);
             /*
                multiclick checking
@@ -747,7 +747,7 @@
             postEventToEventQueue(me);
 
             if ((type == XConstants.ButtonRelease) &&
-                ((mouseButtonClickAllowed & XConstants.buttonsMask[lbutton]) != 0) ) // No up-button in the drag-state
+                ((mouseButtonClickAllowed & XlibUtil.getButtonMask(lbutton)) != 0) ) // No up-button in the drag-state
             {
                 postEventToEventQueue(me = new MouseEvent((Component)getEventSource(),
                                                      MouseEvent.MOUSE_CLICKED,
@@ -777,7 +777,7 @@
         /* Update the state variable AFTER the CLICKED event post. */
         if (type == XConstants.ButtonRelease) {
             /* Exclude this mouse button from allowed list.*/
-            mouseButtonClickAllowed &= ~XConstants.buttonsMask[lbutton];
+            mouseButtonClickAllowed &= ~ XlibUtil.getButtonMask(lbutton);
         }
     }
 
@@ -793,12 +793,12 @@
         //this doesn't work for extra buttons because Xsystem is sending state==0 for every extra button event.
         // we can't correct it in MouseEvent class as we done it with modifiers, because exact type (DRAG|MOVE)
         // should be passed from XWindow.
-        final int buttonsNumber = ((SunToolkit)(Toolkit.getDefaultToolkit())).getNumberOfButtons();
+        final int buttonsNumber = XToolkit.getNumberOfButtonsForMask();
 
         for (int i = 0; i < buttonsNumber; i++){
             // TODO : here is the bug in WM: extra buttons doesn't have state!=0 as they should.
             if ((i != 4) && (i != 5)) {
-                mouseKeyState = mouseKeyState | (xme.get_state() & XConstants.buttonsMask[i]);
+                mouseKeyState = mouseKeyState | (xme.get_state() & XlibUtil.getButtonMask(i + 1));
             }
         }
 
--- a/jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java	Wed Jul 05 18:34:47 2017 +0200
@@ -2070,12 +2070,12 @@
         }
         if (isGrabbed()) {
             boolean dragging = false;
-            final int buttonsNumber = ((SunToolkit)(Toolkit.getDefaultToolkit())).getNumberOfButtons();
+            final int buttonsNumber = XToolkit.getNumberOfButtonsForMask();
 
             for (int i = 0; i < buttonsNumber; i++){
                 // here is the bug in WM: extra buttons doesn't have state!=0 as they should.
                 if ((i != 4) && (i != 5)){
-                    dragging = dragging || ((xme.get_state() & XConstants.buttonsMask[i]) != 0);
+                    dragging = dragging || ((xme.get_state() & XlibUtil.getButtonMask(i + 1)) != 0);
                 }
             }
             // When window is grabbed, all events are dispatched to
--- a/jdk/src/solaris/classes/sun/awt/X11/XlibUtil.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/solaris/classes/sun/awt/X11/XlibUtil.java	Wed Jul 05 18:34:47 2017 +0200
@@ -396,4 +396,14 @@
         return isShapingSupported.booleanValue();
     }
 
+    static int getButtonMask(int button) {
+        // Button indices start with 1. The first bit in the button mask is the 8th.
+        // The state mask does not support button indicies > 5, so we need to
+        // cut there.
+        if (button <= 0 || button > XConstants.MAX_BUTTONS) {
+            return 0;
+        } else {
+            return 1 << (7 + button);
+        }
+    }
 }
--- a/jdk/src/windows/native/sun/windows/awt_Debug.cpp	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/src/windows/native/sun/windows/awt_Debug.cpp	Wed Jul 05 18:34:47 2017 +0200
@@ -147,6 +147,24 @@
     DTrace_Shutdown();
 }
 
+static jboolean isHeadless() {
+    jmethodID headlessFn;
+    JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
+    jclass graphicsEnvClass = env->FindClass(
+        "java/awt/GraphicsEnvironment");
+
+    if (graphicsEnvClass != NULL) {
+        headlessFn = env->GetStaticMethodID(
+            graphicsEnvClass, "isHeadless", "()Z");
+        if (headlessFn != NULL) {
+            return env->CallStaticBooleanMethod(graphicsEnvClass,
+                                                headlessFn);
+        }
+    }
+    return true;
+}
+
+
 void AwtDebugSupport::AssertCallback(const char * expr, const char * file, int line) {
     static const int ASSERT_MSG_SIZE = 1024;
     static const char * AssertFmt =
@@ -158,7 +176,8 @@
     static char assertMsg[ASSERT_MSG_SIZE+1];
     DWORD   lastError = GetLastError();
     LPSTR       msgBuffer = NULL;
-    int     ret;
+    int     ret = IDNO;
+    static jboolean headless = isHeadless();
 
     FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
                   FORMAT_MESSAGE_FROM_SYSTEM |
@@ -183,8 +202,11 @@
     fprintf(stderr, "*********************\n");
     fprintf(stderr, "%s\n", assertMsg);
     fprintf(stderr, "*********************\n");
-    ret = MessageBoxA(NULL, assertMsg, "AWT Assertion Failure",
-        MB_YESNO|MB_ICONSTOP|MB_TASKMODAL);
+
+    if (!headless) {
+        ret = MessageBoxA(NULL, assertMsg, "AWT Assertion Failure",
+                          MB_YESNO|MB_ICONSTOP|MB_TASKMODAL);
+    }
 
     // if clicked Yes, break into the debugger
     if ( ret == IDYES ) {
--- a/jdk/test/ProblemList.txt	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/ProblemList.txt	Wed Jul 05 18:34:47 2017 +0200
@@ -141,9 +141,6 @@
 
 # jdk_management
 
-# 7158614
-sun/management/jmxremote/startstop/JMXStartStopTest.sh		linux-all
-
 ############################################################################
 
 # jdk_jmx
@@ -151,9 +148,6 @@
 # 6959636
 javax/management/loading/LibraryLoader/LibraryLoaderTest.java	windows-all
 
-# 7120365
-javax/management/remote/mandatory/notif/DiffHBTest.java 	generic-all
-
 ############################################################################
 
 # jdk_math
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/jmx/remote/CCAdminReconnectTest.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 7009998
+ * @summary Tests the correct processing of concurrent ClientComunicatorAdmin reconnect requests.
+ * @author Jaroslav Bachorik
+ * @run clean CCAdminReconnectTest
+ * @run build CCAdminReconnectTest
+ * @run main CCAdminReconnectTest
+ */
+
+import com.sun.jmx.remote.internal.ClientCommunicatorAdmin;
+import java.io.*;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public class CCAdminReconnectTest {
+    final private static int THREAD_COUNT = 3;
+
+    public static void main(String ... args) throws Exception {
+        final ExecutorService e = Executors.newFixedThreadPool(THREAD_COUNT);
+        final AtomicBoolean beingReconnected = new AtomicBoolean();
+        final Collection<Exception> thrownExceptions = new LinkedList<>();
+
+        System.out.println(": Testing concurrent restart of ClientCommunicatorAdmin");
+
+        final ClientCommunicatorAdmin cca = new ClientCommunicatorAdmin(50) {
+
+            @Override
+            protected void checkConnection() throws IOException {
+                // empty
+            }
+
+            @Override
+            protected void doStart() throws IOException {
+                if (!beingReconnected.compareAndSet(false, true)) {
+                    IOException e = new IOException("Detected overlayed reconnect requests");
+                    thrownExceptions.add(e);
+                    throw e;
+                }
+                try {
+                    Thread.sleep(800); // simulating a workload
+                    beingReconnected.set(false);
+                } catch (InterruptedException e) {
+                }
+            }
+
+            @Override
+            protected void doStop() {
+                // empty
+            }
+        };
+
+        Runnable r = new Runnable() {
+            final private IOException e = new IOException("Forced reconnect");
+            @Override
+            public void run() {
+                try {
+                    // forcing the reconnect request
+                    cca.gotIOException(e);
+                } catch (Exception ex) {
+                    ex.printStackTrace();
+                }
+            }
+        };
+
+        System.out.println(": Spawning " + THREAD_COUNT + " concurrent reconnect requests");
+
+        for(int i=0;i<THREAD_COUNT;i++) {
+            e.execute(r);
+        }
+
+        Thread.sleep(THREAD_COUNT * 1000);
+        e.shutdown();
+        e.awaitTermination(10, TimeUnit.SECONDS);
+
+        cca.terminate();
+
+        for(Exception thrown : thrownExceptions) {
+            throw thrown;
+        }
+        System.out.println(": Requests processed successfully");
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/jmx/remote/NotificationMarshalVersions/Client/Client.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,47 @@
+
+import java.nio.charset.Charset;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardWatchEventKinds;
+import java.nio.file.WatchEvent;
+import java.nio.file.WatchService;
+import javax.management.MBeanServerConnection;
+import javax.management.Notification;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXServiceURL;
+
+public class Client {
+    public static void main(String[] argv) throws Exception {
+        if (argv.length != 1) throw new IllegalArgumentException("Expecting exactly one jmx url argument");
+
+        JMXServiceURL serverUrl = new JMXServiceURL(argv[0]);
+
+        ObjectName name = new ObjectName("test", "foo", "bar");
+        JMXConnector jmxConnector = JMXConnectorFactory.connect(serverUrl);
+        System.out.println("client connected");
+        jmxConnector.addConnectionNotificationListener(new NotificationListener() {
+            public void handleNotification(Notification notification, Object handback) {
+                System.err.println("no!" + notification);
+            }
+        }, null, null);
+        MBeanServerConnection jmxServer = jmxConnector.getMBeanServerConnection();
+
+        jmxServer.addNotificationListener(name, new NotificationListener() {
+            public void handleNotification(Notification notification, Object handback) {
+                System.out.println("client got:" + notification);
+            }
+        }, null, null);
+
+        for(int i=0;i<10;i++) {
+            System.out.println("client invoking foo");
+            jmxServer.invoke(name, "foo", new Object[]{}, new String[]{});
+            Thread.sleep(50);
+        }
+
+        System.err.println("happy!");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/jmx/remote/NotificationMarshalVersions/Client/ConfigKey.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,3 @@
+public enum ConfigKey {
+    CONSTANT3, CONSTANT2;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/jmx/remote/NotificationMarshalVersions/Client/TestNotification.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,25 @@
+
+import javax.management.Notification;
+
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+/**
+ *
+ * @author Jaroslav Bachorik <jaroslav.bachorik at oracle.com>
+ */
+public class TestNotification extends Notification {
+    private ConfigKey key;
+
+    public TestNotification(String type, Object source, long sequenceNumber) {
+        super(type, source, sequenceNumber);
+        key = ConfigKey.CONSTANT3;
+    }
+
+    @Override
+    public String toString() {
+        return "TestNotification{" + "key=" + key + '}';
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/jmx/remote/NotificationMarshalVersions/Server/ConfigKey.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,3 @@
+public enum ConfigKey {
+    CONSTANT1, CONSTANT2;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/jmx/remote/NotificationMarshalVersions/Server/Server.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,46 @@
+import java.lang.management.ManagementFactory;
+import java.net.BindException;
+import java.nio.charset.Charset;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.server.ExportException;
+import java.util.Random;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
+
+public class Server {
+    public static void main(String[] argv) throws Exception {
+        int serverPort = 12345;
+        ObjectName name = new ObjectName("test", "foo", "bar");
+        MBeanServer jmxServer = ManagementFactory.getPlatformMBeanServer();
+        SteMBean bean = new Ste();
+        jmxServer.registerMBean(bean, name);
+        boolean exported = false;
+        Random rnd = new Random(System.currentTimeMillis());
+        do {
+            try {
+                LocateRegistry.createRegistry(serverPort);
+                exported = true;
+            } catch (ExportException ee) {
+                if (ee.getCause() instanceof BindException) {
+                    serverPort = rnd.nextInt(10000) + 4096;
+                } else {
+                    throw ee;
+                }
+            }
+
+        } while (!exported);
+        JMXServiceURL serverUrl = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:" + serverPort + "/test");
+        JMXConnectorServer jmxConnector = JMXConnectorServerFactory.newJMXConnectorServer(serverUrl, null, jmxServer);
+        jmxConnector.start();
+        System.out.println(serverUrl);
+        System.err.println("server listening on " + serverUrl);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/jmx/remote/NotificationMarshalVersions/Server/Ste.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,10 @@
+
+import javax.management.NotificationBroadcasterSupport;
+
+public class Ste extends NotificationBroadcasterSupport implements SteMBean {
+    private long count = 0;
+
+    public void foo() {
+        sendNotification(new TestNotification("test", this, count++));
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/jmx/remote/NotificationMarshalVersions/Server/SteMBean.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,3 @@
+public interface SteMBean {
+    public void foo();
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/jmx/remote/NotificationMarshalVersions/Server/TestNotification.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,25 @@
+
+import javax.management.Notification;
+
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+/**
+ *
+ * @author Jaroslav Bachorik <jaroslav.bachorik at oracle.com>
+ */
+public class TestNotification extends Notification {
+    private ConfigKey key;
+
+    public TestNotification(String type, Object source, long sequenceNumber) {
+        super(type, source, sequenceNumber);
+        key = ConfigKey.CONSTANT1;
+    }
+
+    @Override
+    public String toString() {
+        return "TestNotification{" + "key=" + key + '}';
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/jmx/remote/NotificationMarshalVersions/TestSerializationMismatch.sh	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,93 @@
+#
+# Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+# 
+# @test
+# @summary  Tests for the RMI unmarshalling errors not to cause silent failure.
+# @author   Jaroslav Bachorik
+# @bug      6937053
+#
+# @run shell TestSerializationMismatch.sh
+#
+
+#set -x
+
+#Set appropriate jdk
+#
+
+if [ ! -z "${TESTJAVA}" ] ; then
+     jdk="$TESTJAVA"
+else
+     echo "--Error: TESTJAVA must be defined as the pathname of a jdk to test."
+     exit 1
+fi
+
+SERVER_TESTCLASSES=$TESTCLASSES/Server
+CLIENT_TESTCLASSES=$TESTCLASSES/Client
+
+URL_PATH=$SERVER_TESTCLASSES/jmxurl
+
+rm $URL_PATH
+
+mkdir -p $SERVER_TESTCLASSES
+mkdir -p $CLIENT_TESTCLASSES
+
+$TESTJAVA/bin/javac -d $CLIENT_TESTCLASSES $TESTSRC/Client/ConfigKey.java $TESTSRC/Client/TestNotification.java $TESTSRC/Client/Client.java
+$TESTJAVA/bin/javac -d $SERVER_TESTCLASSES $TESTSRC/Server/ConfigKey.java $TESTSRC/Server/TestNotification.java $TESTSRC/Server/SteMBean.java $TESTSRC/Server/Ste.java $TESTSRC/Server/Server.java
+
+startServer()
+{
+   ($TESTJAVA/bin/java -classpath $SERVER_TESTCLASSES Server) 1>$URL_PATH &
+   SERVER_PID=$!
+}
+
+runClient() 
+{
+   while true
+   do
+      [ -f $URL_PATH ] && break
+      sleep 2
+   done
+   read JMXURL < $URL_PATH
+   
+   HAS_ERRORS=`($TESTJAVA/bin/java -classpath $CLIENT_TESTCLASSES Client $JMXURL) 2>&1 | grep -i "SEVERE: Failed to fetch notification, stopping thread. Error is: java.rmi.UnmarshalException"`
+}
+
+startServer
+
+runClient
+
+sleep 1 # wait for notifications to arrive
+
+kill "$SERVER_PID"
+
+if [ -z "$HAS_ERRORS" ]
+then
+  echo "Test PASSED"
+  exit 0
+fi
+
+echo "Test FAILED"
+echo $HAS_ERRORS 1>&2
+exit 1
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/beans/Introspector/Test8005065.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8005065
+ * @summary Tests that all arrays in JavaBeans are guarded
+ * @author Sergey Malenkov
+ */
+
+import java.beans.DefaultPersistenceDelegate;
+import java.beans.Encoder;
+import java.beans.EventSetDescriptor;
+import java.beans.ExceptionListener;
+import java.beans.Expression;
+import java.beans.Statement;
+import java.beans.MethodDescriptor;
+import java.beans.ParameterDescriptor;
+
+public class Test8005065 {
+
+    public static void main(String[] args) {
+        testDefaultPersistenceDelegate();
+        testEventSetDescriptor();
+        testMethodDescriptor();
+        testStatement();
+    }
+
+    private static void testDefaultPersistenceDelegate() {
+        Encoder encoder = new Encoder();
+        String[] array = { "array" };
+        MyDPD dpd = new MyDPD(array);
+        dpd.instantiate(dpd, encoder);
+        array[0] = null;
+        dpd.instantiate(dpd, encoder);
+    }
+
+    private static void testEventSetDescriptor() {
+        try {
+            MethodDescriptor[] array = { new MethodDescriptor(MyDPD.class.getMethod("getArray")) };
+            EventSetDescriptor descriptor = new EventSetDescriptor(null, null, array, null, null);
+            test(descriptor.getListenerMethodDescriptors());
+            array[0] = null;
+            test(descriptor.getListenerMethodDescriptors());
+            descriptor.getListenerMethodDescriptors()[0] = null;
+            test(descriptor.getListenerMethodDescriptors());
+        }
+        catch (Exception exception) {
+            throw new Error("unexpected error", exception);
+        }
+    }
+
+    private static void testMethodDescriptor() {
+        try {
+            ParameterDescriptor[] array = { new ParameterDescriptor() };
+            MethodDescriptor descriptor = new MethodDescriptor(MyDPD.class.getMethod("getArray"), array);
+            test(descriptor.getParameterDescriptors());
+            array[0] = null;
+            test(descriptor.getParameterDescriptors());
+            descriptor.getParameterDescriptors()[0] = null;
+            test(descriptor.getParameterDescriptors());
+        }
+        catch (Exception exception) {
+            throw new Error("unexpected error", exception);
+        }
+    }
+
+    private static void testStatement() {
+        Object[] array = { new Object() };
+        Statement statement = new Statement(null, null, array);
+        test(statement.getArguments());
+        array[0] = null;
+        test(statement.getArguments());
+        statement.getArguments()[0] = null;
+        test(statement.getArguments());
+    }
+
+    private static <T> void test(T[] array) {
+        if (array.length != 1) {
+            throw new Error("unexpected array length");
+        }
+        if (array[0] == null) {
+            throw new Error("unexpected array content");
+        }
+    }
+
+    public static class MyDPD
+            extends DefaultPersistenceDelegate
+            implements ExceptionListener {
+
+        private final String[] array;
+
+        public MyDPD(String[] array) {
+            super(array);
+            this.array = array;
+        }
+
+        public Expression instantiate(Object instance, Encoder encoder) {
+            encoder.setExceptionListener(this);
+            return super.instantiate(instance, encoder);
+        }
+
+        public String[] getArray() {
+            return this.array;
+        }
+
+        public void exceptionThrown(Exception exception) {
+            throw new Error("unexpected error", exception);
+        }
+    }
+}
--- a/jdk/test/java/io/Serializable/resolveProxyClass/NonPublicInterface.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/java/io/Serializable/resolveProxyClass/NonPublicInterface.java	Wed Jul 05 18:34:47 2017 +0200
@@ -22,14 +22,17 @@
  */
 
 /* @test
- * @bug 4413817
+ * @bug 4413817 8004928
  * @summary Verify that ObjectInputStream.resolveProxyClass can properly
  *          resolve a dynamic proxy class which implements a non-public
  *          interface not defined in the latest user defined class loader.
  */
 
 import java.io.*;
-import java.lang.reflect.*;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Proxy;
 
 public class NonPublicInterface {
 
@@ -39,35 +42,19 @@
         }
     }
 
+    public static final String nonPublicIntrfaceName = "java.util.zip.ZipConstants";
+
     public static void main(String[] args) throws Exception {
-        Class nonPublic = null;
-        String[] nonPublicInterfaces = new String[] {
-            "java.awt.Conditional",
-            "java.util.zip.ZipConstants",
-            "javax.swing.GraphicsWrapper",
-            "javax.swing.JPopupMenu$Popup",
-            "javax.swing.JTable$Resizable2",
-            "javax.swing.JTable$Resizable3",
-            "javax.swing.ToolTipManager$Popup",
-            "sun.audio.Format",
-            "sun.audio.HaePlayable",
-            "sun.tools.agent.StepConstants",
-        };
-        for (int i = 0; i < nonPublicInterfaces.length; i++) {
-            try {
-                nonPublic = Class.forName(nonPublicInterfaces[i]);
-                break;
-            } catch (ClassNotFoundException ex) {
-            }
-        }
-        if (nonPublic == null) {
-            throw new Error("couldn't find system non-public interface");
+        Class<?> nonPublic = Class.forName(nonPublicIntrfaceName);
+        if (Modifier.isPublic(nonPublic.getModifiers())) {
+            throw new Error("Interface " + nonPublicIntrfaceName +
+                    " is public and need to be changed!");
         }
 
         ByteArrayOutputStream bout = new ByteArrayOutputStream();
         ObjectOutputStream oout = new ObjectOutputStream(bout);
         oout.writeObject(Proxy.newProxyInstance(nonPublic.getClassLoader(),
-            new Class[]{ nonPublic }, new Handler()));
+            new Class<?>[]{ nonPublic }, new Handler()));
         oout.close();
         ObjectInputStream oin = new ObjectInputStream(
             new ByteArrayInputStream(bout.toByteArray()));
--- a/jdk/test/java/lang/Throwable/LegacyChainedExceptionSerialization.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/java/lang/Throwable/LegacyChainedExceptionSerialization.java	Wed Jul 05 18:34:47 2017 +0200
@@ -25,7 +25,7 @@
 
 /**
  * @test
- * @bug     4385429
+ * @bug     4385429 8004928
  * @summary Certain legacy chained exceptions throw IllegalArgumentException
  *          upon deserialization if "causative exception" is null.
  * @author  Josh Bloch
@@ -36,8 +36,7 @@
         new ExceptionInInitializerError(),
         new java.lang.reflect.UndeclaredThrowableException(null),
         new java.lang.reflect.InvocationTargetException(null),
-        new java.security.PrivilegedActionException(null),
-        new java.awt.print.PrinterIOException(null)
+        new java.security.PrivilegedActionException(null)
     };
 
     public static void main(String[] args) throws Exception {
--- a/jdk/test/java/lang/management/CompilationMXBean/Basic.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/java/lang/management/CompilationMXBean/Basic.java	Wed Jul 05 18:34:47 2017 +0200
@@ -23,10 +23,10 @@
 
 /*
  * @test
- * @bug 5011189
+ * @bug 5011189 8004928
  * @summary Unit test for java.lang.management.CompilationMXBean
  *
- * @run main/othervm -Xcomp -Xbatch -Djava.awt.headless=true Basic
+ * @run main/othervm -Xcomp -Xbatch Basic
  */
 import java.lang.management.*;
 
@@ -65,8 +65,6 @@
 
         java.util.Locale.getAvailableLocales();
         java.security.Security.getProviders();
-        java.awt.Toolkit.getDefaultToolkit();
-        javax.swing.UIManager.getInstalledLookAndFeels();
         java.nio.channels.spi.SelectorProvider.provider();
 
         time = mb.getTotalCompilationTime();
--- a/jdk/test/java/lang/reflect/Generics/Probe.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/java/lang/reflect/Generics/Probe.java	Wed Jul 05 18:34:47 2017 +0200
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 5003916 6704655 6873951 6476261
+ * @bug 5003916 6704655 6873951 6476261 8004928
  * @summary Testing parsing of signatures attributes of nested classes
  * @author Joseph D. Darcy
  */
@@ -52,8 +52,7 @@
           "java.util.HashMap$ValueIterator",
           "java.util.LinkedHashMap$EntryIterator",
           "java.util.LinkedHashMap$KeyIterator",
-          "java.util.LinkedHashMap$ValueIterator",
-          "javax.swing.JComboBox$AccessibleJComboBox"})
+          "java.util.LinkedHashMap$ValueIterator"})
 public class Probe {
     public static void main (String... args) throws Throwable {
         Classes classesAnnotation = (Probe.class).getAnnotation(Classes.class);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/Method/IsDefaultTest.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8005042
+ * @summary Check behavior of Method.isDefault
+ * @author Joseph D. Darcy
+ */
+
+import java.lang.reflect.*;
+import java.lang.annotation.*;
+import java.util.*;
+
+public class IsDefaultTest {
+    public static void main(String... argv) throws Exception {
+        int failures = 0;
+        int visitationCount = 0;
+
+        List<Class<?>> classList = new ArrayList<>();
+        classList.add(TestType1.class);
+        classList.add(TestType2.class);
+        classList.add(TestType3.class);
+        classList.add(TestType4.class);
+
+        for(Class<?> clazz: classList) {
+            for(Method method: clazz.getDeclaredMethods()) {
+                ExpectedIsDefault expectedIsDefault = method.getAnnotation(ExpectedIsDefault.class);
+                if (expectedIsDefault != null) {
+                    visitationCount++;
+                    boolean expected = expectedIsDefault.value();
+                    boolean actual   = method.isDefault();
+
+                    if (actual != expected) {
+                        failures++;
+                        System.err.printf("ERROR: On %s expected isDefault of ''%s''; got ''%s''.\n",
+                                          method.toString(), expected, actual);
+                    }
+                }
+            }
+        }
+
+        if (visitationCount == 0) {
+            System.err.println("Test failed because no methods checked.");
+            throw new RuntimeException();
+        }
+
+        if (failures > 0) {
+            System.err.println("Test failed.");
+            throw new RuntimeException();
+        }
+    }
+}
+
+interface TestType1 {
+    @ExpectedIsDefault(false)
+    void foo();
+
+    @ExpectedIsDefault(true)
+    default void bar() {}; // Default method
+}
+
+class TestType2 {
+    @ExpectedIsDefault(false)
+    void bar() {};
+}
+
+class TestType3 implements TestType1 {
+    @ExpectedIsDefault(false)
+    public void foo(){}
+
+    @ExpectedIsDefault(false)
+    @Override
+    public void bar() {};
+}
+
+@interface TestType4 {
+    @ExpectedIsDefault(false)
+    String value();
+
+    @ExpectedIsDefault(false)
+    String anotherValue() default "";
+}
+
+@Retention(RetentionPolicy.RUNTIME)
+@interface ExpectedIsDefault {
+    boolean value();
+}
--- a/jdk/test/java/lang/reflect/Proxy/ClassRestrictions.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/java/lang/reflect/Proxy/ClassRestrictions.java	Wed Jul 05 18:34:47 2017 +0200
@@ -22,7 +22,7 @@
  */
 
 /* @test
- * @bug 4227192
+ * @bug 4227192 8004928
  * @summary This is a test of the restrictions on the parameters that may
  * be passed to the Proxy.getProxyClass method.
  * @author Peter Jones
@@ -31,6 +31,7 @@
  * @run main ClassRestrictions
  */
 
+import java.lang.reflect.Modifier;
 import java.lang.reflect.Proxy;
 import java.net.URLClassLoader;
 
@@ -48,6 +49,8 @@
         void foo();
     }
 
+    public static final String nonPublicIntrfaceName = "java.util.zip.ZipConstants";
+
     public static void main(String[] args) {
 
         System.err.println(
@@ -65,7 +68,7 @@
             try {
                 interfaces = new Class<?>[] { Object.class };
                 proxyClass = Proxy.getProxyClass(loader, interfaces);
-                throw new RuntimeException(
+                throw new Error(
                     "proxy class created with java.lang.Object as interface");
             } catch (IllegalArgumentException e) {
                 e.printStackTrace();
@@ -75,7 +78,7 @@
             try {
                 interfaces = new Class<?>[] { Integer.TYPE };
                 proxyClass = Proxy.getProxyClass(loader, interfaces);
-                throw new RuntimeException(
+                throw new Error(
                     "proxy class created with int.class as interface");
             } catch (IllegalArgumentException e) {
                 e.printStackTrace();
@@ -90,7 +93,7 @@
             try {
                 interfaces = new Class<?>[] { Bar.class, Bar.class };
                 proxyClass = Proxy.getProxyClass(loader, interfaces);
-                throw new RuntimeException(
+                throw new Error(
                     "proxy class created with repeated interfaces");
             } catch (IllegalArgumentException e) {
                 e.printStackTrace();
@@ -109,7 +112,7 @@
             try {
                 interfaces = new Class<?>[] { altBarClass };
                 proxyClass = Proxy.getProxyClass(loader, interfaces);
-                throw new RuntimeException(
+                throw new Error(
                     "proxy class created with interface " +
                     "not visible to class loader");
             } catch (IllegalArgumentException e) {
@@ -122,34 +125,16 @@
              * All non-public interfaces must be in the same package.
              */
             Class<?> nonPublic1 = Bashful.class;
-            Class<?> nonPublic2 = null;
-            String[] nonPublicInterfaces = new String[] {
-                "java.awt.Conditional",
-                "java.util.zip.ZipConstants",
-                "javax.swing.GraphicsWrapper",
-                "javax.swing.JPopupMenu$Popup",
-                "javax.swing.JTable$Resizable2",
-                "javax.swing.JTable$Resizable3",
-                "javax.swing.ToolTipManager$Popup",
-                "sun.audio.Format",
-                "sun.audio.HaePlayable",
-                "sun.tools.agent.StepConstants",
-            };
-            for (int i = 0; i < nonPublicInterfaces.length; i++) {
-                try {
-                    nonPublic2 = Class.forName(nonPublicInterfaces[i]);
-                    break;
-                } catch (ClassNotFoundException e) {
-                }
-            }
-            if (nonPublic2 == null) {
-                throw new RuntimeException(
-                    "no second non-public interface found for test");
+            Class<?> nonPublic2 = Class.forName(nonPublicIntrfaceName);
+            if (Modifier.isPublic(nonPublic2.getModifiers())) {
+                throw new Error(
+                    "Interface " + nonPublicIntrfaceName +
+                    " is public and need to be changed!");
             }
             try {
                 interfaces = new Class<?>[] { nonPublic1, nonPublic2 };
                 proxyClass = Proxy.getProxyClass(loader, interfaces);
-                throw new RuntimeException(
+                throw new Error(
                     "proxy class created with two non-public interfaces " +
                     "in different packages");
             } catch (IllegalArgumentException e) {
@@ -165,7 +150,7 @@
             try {
                 interfaces = new Class<?>[] { Bar.class, Baz.class };
                 proxyClass = Proxy.getProxyClass(loader, interfaces);
-                throw new RuntimeException(
+                throw new Error(
                     "proxy class created with conflicting methods");
             } catch (IllegalArgumentException e) {
                 e.printStackTrace();
@@ -178,10 +163,10 @@
              */
             System.err.println("\nTEST PASSED");
 
-        } catch (Exception e) {
+        } catch (Throwable e) {
             System.err.println("\nTEST FAILED:");
             e.printStackTrace();
-            throw new RuntimeException("TEST FAILED: " + e.toString());
+            throw new Error("TEST FAILED: ", e);
         }
     }
 }
--- a/jdk/test/java/rmi/testlibrary/JavaVM.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/java/rmi/testlibrary/JavaVM.java	Wed Jul 05 18:34:47 2017 +0200
@@ -21,13 +21,10 @@
  * questions.
  */
 
-/**
- *
- */
-
-import java.io.*;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
 import java.util.Arrays;
-import java.util.Properties;
 import java.util.StringTokenizer;
 
 /**
@@ -45,10 +42,6 @@
     private OutputStream errorStream = System.err;
     private String policyFileName = null;
 
-    // This is used to shorten waiting time at startup.
-    private volatile boolean started = false;
-    private boolean forcesOutput = true; // default behavior
-
     private static void mesg(Object mesg) {
         System.err.println("JAVAVM: " + mesg.toString());
     }
@@ -82,24 +75,6 @@
         this.errorStream = err;
     }
 
-    /* This constructor will instantiate a JavaVM object for which caller
-     * can ask for forcing initial version output on child vm process
-     * (if forcesVersionOutput is true), or letting the started vm behave freely
-     * (when forcesVersionOutput is false).
-     */
-    public JavaVM(String classname,
-                  String options, String args,
-                  OutputStream out, OutputStream err,
-                  boolean forcesVersionOutput) {
-        this(classname, options, args, out, err);
-        this.forcesOutput = forcesVersionOutput;
-    }
-
-
-    public void setStarted() {
-        started = true;
-    }
-
     // Prepends passed opts array to current options
     public void addOptions(String[] opts) {
         String newOpts = "";
@@ -139,7 +114,8 @@
      */
     public void start() throws IOException {
 
-        if (vm != null) return;
+        if (vm != null)
+            throw new IllegalStateException("JavaVM already started");
 
         /*
          * If specified, add option for policy file
@@ -151,18 +127,6 @@
 
         addOptions(new String[] { getCodeCoverageOptions() });
 
-        /*
-         * If forcesOutput is true :
-         *  We force the new starting vm to output something so that we can know
-         *  when it is effectively started by redirecting standard output through
-         *  the next StreamPipe call (the vm is considered started when a first
-         *  output has been streamed out).
-         *  We do this by prepnding a "-showversion" option in the command line.
-         */
-        if (forcesOutput) {
-            addOptions(new String[] {"-showversion"});
-        }
-
         StringTokenizer optionsTokenizer = new StringTokenizer(options);
         StringTokenizer argsTokenizer = new StringTokenizer(args);
         int optionsCount = optionsTokenizer.countTokens();
@@ -186,43 +150,8 @@
         vm = Runtime.getRuntime().exec(javaCommand);
 
         /* output from the execed process may optionally be captured. */
-        StreamPipe.plugTogether(this, vm.getInputStream(), this.outputStream);
-        StreamPipe.plugTogether(this, vm.getErrorStream(), this.errorStream);
-
-        try {
-            if (forcesOutput) {
-                // Wait distant vm to start, by using waiting time slices of 100 ms.
-                // Wait at most for 2secs, after it considers the vm to be started.
-                final long vmStartSleepTime = 100;
-                final int maxTrials = 20;
-                int numTrials = 0;
-                while (!started && numTrials < maxTrials) {
-                    numTrials++;
-                    Thread.sleep(vmStartSleepTime);
-                }
-
-                // Outputs running status of distant vm
-                String message =
-                    "after " + (numTrials * vmStartSleepTime) + " milliseconds";
-                if (started) {
-                    mesg("distant vm process running, " + message);
-                }
-                else {
-                    mesg("unknown running status of distant vm process, " + message);
-                }
-            }
-            else {
-                // Since we have no way to know if the distant vm is started,
-                // we just consider the vm to be started after a 2secs waiting time.
-                Thread.sleep(2000);
-                mesg("distant vm considered to be started after a waiting time of 2 secs");
-            }
-        } catch (InterruptedException e) {
-            Thread.currentThread().interrupt();
-            mesg("Thread interrupted while checking if distant vm is started. Giving up check.");
-            mesg("Distant vm state unknown");
-            return;
-        }
+        StreamPipe.plugTogether(vm.getInputStream(), this.outputStream);
+        StreamPipe.plugTogether(vm.getErrorStream(), this.errorStream);
     }
 
     public void destroy() {
--- a/jdk/test/java/rmi/testlibrary/StreamPipe.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/java/rmi/testlibrary/StreamPipe.java	Wed Jul 05 18:34:47 2017 +0200
@@ -21,11 +21,10 @@
  * questions.
  */
 
-/**
- *
- */
-
-import java.io.*;
+import java.io.InputStream;
+import java.io.InterruptedIOException;
+import java.io.IOException;
+import java.io.OutputStream;
 
 /**
  * Pipe output of one stream into input of another.
@@ -34,84 +33,46 @@
 
     private InputStream in;
     private OutputStream out;
-    private String preamble;
-    private JavaVM javaVM;
-    private static Object lock = new Object();
+
+    private static Object countLock = new Object();
     private static int count = 0;
 
-
-    /* StreamPipe constructor : should only be called by plugTogether() method !!
-     * If passed vm is not null :
-     * -  This is StreamPipe usage when streams to pipe come from a given
-     *    vm (JavaVM) process (the vm process must be started with a prefixed
-     *    "-showversion" option to be able to determine as soon as possible when
-     *    the vm process is started through the redirection of the streams).
-     *    There must be a close connection between the StreamPipe instance and
-     *    the JavaVM object on which a start() call has been done.
-     *    run() method will flag distant JavaVM as started.
-     * If passed vm is null :
-     * -  We don't have control on the process which we want to redirect the passed
-     *    streams.
-     *    run() method will ignore distant process.
+    /**
+     * StreamPipe constructor : should only be called by plugTogether() method.
      */
-    private StreamPipe(JavaVM vm, InputStream in, OutputStream out, String name) {
+    private StreamPipe(InputStream in, OutputStream out, String name) {
         super(name);
         this.in  = in;
         this.out = out;
-        this.preamble = "# ";
-        this.javaVM = vm;
     }
 
-    // Install redirection of passed InputStream and OutputStream from passed JavaVM
-    // to this vm standard output and input streams.
-    public static void plugTogether(JavaVM vm, InputStream in, OutputStream out) {
-        String name = null;
+    /**
+     * Creates a StreamPipe thread that copies in to out and returns
+     * the created instance.
+     */
+    public static StreamPipe plugTogether(InputStream in, OutputStream out) {
+        String name;
 
-        synchronized (lock) {
-            name = "TestLibrary: StreamPipe-" + (count ++ );
+        synchronized (countLock) {
+            name = "java.rmi.testlibrary.StreamPipe-" + (count++);
         }
 
-        Thread pipe = new StreamPipe(vm, in, out, name);
+        StreamPipe pipe = new StreamPipe(in, out, name);
         pipe.setDaemon(true);
         pipe.start();
-    }
-
-    /* Redirects the InputStream and OutputStream passed by caller to this
-     * vm standard output and input streams.
-     * (we just have to use fully parametered plugTogether() call with a null
-     *  JavaVM input to do this).
-     */
-    public static void plugTogether(InputStream in, OutputStream out) {
-        plugTogether(null, in, out);
+        return pipe;
     }
 
     // Starts redirection of streams.
     public void run() {
-        BufferedReader r = new BufferedReader(new InputStreamReader(in), 1);
-        BufferedWriter w = new BufferedWriter(new OutputStreamWriter(out));
-        byte[] buf = new byte[256];
-
         try {
-            String line;
+            byte[] buf = new byte[1024];
 
-            /* This is to check that the distant vm has started,
-             * if such a vm has been provided at construction :
-             * - As soon as we can read something from r BufferedReader,
-             *   that means the distant vm is already started.
-             * Thus we signal associated JavaVM object that it is now started.
-             */
-            if (((line = r.readLine()) != null) &&
-                (javaVM != null)) {
-                javaVM.setStarted();
-            }
-
-            // Redirects r on w.
-            while (line != null) {
-                w.write(preamble);
-                w.write(line);
-                w.newLine();
-                w.flush();
-                line = r.readLine();
+            while (true) {
+                int nr = in.read(buf);
+                if (nr == -1)
+                    break;
+                out.write(buf, 0, nr);
             }
         } catch (InterruptedIOException iioe) {
             // Thread interrupted during IO operation. Terminate StreamPipe.
@@ -121,5 +82,4 @@
             e.printStackTrace();
         }
     }
-
 }
--- a/jdk/test/java/security/cert/CertPathBuilder/targetConstraints/BuildEEBasicConstraints.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/java/security/cert/CertPathBuilder/targetConstraints/BuildEEBasicConstraints.java	Wed Jul 05 18:34:47 2017 +0200
@@ -21,18 +21,22 @@
  * questions.
  */
 
+// This test case relies on updated static security property, no way to re-use
+// security property in samevm/agentvm mode.
+
 /**
  * @test
  * @bug 6714842
  * @library ../../../testlibrary
  * @build CertUtils
- * @run main BuildEEBasicConstraints
+ * @run main/othervm BuildEEBasicConstraints
  * @summary make sure a PKIX CertPathBuilder builds a path to an
  *      end entity certificate when the setBasicConstraints method of the
  *      X509CertSelector of the targetConstraints PKIXBuilderParameters
  *      parameter is set to -2.
  */
 
+import java.security.Security;
 import java.security.cert.Certificate;
 import java.security.cert.CertPath;
 import java.security.cert.CertStore;
@@ -49,6 +53,9 @@
 public final class BuildEEBasicConstraints {
 
     public static void main(String[] args) throws Exception {
+        // reset the security property to make sure that the algorithms
+        // and keys used in this test are not disabled.
+        Security.setProperty("jdk.certpath.disabledAlgorithms", "MD2");
 
         X509Certificate rootCert = CertUtils.getCertFromFile("anchor.cer");
         TrustAnchor anchor = new TrustAnchor
--- a/jdk/test/java/security/cert/pkix/policyChanges/TestPolicy.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/java/security/cert/pkix/policyChanges/TestPolicy.java	Wed Jul 05 18:34:47 2017 +0200
@@ -21,16 +21,22 @@
  * questions.
  */
 
+// This test case relies on updated static security property, no way to re-use
+// security property in samevm/agentvm mode.
+
 /**
  * @test
  * @bug 4684793
- * @summary verify that the RFC3280 policy processing changes are implemented correctly
+ * @summary verify that the RFC3280 policy processing changes are
+ *          implemented correctly
+ * @run main/othervm TestPolicy
  * @author Andreas Sterbenz
  */
 
 import java.io.*;
 import java.util.*;
 
+import java.security.Security;
 import java.security.cert.*;
 
 public class TestPolicy {
@@ -72,6 +78,10 @@
     };
 
     public static void main(String[] args) throws Exception {
+        // reset the security property to make sure that the algorithms
+        // and keys used in this test are not disabled.
+        Security.setProperty("jdk.certpath.disabledAlgorithms", "MD2");
+
         factory = CertificateFactory.getInstance("X.509");
 
         X509Certificate anchor = loadCertificate("anchor.cer");
--- a/jdk/test/java/text/Bidi/BidiConformance.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/java/text/Bidi/BidiConformance.java	Wed Jul 05 18:34:47 2017 +0200
@@ -656,7 +656,6 @@
                        baseIsLTR4Constructor1[textNo][testNo],
                        isLTR_isRTL4Constructor1[textNo][0][testNo],
                        isLTR_isRTL4Constructor1[textNo][1][testNo]);
-System.out.println(bidi.toString());
     }
 
     private void callTestEachMethod4Constructor2(int textNo,
@@ -668,7 +667,6 @@
                        baseIsLTR4Constructor2[textNo][flagNo],
                        isLTR_isRTL4Constructor2[textNo][0][flagNo],
                        isLTR_isRTL4Constructor2[textNo][1][flagNo]);
-System.out.println(bidi.toString());
     }
 
     private void callTestEachMethod4Constructor3(int textNo,
@@ -680,7 +678,6 @@
                        baseIsLTR4Constructor3[textNo][dataNo],
                        isLTR_isRTL4Constructor3[textNo][0][dataNo],
                        isLTR_isRTL4Constructor3[textNo][1][dataNo]);
-System.out.println(bidi.toString());
     }
 
     private StringBuilder sb = new StringBuilder();
@@ -934,59 +931,145 @@
         System.out.println("*** Test getRunLevel()");
 
         String str = "ABC 123";
-        int length = str.length();
         Bidi bidi = new Bidi(str, Bidi.DIRECTION_LEFT_TO_RIGHT);
-
         try {
-            if (bidi.getRunLevel(-1) != 0 ||  // runCount - 2
+            if (bidi.getRunLevel(-1) != 0 ||  // runCount - 2 (out of range)
                 bidi.getRunLevel(0) != 0 ||   // runCount - 1
-                bidi.getRunLevel(1) != 0 ||   // runCount
-                bidi.getRunLevel(2) != 0) {   // runCount + 1
-                errorHandling("getRunLevel() should return 0" +
-                    " when getRunCount() is 1.");
+                bidi.getRunLevel(1) != 0 ||   // runCount     (out of range)
+                bidi.getRunLevel(2) != 0) {   // runCount + 1 (out of range)
+                errorHandling("Incorrect getRunLevel() value(s).");
             }
         }
         catch (Exception e) {
-            errorHandling("getRunLevel() should not throw an exception " +
-                "when getRunCount() is 1.");
+            errorHandling("getRunLevel() should not throw an exception: " + e);
         }
 
         str = "ABC " + HebrewABC + " 123";
-        length = str.length();
         bidi = new Bidi(str, Bidi.DIRECTION_LEFT_TO_RIGHT);
+        try {
+            if (bidi.getRunLevel(-1) != 0 ||  // runCount - 4 (out of range)
+                bidi.getRunLevel(0) != 0 ||   // runCount - 3
+                bidi.getRunLevel(1) != 1 ||   // runCount - 2
+                bidi.getRunLevel(2) != 2 ||   // runCount - 1
+                bidi.getRunLevel(3) != 0 ||   // runCount     (out of range)
+                bidi.getRunLevel(4) != 0) {   // runCount + 1 (out of range)
+                errorHandling("Incorrect getRunLevel() value(s).");
+            }
+        }
+        catch (Exception e) {
+            errorHandling("getRunLevel() should not throw an exception: " + e);
+        }
 
+        str = "ABC";
+        bidi = new Bidi(str, Bidi.DIRECTION_LEFT_TO_RIGHT);
         try {
-            bidi.getRunLevel(-1);
-            errorHandling("getRunLevel() should throw an AIOoBE " +
-                "when run is -1(too small).");
+            if (bidi.getRunLevel(-1) != 0 ||  // runCount - 2 (out of range)
+                bidi.getRunLevel(0) != 0 ||   // runCount - 1
+                bidi.getRunLevel(1) != 0 ||   // runCount     (out of range)
+                bidi.getRunLevel(2) != 0) {   // runCount + 1 (out of range)
+                errorHandling("Incorrect getRunLevel() value(s).");
+            }
+        }
+        catch (Exception e) {
+            errorHandling("getRunLevel() should not throw an exception: " + e);
         }
-        catch (ArrayIndexOutOfBoundsException e) {
+
+        str = "ABC";
+        bidi = new Bidi(str, Bidi.DIRECTION_RIGHT_TO_LEFT);
+        try {
+            if (bidi.getRunLevel(-1) != 1 ||  // runCount - 2 (out of range)
+                bidi.getRunLevel(0) != 2 ||   // runCount - 1
+                bidi.getRunLevel(1) != 1 ||   // runCount     (out of range)
+                bidi.getRunLevel(2) != 1) {   // runCount + 1 (out of range)
+                errorHandling("Incorrect getRunLevel() value(s).");
+            }
+        }
+        catch (Exception e) {
+            errorHandling("getRunLevel() should not throw an exception: " + e);
         }
-        catch (IllegalArgumentException e) {
-            errorHandling("getRunLevel() should not throw an IAE " +
-                "but an AIOoBE when run is -1(too small).");
+
+        str = "ABC";
+        bidi = new Bidi(str, Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT);
+        try {
+            if (bidi.getRunLevel(-1) != 0 ||  // runCount - 2 (out of range)
+                bidi.getRunLevel(0) != 0 ||   // runCount - 1
+                bidi.getRunLevel(1) != 0 ||   // runCount     (out of range)
+                bidi.getRunLevel(2) != 0) {   // runCount + 1 (out of range)
+                errorHandling("Incorrect getRunLevel() value(s).");
+            }
+        }
+        catch (Exception e) {
+            errorHandling("getRunLevel() should not throw an exception: " + e);
         }
 
+        str = "ABC";
+        bidi = new Bidi(str, Bidi.DIRECTION_DEFAULT_RIGHT_TO_LEFT);
         try {
-            bidi.getRunLevel(0);
-            bidi.getRunLevel(1);
-            bidi.getRunLevel(2);
+            if (bidi.getRunLevel(-1) != 0 ||  // runCount - 2 (out of range)
+                bidi.getRunLevel(0) != 0 ||   // runCount - 1
+                bidi.getRunLevel(1) != 0 ||   // runCount     (out of range)
+                bidi.getRunLevel(2) != 0) {   // runCount + 1 (out of range)
+                errorHandling("Incorrect getRunLevel() value(s).");
+            }
         }
         catch (Exception e) {
-            errorHandling("getRunLevel() should not throw an exception" +
-                " when run is from 0 to 2(runCount-1).");
+            errorHandling("getRunLevel() should not throw an exception: " + e);
+        }
+
+        str = HebrewABC;
+        bidi = new Bidi(str, Bidi.DIRECTION_LEFT_TO_RIGHT);
+        try {
+            if (bidi.getRunLevel(-1) != 0 ||  // runCount - 2 (out of range)
+                bidi.getRunLevel(0) != 1 ||   // runCount - 1
+                bidi.getRunLevel(1) != 0 ||   // runCount     (out of range)
+                bidi.getRunLevel(2) != 0) {   // runCount + 1 (out of range)
+                errorHandling("Incorrect getRunLevel() value(s).");
+            }
+        }
+        catch (Exception e) {
+            errorHandling("getRunLevel() should not throw an exception: " + e);
         }
 
+        str = HebrewABC;
+        bidi = new Bidi(str, Bidi.DIRECTION_RIGHT_TO_LEFT);
         try {
-            bidi.getRunLevel(3);
-            errorHandling("getRunLevel() should throw an AIOoBE" +
-                " when run is 3(same as runCount).");
+            if (bidi.getRunLevel(-1) != 1 ||  // runCount - 2 (out of range)
+                bidi.getRunLevel(0) != 1 ||   // runCount - 1
+                bidi.getRunLevel(1) != 1 ||   // runCount     (out of range)
+                bidi.getRunLevel(2) != 1) {   // runCount + 1 (out of range)
+                errorHandling("Incorrect getRunLevel() value(s).");
+            }
+        }
+        catch (Exception e) {
+            errorHandling("getRunLevel() should not throw an exception: " + e);
         }
-        catch (ArrayIndexOutOfBoundsException e) {
+
+        str = HebrewABC;
+        bidi = new Bidi(str, Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT);
+        try {
+            if (bidi.getRunLevel(-1) != 1 ||  // runCount - 2 (out of range)
+                bidi.getRunLevel(0) != 1 ||   // runCount - 1
+                bidi.getRunLevel(1) != 1 ||   // runCount     (out of range)
+                bidi.getRunLevel(2) != 1) {   // runCount + 1 (out of range)
+                errorHandling("Incorrect getRunLevel() value(s).");
+            }
+        }
+        catch (Exception e) {
+            errorHandling("getRunLevel() should not throw an exception: " + e);
         }
-        catch (IllegalArgumentException e) {
-            errorHandling("getRunLevel() should not throw an IAE " +
-                "but an AIOoBE when run is 3(same as runCount).");
+
+        str = HebrewABC;
+        bidi = new Bidi(str, Bidi.DIRECTION_DEFAULT_RIGHT_TO_LEFT);
+        try {
+            if (bidi.getRunLevel(-1) != 1 ||  // runCount - 2 (out of range)
+                bidi.getRunLevel(0) != 1 ||   // runCount - 1
+                bidi.getRunLevel(1) != 1 ||   // runCount     (out of range)
+                bidi.getRunLevel(2) != 1) {   // runCount + 1 (out of range)
+                errorHandling("Incorrect getRunLevel() value(s).");
+            }
+        }
+        catch (Exception e) {
+            errorHandling("getRunLevel() should not throw an exception: " + e);
         }
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/text/Bidi/Bug8005277.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8005277
+ * @summary verify that Bidi.getRunLevel() returns a corect level.
+ */
+import java.text.Bidi;
+
+public class Bug8005277 {
+
+    public static void main(String[] args) {
+        boolean err = false;
+        String string = "\u05D0\u05D1\u05D2";
+        Bidi bidi = new Bidi(string, Bidi.DIRECTION_LEFT_TO_RIGHT);
+
+        int result = bidi.getRunCount();
+        if (result != 1) {
+            System.err.println("Incorrect run count: " + result);
+            err = true;
+        }
+
+        result = bidi.getRunStart(0);
+        if (result != 0) {
+            System.err.println("Incorrect run start: " + result);
+            err = true;
+        }
+
+        result = bidi.getRunLimit(0);
+        if (result != 3) {
+            System.err.println("Incorrect run limit: " + result);
+            err = true;
+        }
+
+        result = bidi.getRunLevel(0);
+        if (result != 1) {
+            System.err.println("Incorrect run level: " + result);
+            err = true;
+        }
+
+        if (err) {
+            throw new RuntimeException("Failed.");
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Arrays/ParallelSorting.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,2067 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* Adapted from test/java/util/Arrays/Sorting.java
+ *
+ * Where that test checks Arrays.sort against manual quicksort routines,
+ * this test checks parallelSort against either Arrays.sort or manual
+ * quicksort routines.
+ */
+
+/*
+ * @test
+ * @bug 8003981
+ * @run main ParallelSorting -shortrun
+ * @summary Exercise Arrays.parallelSort (adapted from test Sorting)
+ *
+ * @author Vladimir Yaroslavskiy
+ * @author Jon Bentley
+ * @author Josh Bloch
+ */
+
+import java.util.Arrays;
+import java.util.Random;
+import java.io.PrintStream;
+import java.util.Comparator;
+
+public class ParallelSorting {
+    private static final PrintStream out = System.out;
+    private static final PrintStream err = System.err;
+
+    // Array lengths used in a long run (default)
+    private static final int[] LONG_RUN_LENGTHS = {
+        1, 2, 3, 5, 8, 13, 21, 34, 55, 100, 1000, 10000, 100000, 1000000 };
+
+    // Array lengths used in a short run
+    private static final int[] SHORT_RUN_LENGTHS = {
+        1, 2, 3, 21, 55, 1000, 10000 };
+
+    // Random initial values used in a long run (default)
+    private static final long[] LONG_RUN_RANDOMS = { 666, 0xC0FFEE, 999 };
+
+    // Random initial values used in a short run
+    private static final long[] SHORT_RUN_RANDOMS = { 666 };
+
+    public static void main(String[] args) {
+        boolean shortRun = args.length > 0 && args[0].equals("-shortrun");
+        long start = System.currentTimeMillis();
+
+        if (shortRun) {
+            testAndCheck(SHORT_RUN_LENGTHS, SHORT_RUN_RANDOMS);
+        } else {
+            testAndCheck(LONG_RUN_LENGTHS, LONG_RUN_RANDOMS);
+        }
+        long end = System.currentTimeMillis();
+
+        out.format("PASSED in %d sec.\n", Math.round((end - start) / 1E3));
+    }
+
+    private static void testAndCheck(int[] lengths, long[] randoms) {
+        testEmptyAndNullIntArray();
+        testEmptyAndNullLongArray();
+        testEmptyAndNullShortArray();
+        testEmptyAndNullCharArray();
+        testEmptyAndNullByteArray();
+        testEmptyAndNullFloatArray();
+        testEmptyAndNullDoubleArray();
+
+        for (int length : lengths) {
+            testMergeSort(length);
+            testAndCheckRange(length);
+            testAndCheckSubArray(length);
+        }
+        for (long seed : randoms) {
+            for (int length : lengths) {
+                testAndCheckWithInsertionSort(length, new MyRandom(seed));
+                testAndCheckWithCheckSum(length, new MyRandom(seed));
+                testAndCheckWithScrambling(length, new MyRandom(seed));
+                testAndCheckFloat(length, new MyRandom(seed));
+                testAndCheckDouble(length, new MyRandom(seed));
+                testStable(length, new MyRandom(seed));
+            }
+        }
+    }
+
+    private static void testEmptyAndNullIntArray() {
+        ourDescription = "Check empty and null array";
+        Arrays.parallelSort(new int[]{});
+        Arrays.parallelSort(new int[]{}, 0, 0);
+
+        try {
+            Arrays.parallelSort((int[]) null);
+        } catch (NullPointerException expected) {
+            try {
+                Arrays.parallelSort((int[]) null, 0, 0);
+            } catch (NullPointerException expected2) {
+                return;
+            }
+            failed("Arrays.parallelSort(int[],fromIndex,toIndex) shouldn't " +
+                "catch null array");
+        }
+        failed("Arrays.parallelSort(int[]) shouldn't catch null array");
+    }
+
+    private static void testEmptyAndNullLongArray() {
+        ourDescription = "Check empty and null array";
+        Arrays.parallelSort(new long[]{});
+        Arrays.parallelSort(new long[]{}, 0, 0);
+
+        try {
+            Arrays.parallelSort((long[]) null);
+        } catch (NullPointerException expected) {
+            try {
+                Arrays.parallelSort((long[]) null, 0, 0);
+            } catch (NullPointerException expected2) {
+                return;
+            }
+            failed("Arrays.parallelSort(long[],fromIndex,toIndex) shouldn't " +
+                "catch null array");
+        }
+        failed("Arrays.parallelSort(long[]) shouldn't catch null array");
+    }
+
+    private static void testEmptyAndNullShortArray() {
+        ourDescription = "Check empty and null array";
+        Arrays.parallelSort(new short[]{});
+        Arrays.parallelSort(new short[]{}, 0, 0);
+
+        try {
+            Arrays.parallelSort((short[]) null);
+        } catch (NullPointerException expected) {
+            try {
+                Arrays.parallelSort((short[]) null, 0, 0);
+            } catch (NullPointerException expected2) {
+                return;
+            }
+            failed("Arrays.parallelSort(short[],fromIndex,toIndex) shouldn't " +
+                "catch null array");
+        }
+        failed("Arrays.parallelSort(short[]) shouldn't catch null array");
+    }
+
+    private static void testEmptyAndNullCharArray() {
+        ourDescription = "Check empty and null array";
+        Arrays.parallelSort(new char[]{});
+        Arrays.parallelSort(new char[]{}, 0, 0);
+
+        try {
+            Arrays.parallelSort((char[]) null);
+        } catch (NullPointerException expected) {
+            try {
+                Arrays.parallelSort((char[]) null, 0, 0);
+            } catch (NullPointerException expected2) {
+                return;
+            }
+            failed("Arrays.parallelSort(char[],fromIndex,toIndex) shouldn't " +
+                "catch null array");
+        }
+        failed("Arrays.parallelSort(char[]) shouldn't catch null array");
+    }
+
+    private static void testEmptyAndNullByteArray() {
+        ourDescription = "Check empty and null array";
+        Arrays.parallelSort(new byte[]{});
+        Arrays.parallelSort(new byte[]{}, 0, 0);
+
+        try {
+            Arrays.parallelSort((byte[]) null);
+        } catch (NullPointerException expected) {
+            try {
+                Arrays.parallelSort((byte[]) null, 0, 0);
+            } catch (NullPointerException expected2) {
+                return;
+            }
+            failed("Arrays.parallelSort(byte[],fromIndex,toIndex) shouldn't " +
+                "catch null array");
+        }
+        failed("Arrays.parallelSort(byte[]) shouldn't catch null array");
+    }
+
+    private static void testEmptyAndNullFloatArray() {
+        ourDescription = "Check empty and null array";
+        Arrays.parallelSort(new float[]{});
+        Arrays.parallelSort(new float[]{}, 0, 0);
+
+        try {
+            Arrays.parallelSort((float[]) null);
+        } catch (NullPointerException expected) {
+            try {
+                Arrays.parallelSort((float[]) null, 0, 0);
+            } catch (NullPointerException expected2) {
+                return;
+            }
+            failed("Arrays.parallelSort(float[],fromIndex,toIndex) shouldn't " +
+                "catch null array");
+        }
+        failed("Arrays.parallelSort(float[]) shouldn't catch null array");
+    }
+
+    private static void testEmptyAndNullDoubleArray() {
+        ourDescription = "Check empty and null array";
+        Arrays.parallelSort(new double[]{});
+        Arrays.parallelSort(new double[]{}, 0, 0);
+
+        try {
+            Arrays.parallelSort((double[]) null);
+        } catch (NullPointerException expected) {
+            try {
+                Arrays.parallelSort((double[]) null, 0, 0);
+            } catch (NullPointerException expected2) {
+                return;
+            }
+            failed("Arrays.parallelSort(double[],fromIndex,toIndex) shouldn't " +
+                "catch null array");
+        }
+        failed("Arrays.parallelSort(double[]) shouldn't catch null array");
+    }
+
+    private static void testAndCheckSubArray(int length) {
+        ourDescription = "Check sorting of subarray";
+        int[] golden = new int[length];
+        boolean newLine = false;
+
+        for (int m = 1; m < length / 2; m *= 2) {
+            newLine = true;
+            int fromIndex = m;
+            int toIndex = length - m;
+
+            prepareSubArray(golden, fromIndex, toIndex, m);
+            int[] test = golden.clone();
+
+            for (TypeConverter converter : TypeConverter.values()) {
+                out.println("Test 'subarray': " + converter +
+                   " length = " + length + ", m = " + m);
+                Object convertedGolden = converter.convert(golden);
+                Object convertedTest = converter.convert(test);
+                sortSubArray(convertedTest, fromIndex, toIndex);
+                checkSubArray(convertedTest, fromIndex, toIndex, m);
+            }
+        }
+        if (newLine) {
+            out.println();
+        }
+    }
+
+    private static void testAndCheckRange(int length) {
+        ourDescription = "Check range check";
+        int[] golden = new int[length];
+
+        for (int m = 1; m < 2 * length; m *= 2) {
+            for (int i = 1; i <= length; i++) {
+                golden[i - 1] = i % m + m % i;
+            }
+            for (TypeConverter converter : TypeConverter.values()) {
+                out.println("Test 'range': " + converter +
+                   ", length = " + length + ", m = " + m);
+                Object convertedGolden = converter.convert(golden);
+                checkRange(convertedGolden, m);
+            }
+        }
+        out.println();
+    }
+
+    private static void testStable(int length, MyRandom random) {
+        ourDescription = "Check if sorting is stable";
+        Pair[] a = build(length, random);
+
+        out.println("Test 'stable': " + "random = " + random.getSeed() +
+            ", length = " + length);
+        Arrays.parallelSort(a);
+        checkSorted(a);
+        checkStable(a);
+        out.println();
+
+        a = build(length, random);
+
+        out.println("Test 'stable' comparator: " + "random = " + random.getSeed() +
+            ", length = " + length);
+        Arrays.parallelSort(a, pairCmp);
+        checkSorted(a);
+        checkStable(a);
+        out.println();
+
+    }
+
+    private static void checkSorted(Pair[] a) {
+        for (int i = 0; i < a.length - 1; i++) {
+            if (a[i].getKey() > a[i + 1].getKey()) {
+                failedSort(i, "" + a[i].getKey(), "" + a[i + 1].getKey());
+            }
+        }
+    }
+
+    private static void checkStable(Pair[] a) {
+        for (int i = 0; i < a.length / 4; ) {
+            int key1 = a[i].getKey();
+            int value1 = a[i++].getValue();
+            int key2 = a[i].getKey();
+            int value2 = a[i++].getValue();
+            int key3 = a[i].getKey();
+            int value3 = a[i++].getValue();
+            int key4 = a[i].getKey();
+            int value4 = a[i++].getValue();
+
+            if (!(key1 == key2 && key2 == key3 && key3 == key4)) {
+                failed("On position " + i + " keys are different " +
+                    key1 + ", " + key2 + ", " + key3 + ", " + key4);
+            }
+            if (!(value1 < value2 && value2 < value3 && value3 < value4)) {
+                failed("Sorting is not stable at position " + i +
+                    ". Second values have been changed: " +  value1 + ", " +
+                    value2 + ", " + value3 + ", " + value4);
+            }
+        }
+    }
+
+    private static Pair[] build(int length, Random random) {
+        Pair[] a = new Pair[length * 4];
+
+        for (int i = 0; i < a.length; ) {
+            int key = random.nextInt();
+            a[i++] = new Pair(key, 1);
+            a[i++] = new Pair(key, 2);
+            a[i++] = new Pair(key, 3);
+            a[i++] = new Pair(key, 4);
+        }
+        return a;
+    }
+
+    private static Comparator<Pair> pairCmp = new Comparator<Pair>() {
+        public int compare(Pair p1, Pair p2) {
+            return p1.compareTo(p2);
+        }
+    };
+
+    private static final class Pair implements Comparable<Pair> {
+        Pair(int key, int value) {
+            myKey = key;
+            myValue = value;
+        }
+
+        int getKey() {
+            return myKey;
+        }
+
+        int getValue() {
+            return myValue;
+        }
+
+        public int compareTo(Pair pair) {
+            if (myKey < pair.myKey) {
+                return -1;
+            }
+            if (myKey > pair.myKey) {
+                return 1;
+            }
+            return 0;
+        }
+
+        @Override
+        public String toString() {
+            return "(" + myKey + ", " + myValue + ")";
+        }
+
+        private int myKey;
+        private int myValue;
+    }
+
+
+    private static void testAndCheckWithInsertionSort(int length, MyRandom random) {
+        if (length > 1000) {
+            return;
+        }
+        ourDescription = "Check sorting with insertion sort";
+        int[] golden = new int[length];
+
+        for (int m = 1; m < 2 * length; m *= 2) {
+            for (UnsortedBuilder builder : UnsortedBuilder.values()) {
+                builder.build(golden, m, random);
+                int[] test = golden.clone();
+
+                for (TypeConverter converter : TypeConverter.values()) {
+                    out.println("Test 'insertion sort': " + converter +
+                        " " + builder + "random = " + random.getSeed() +
+                        ", length = " + length + ", m = " + m);
+                    Object convertedGolden = converter.convert(golden);
+                    Object convertedTest1 = converter.convert(test);
+                    Object convertedTest2 = converter.convert(test);
+                    sort(convertedTest1);
+                    sortByInsertionSort(convertedTest2);
+                    compare(convertedTest1, convertedTest2);
+                }
+            }
+        }
+        out.println();
+    }
+
+    private static void testMergeSort(int length) {
+        if (length < 1000) {
+            return;
+        }
+        ourDescription = "Check merge sorting";
+        int[] golden = new int[length];
+        int period = 67; // java.util.DualPivotQuicksort.MAX_RUN_COUNT
+
+        for (int m = period - 2; m <= period + 2; m++) {
+            for (MergeBuilder builder : MergeBuilder.values()) {
+                builder.build(golden, m);
+                int[] test = golden.clone();
+
+                for (TypeConverter converter : TypeConverter.values()) {
+                    out.println("Test 'merge sort': " + converter + " " +
+                        builder + "length = " + length + ", m = " + m);
+                    Object convertedGolden = converter.convert(golden);
+                    sort(convertedGolden);
+                    checkSorted(convertedGolden);
+                }
+            }
+        }
+        out.println();
+    }
+
+    private static void testAndCheckWithCheckSum(int length, MyRandom random) {
+        ourDescription = "Check sorting with check sum";
+        int[] golden = new int[length];
+
+        for (int m = 1; m < 2 * length; m *= 2) {
+            for (UnsortedBuilder builder : UnsortedBuilder.values()) {
+                builder.build(golden, m, random);
+                int[] test = golden.clone();
+
+                for (TypeConverter converter : TypeConverter.values()) {
+                    out.println("Test 'check sum': " + converter +
+                        " " + builder + "random = " + random.getSeed() +
+                        ", length = " + length + ", m = " + m);
+                    Object convertedGolden = converter.convert(golden);
+                    Object convertedTest = converter.convert(test);
+                    sort(convertedTest);
+                    checkWithCheckSum(convertedTest, convertedGolden);
+                }
+            }
+        }
+        out.println();
+    }
+
+    private static void testAndCheckWithScrambling(int length, MyRandom random) {
+        ourDescription = "Check sorting with scrambling";
+        int[] golden = new int[length];
+
+        for (int m = 1; m <= 7; m++) {
+            if (m > length) {
+                break;
+            }
+            for (SortedBuilder builder : SortedBuilder.values()) {
+                builder.build(golden, m);
+                int[] test = golden.clone();
+                scramble(test, random);
+
+                for (TypeConverter converter : TypeConverter.values()) {
+                    out.println("Test 'scrambling': " + converter +
+                       " " + builder + "random = " + random.getSeed() +
+                       ", length = " + length + ", m = " + m);
+                    Object convertedGolden = converter.convert(golden);
+                    Object convertedTest = converter.convert(test);
+                    sort(convertedTest);
+                    compare(convertedTest, convertedGolden);
+                }
+            }
+        }
+        out.println();
+    }
+
+    private static void testAndCheckFloat(int length, MyRandom random) {
+        ourDescription = "Check float sorting";
+        float[] golden = new float[length];
+        final int MAX = 10;
+        boolean newLine = false;
+
+        for (int a = 0; a <= MAX; a++) {
+            for (int g = 0; g <= MAX; g++) {
+                for (int z = 0; z <= MAX; z++) {
+                    for (int n = 0; n <= MAX; n++) {
+                        for (int p = 0; p <= MAX; p++) {
+                            if (a + g + z + n + p > length) {
+                                continue;
+                            }
+                            if (a + g + z + n + p < length) {
+                                continue;
+                            }
+                            for (FloatBuilder builder : FloatBuilder.values()) {
+                                out.println("Test 'float': random = " + random.getSeed() +
+                                   ", length = " + length + ", a = " + a + ", g = " +
+                                   g + ", z = " + z + ", n = " + n + ", p = " + p);
+                                builder.build(golden, a, g, z, n, p, random);
+                                float[] test = golden.clone();
+                                scramble(test, random);
+                                sort(test);
+                                compare(test, golden, a, n, g);
+                            }
+                            newLine = true;
+                        }
+                    }
+                }
+            }
+        }
+        if (newLine) {
+            out.println();
+        }
+    }
+
+    private static void testAndCheckDouble(int length, MyRandom random) {
+        ourDescription = "Check double sorting";
+        double[] golden = new double[length];
+        final int MAX = 10;
+        boolean newLine = false;
+
+        for (int a = 0; a <= MAX; a++) {
+            for (int g = 0; g <= MAX; g++) {
+                for (int z = 0; z <= MAX; z++) {
+                    for (int n = 0; n <= MAX; n++) {
+                        for (int p = 0; p <= MAX; p++) {
+                            if (a + g + z + n + p > length) {
+                                continue;
+                            }
+                            if (a + g + z + n + p < length) {
+                                continue;
+                            }
+                            for (DoubleBuilder builder : DoubleBuilder.values()) {
+                                out.println("Test 'double': random = " + random.getSeed() +
+                                   ", length = " + length + ", a = " + a + ", g = " +
+                                   g + ", z = " + z + ", n = " + n + ", p = " + p);
+                                builder.build(golden, a, g, z, n, p, random);
+                                double[] test = golden.clone();
+                                scramble(test, random);
+                                sort(test);
+                                compare(test, golden, a, n, g);
+                            }
+                            newLine = true;
+                        }
+                    }
+                }
+            }
+        }
+        if (newLine) {
+            out.println();
+        }
+    }
+
+    private static void prepareSubArray(int[] a, int fromIndex, int toIndex, int m) {
+        for (int i = 0; i < fromIndex; i++) {
+            a[i] = 0xDEDA;
+        }
+        int middle = (fromIndex + toIndex) >>> 1;
+        int k = 0;
+
+        for (int i = fromIndex; i < middle; i++) {
+            a[i] = k++;
+        }
+        for (int i = middle; i < toIndex; i++) {
+            a[i] = k--;
+        }
+        for (int i = toIndex; i < a.length; i++) {
+            a[i] = 0xBABA;
+        }
+    }
+
+    private static void scramble(int[] a, Random random) {
+        for (int i = 0; i < a.length * 7; i++) {
+            swap(a, random.nextInt(a.length), random.nextInt(a.length));
+        }
+    }
+
+    private static void scramble(float[] a, Random random) {
+        for (int i = 0; i < a.length * 7; i++) {
+            swap(a, random.nextInt(a.length), random.nextInt(a.length));
+        }
+    }
+
+    private static void scramble(double[] a, Random random) {
+        for (int i = 0; i < a.length * 7; i++) {
+            swap(a, random.nextInt(a.length), random.nextInt(a.length));
+        }
+    }
+
+    private static void swap(int[] a, int i, int j) {
+        int t = a[i];
+        a[i] = a[j];
+        a[j] = t;
+    }
+
+    private static void swap(float[] a, int i, int j) {
+        float t = a[i];
+        a[i] = a[j];
+        a[j] = t;
+    }
+
+    private static void swap(double[] a, int i, int j) {
+        double t = a[i];
+        a[i] = a[j];
+        a[j] = t;
+    }
+
+    private static enum TypeConverter {
+        INT {
+            Object convert(int[] a) {
+                return a.clone();
+            }
+        },
+        LONG {
+            Object convert(int[] a) {
+                long[] b = new long[a.length];
+
+                for (int i = 0; i < a.length; i++) {
+                    b[i] = (long) a[i];
+                }
+                return b;
+            }
+        },
+        BYTE {
+            Object convert(int[] a) {
+                byte[] b = new byte[a.length];
+
+                for (int i = 0; i < a.length; i++) {
+                    b[i] = (byte) a[i];
+                }
+                return b;
+            }
+        },
+        SHORT {
+            Object convert(int[] a) {
+                short[] b = new short[a.length];
+
+                for (int i = 0; i < a.length; i++) {
+                    b[i] = (short) a[i];
+                }
+                return b;
+            }
+        },
+        CHAR {
+            Object convert(int[] a) {
+                char[] b = new char[a.length];
+
+                for (int i = 0; i < a.length; i++) {
+                    b[i] = (char) a[i];
+                }
+                return b;
+            }
+        },
+        FLOAT {
+            Object convert(int[] a) {
+                float[] b = new float[a.length];
+
+                for (int i = 0; i < a.length; i++) {
+                    b[i] = (float) a[i];
+                }
+                return b;
+            }
+        },
+        DOUBLE {
+            Object convert(int[] a) {
+                double[] b = new double[a.length];
+
+                for (int i = 0; i < a.length; i++) {
+                    b[i] = (double) a[i];
+                }
+                return b;
+            }
+        },
+        INTEGER {
+            Object convert(int[] a) {
+                Integer[] b = new Integer[a.length];
+
+                for (int i = 0; i < a.length; i++) {
+                    b[i] = new Integer(a[i]);
+                }
+                return b;
+            }
+        };
+
+        abstract Object convert(int[] a);
+
+        @Override public String toString() {
+            String name = name();
+
+            for (int i = name.length(); i < 9; i++) {
+                name += " ";
+            }
+            return name;
+        }
+    }
+
+    private static enum FloatBuilder {
+        SIMPLE {
+            void build(float[] x, int a, int g, int z, int n, int p, Random random) {
+                int fromIndex = 0;
+                float negativeValue = -random.nextFloat();
+                float positiveValue =  random.nextFloat();
+
+                writeValue(x, negativeValue, fromIndex, n);
+                fromIndex += n;
+
+                writeValue(x, -0.0f, fromIndex, g);
+                fromIndex += g;
+
+                writeValue(x, 0.0f, fromIndex, z);
+                fromIndex += z;
+
+                writeValue(x, positiveValue, fromIndex, p);
+                fromIndex += p;
+
+                writeValue(x, Float.NaN, fromIndex, a);
+            }
+        };
+
+        abstract void build(float[] x, int a, int g, int z, int n, int p, Random random);
+    }
+
+    private static enum DoubleBuilder {
+        SIMPLE {
+            void build(double[] x, int a, int g, int z, int n, int p, Random random) {
+                int fromIndex = 0;
+                double negativeValue = -random.nextFloat();
+                double positiveValue =  random.nextFloat();
+
+                writeValue(x, negativeValue, fromIndex, n);
+                fromIndex += n;
+
+                writeValue(x, -0.0d, fromIndex, g);
+                fromIndex += g;
+
+                writeValue(x, 0.0d, fromIndex, z);
+                fromIndex += z;
+
+                writeValue(x, positiveValue, fromIndex, p);
+                fromIndex += p;
+
+                writeValue(x, Double.NaN, fromIndex, a);
+            }
+        };
+
+        abstract void build(double[] x, int a, int g, int z, int n, int p, Random random);
+    }
+
+    private static void writeValue(float[] a, float value, int fromIndex, int count) {
+        for (int i = fromIndex; i < fromIndex + count; i++) {
+            a[i] = value;
+        }
+    }
+
+    private static void compare(float[] a, float[] b, int numNaN, int numNeg, int numNegZero) {
+        for (int i = a.length - numNaN; i < a.length; i++) {
+            if (a[i] == a[i]) {
+                failed("On position " + i + " must be NaN instead of " + a[i]);
+            }
+        }
+        final int NEGATIVE_ZERO = Float.floatToIntBits(-0.0f);
+
+        for (int i = numNeg; i < numNeg + numNegZero; i++) {
+            if (NEGATIVE_ZERO != Float.floatToIntBits(a[i])) {
+                failed("On position " + i + " must be -0.0 instead of " + a[i]);
+            }
+        }
+        for (int i = 0; i < a.length - numNaN; i++) {
+            if (a[i] != b[i]) {
+                failedCompare(i, "" + a[i], "" + b[i]);
+            }
+        }
+    }
+
+    private static void writeValue(double[] a, double value, int fromIndex, int count) {
+        for (int i = fromIndex; i < fromIndex + count; i++) {
+            a[i] = value;
+        }
+    }
+
+    private static void compare(double[] a, double[] b, int numNaN, int numNeg, int numNegZero) {
+        for (int i = a.length - numNaN; i < a.length; i++) {
+            if (a[i] == a[i]) {
+                failed("On position " + i + " must be NaN instead of " + a[i]);
+            }
+        }
+        final long NEGATIVE_ZERO = Double.doubleToLongBits(-0.0d);
+
+        for (int i = numNeg; i < numNeg + numNegZero; i++) {
+            if (NEGATIVE_ZERO != Double.doubleToLongBits(a[i])) {
+                failed("On position " + i + " must be -0.0 instead of " + a[i]);
+            }
+        }
+        for (int i = 0; i < a.length - numNaN; i++) {
+            if (a[i] != b[i]) {
+                failedCompare(i, "" + a[i], "" + b[i]);
+            }
+        }
+    }
+
+    private static enum SortedBuilder {
+        REPEATED {
+            void build(int[] a, int m) {
+                int period = a.length / m;
+                int i = 0;
+                int k = 0;
+
+                while (true) {
+                    for (int t = 1; t <= period; t++) {
+                        if (i >= a.length) {
+                            return;
+                        }
+                        a[i++] = k;
+                    }
+                    if (i >= a.length) {
+                        return;
+                    }
+                    k++;
+                }
+            }
+        },
+        ORGAN_PIPES {
+            void build(int[] a, int m) {
+                int i = 0;
+                int k = m;
+
+                while (true) {
+                    for (int t = 1; t <= m; t++) {
+                        if (i >= a.length) {
+                            return;
+                        }
+                        a[i++] = k;
+                    }
+                }
+            }
+        };
+
+        abstract void build(int[] a, int m);
+
+        @Override public String toString() {
+            String name = name();
+
+            for (int i = name.length(); i < 12; i++) {
+                name += " ";
+            }
+            return name;
+        }
+    }
+
+    private static enum MergeBuilder {
+        ASCENDING {
+            void build(int[] a, int m) {
+                int period = a.length / m;
+                int v = 1, i = 0;
+
+                for (int k = 0; k < m; k++) {
+                    v = 1;
+                    for (int p = 0; p < period; p++) {
+                        a[i++] = v++;
+                    }
+                }
+                for (int j = i; j < a.length - 1; j++) {
+                    a[j] = v++;
+                }
+                a[a.length - 1] = 0;
+            }
+        },
+        DESCENDING {
+            void build(int[] a, int m) {
+                int period = a.length / m;
+                int v = -1, i = 0;
+
+                for (int k = 0; k < m; k++) {
+                    v = -1;
+                    for (int p = 0; p < period; p++) {
+                        a[i++] = v--;
+                    }
+                }
+                for (int j = i; j < a.length - 1; j++) {
+                    a[j] = v--;
+                }
+                a[a.length - 1] = 0;
+            }
+        };
+
+        abstract void build(int[] a, int m);
+
+        @Override public String toString() {
+            String name = name();
+
+            for (int i = name.length(); i < 12; i++) {
+                name += " ";
+            }
+            return name;
+        }
+    }
+
+    private static enum UnsortedBuilder {
+        RANDOM {
+            void build(int[] a, int m, Random random) {
+                for (int i = 0; i < a.length; i++) {
+                    a[i] = random.nextInt();
+                }
+            }
+        },
+        ASCENDING {
+            void build(int[] a, int m, Random random) {
+                for (int i = 0; i < a.length; i++) {
+                    a[i] = m + i;
+                }
+            }
+        },
+        DESCENDING {
+            void build(int[] a, int m, Random random) {
+                for (int i = 0; i < a.length; i++) {
+                    a[i] = a.length - m - i;
+                }
+            }
+        },
+        ALL_EQUAL {
+            void build(int[] a, int m, Random random) {
+                for (int i = 0; i < a.length; i++) {
+                    a[i] = m;
+                }
+            }
+        },
+        SAW {
+            void build(int[] a, int m, Random random) {
+                int incCount = 1;
+                int decCount = a.length;
+                int i = 0;
+                int period = m--;
+
+                while (true) {
+                    for (int k = 1; k <= period; k++) {
+                        if (i >= a.length) {
+                            return;
+                        }
+                        a[i++] = incCount++;
+                    }
+                    period += m;
+
+                    for (int k = 1; k <= period; k++) {
+                        if (i >= a.length) {
+                            return;
+                        }
+                        a[i++] = decCount--;
+                    }
+                    period += m;
+                }
+            }
+        },
+        REPEATED {
+            void build(int[] a, int m, Random random) {
+                for (int i = 0; i < a.length; i++) {
+                    a[i] = i % m;
+                }
+            }
+        },
+        DUPLICATED {
+            void build(int[] a, int m, Random random) {
+                for (int i = 0; i < a.length; i++) {
+                    a[i] = random.nextInt(m);
+                }
+            }
+        },
+        ORGAN_PIPES {
+            void build(int[] a, int m, Random random) {
+                int middle = a.length / (m + 1);
+
+                for (int i = 0; i < middle; i++) {
+                    a[i] = i;
+                }
+                for (int i = middle; i < a.length; i++) {
+                    a[i] = a.length - i - 1;
+                }
+            }
+        },
+        STAGGER {
+            void build(int[] a, int m, Random random) {
+                for (int i = 0; i < a.length; i++) {
+                    a[i] = (i * m + i) % a.length;
+                }
+            }
+        },
+        PLATEAU {
+            void build(int[] a, int m, Random random) {
+                for (int i = 0; i < a.length; i++) {
+                    a[i] = Math.min(i, m);
+                }
+            }
+        },
+        SHUFFLE {
+            void build(int[] a, int m, Random random) {
+                int x = 0, y = 0;
+                for (int i = 0; i < a.length; i++) {
+                    a[i] = random.nextBoolean() ? (x += 2) : (y += 2);
+                }
+            }
+        };
+
+        abstract void build(int[] a, int m, Random random);
+
+        @Override public String toString() {
+            String name = name();
+
+            for (int i = name.length(); i < 12; i++) {
+                name += " ";
+            }
+            return name;
+        }
+    }
+
+    private static void checkWithCheckSum(Object test, Object golden) {
+        checkSorted(test);
+        checkCheckSum(test, golden);
+    }
+
+    private static void failed(String message) {
+        err.format("\n*** TEST FAILED - %s.\n\n%s.\n\n", ourDescription, message);
+        throw new RuntimeException("Test failed - see log file for details");
+    }
+
+    private static void failedSort(int index, String value1, String value2) {
+        failed("Array is not sorted at " + index + "-th position: " +
+            value1 + " and " + value2);
+    }
+
+    private static void failedCompare(int index, String value1, String value2) {
+        failed("On position " + index + " must be " + value2 + " instead of " + value1);
+    }
+
+    private static void compare(Object test, Object golden) {
+        if (test instanceof int[]) {
+            compare((int[]) test, (int[]) golden);
+        } else if (test instanceof long[]) {
+            compare((long[]) test, (long[]) golden);
+        } else if (test instanceof short[]) {
+            compare((short[]) test, (short[]) golden);
+        } else if (test instanceof byte[]) {
+            compare((byte[]) test, (byte[]) golden);
+        } else if (test instanceof char[]) {
+            compare((char[]) test, (char[]) golden);
+        } else if (test instanceof float[]) {
+            compare((float[]) test, (float[]) golden);
+        } else if (test instanceof double[]) {
+            compare((double[]) test, (double[]) golden);
+        } else if (test instanceof Integer[]) {
+            compare((Integer[]) test, (Integer[]) golden);
+        } else {
+            failed("Unknow type of array: " + test + " of class " +
+                test.getClass().getName());
+        }
+    }
+
+    private static void compare(int[] a, int[] b) {
+        for (int i = 0; i < a.length; i++) {
+            if (a[i] != b[i]) {
+                failedCompare(i, "" + a[i], "" + b[i]);
+            }
+        }
+    }
+
+    private static void compare(long[] a, long[] b) {
+        for (int i = 0; i < a.length; i++) {
+            if (a[i] != b[i]) {
+                failedCompare(i, "" + a[i], "" + b[i]);
+            }
+        }
+    }
+
+    private static void compare(short[] a, short[] b) {
+        for (int i = 0; i < a.length; i++) {
+            if (a[i] != b[i]) {
+                failedCompare(i, "" + a[i], "" + b[i]);
+            }
+        }
+    }
+
+    private static void compare(byte[] a, byte[] b) {
+        for (int i = 0; i < a.length; i++) {
+            if (a[i] != b[i]) {
+                failedCompare(i, "" + a[i], "" + b[i]);
+            }
+        }
+    }
+
+    private static void compare(char[] a, char[] b) {
+        for (int i = 0; i < a.length; i++) {
+            if (a[i] != b[i]) {
+                failedCompare(i, "" + a[i], "" + b[i]);
+            }
+        }
+    }
+
+    private static void compare(float[] a, float[] b) {
+        for (int i = 0; i < a.length; i++) {
+            if (a[i] != b[i]) {
+                failedCompare(i, "" + a[i], "" + b[i]);
+            }
+        }
+    }
+
+    private static void compare(double[] a, double[] b) {
+        for (int i = 0; i < a.length; i++) {
+            if (a[i] != b[i]) {
+                failedCompare(i, "" + a[i], "" + b[i]);
+            }
+        }
+    }
+
+    private static void compare(Integer[] a, Integer[] b) {
+        for (int i = 0; i < a.length; i++) {
+            if (a[i].compareTo(b[i]) != 0) {
+                failedCompare(i, "" + a[i], "" + b[i]);
+            }
+        }
+    }
+
+    private static void checkSorted(Object object) {
+        if (object instanceof int[]) {
+            checkSorted((int[]) object);
+        } else if (object instanceof long[]) {
+            checkSorted((long[]) object);
+        } else if (object instanceof short[]) {
+            checkSorted((short[]) object);
+        } else if (object instanceof byte[]) {
+            checkSorted((byte[]) object);
+        } else if (object instanceof char[]) {
+            checkSorted((char[]) object);
+        } else if (object instanceof float[]) {
+            checkSorted((float[]) object);
+        } else if (object instanceof double[]) {
+            checkSorted((double[]) object);
+        } else if (object instanceof Integer[]) {
+            checkSorted((Integer[]) object);
+        } else {
+            failed("Unknow type of array: " + object + " of class " +
+                object.getClass().getName());
+        }
+    }
+
+    private static void checkSorted(int[] a) {
+        for (int i = 0; i < a.length - 1; i++) {
+            if (a[i] > a[i + 1]) {
+                failedSort(i, "" + a[i], "" + a[i + 1]);
+            }
+        }
+    }
+
+    private static void checkSorted(long[] a) {
+        for (int i = 0; i < a.length - 1; i++) {
+            if (a[i] > a[i + 1]) {
+                failedSort(i, "" + a[i], "" + a[i + 1]);
+            }
+        }
+    }
+
+    private static void checkSorted(short[] a) {
+        for (int i = 0; i < a.length - 1; i++) {
+            if (a[i] > a[i + 1]) {
+                failedSort(i, "" + a[i], "" + a[i + 1]);
+            }
+        }
+    }
+
+    private static void checkSorted(byte[] a) {
+        for (int i = 0; i < a.length - 1; i++) {
+            if (a[i] > a[i + 1]) {
+                failedSort(i, "" + a[i], "" + a[i + 1]);
+            }
+        }
+    }
+
+    private static void checkSorted(char[] a) {
+        for (int i = 0; i < a.length - 1; i++) {
+            if (a[i] > a[i + 1]) {
+                failedSort(i, "" + a[i], "" + a[i + 1]);
+            }
+        }
+    }
+
+    private static void checkSorted(float[] a) {
+        for (int i = 0; i < a.length - 1; i++) {
+            if (a[i] > a[i + 1]) {
+                failedSort(i, "" + a[i], "" + a[i + 1]);
+            }
+        }
+    }
+
+    private static void checkSorted(double[] a) {
+        for (int i = 0; i < a.length - 1; i++) {
+            if (a[i] > a[i + 1]) {
+                failedSort(i, "" + a[i], "" + a[i + 1]);
+            }
+        }
+    }
+
+    private static void checkSorted(Integer[] a) {
+        for (int i = 0; i < a.length - 1; i++) {
+            if (a[i].intValue() > a[i + 1].intValue()) {
+                failedSort(i, "" + a[i], "" + a[i + 1]);
+            }
+        }
+    }
+
+    private static void checkCheckSum(Object test, Object golden) {
+        if (checkSumXor(test) != checkSumXor(golden)) {
+            failed("Original and sorted arrays are not identical [xor]");
+        }
+        if (checkSumPlus(test) != checkSumPlus(golden)) {
+            failed("Original and sorted arrays are not identical [plus]");
+        }
+    }
+
+    private static int checkSumXor(Object object) {
+        if (object instanceof int[]) {
+            return checkSumXor((int[]) object);
+        } else if (object instanceof long[]) {
+            return checkSumXor((long[]) object);
+        } else if (object instanceof short[]) {
+            return checkSumXor((short[]) object);
+        } else if (object instanceof byte[]) {
+            return checkSumXor((byte[]) object);
+        } else if (object instanceof char[]) {
+            return checkSumXor((char[]) object);
+        } else if (object instanceof float[]) {
+            return checkSumXor((float[]) object);
+        } else if (object instanceof double[]) {
+            return checkSumXor((double[]) object);
+        } else if (object instanceof Integer[]) {
+            return checkSumXor((Integer[]) object);
+        } else {
+            failed("Unknow type of array: " + object + " of class " +
+                object.getClass().getName());
+            return -1;
+        }
+    }
+
+    private static int checkSumXor(Integer[] a) {
+        int checkSum = 0;
+
+        for (Integer e : a) {
+            checkSum ^= e.intValue();
+        }
+        return checkSum;
+    }
+
+    private static int checkSumXor(int[] a) {
+        int checkSum = 0;
+
+        for (int e : a) {
+            checkSum ^= e;
+        }
+        return checkSum;
+    }
+
+    private static int checkSumXor(long[] a) {
+        long checkSum = 0;
+
+        for (long e : a) {
+            checkSum ^= e;
+        }
+        return (int) checkSum;
+    }
+
+    private static int checkSumXor(short[] a) {
+        short checkSum = 0;
+
+        for (short e : a) {
+            checkSum ^= e;
+        }
+        return (int) checkSum;
+    }
+
+    private static int checkSumXor(byte[] a) {
+        byte checkSum = 0;
+
+        for (byte e : a) {
+            checkSum ^= e;
+        }
+        return (int) checkSum;
+    }
+
+    private static int checkSumXor(char[] a) {
+        char checkSum = 0;
+
+        for (char e : a) {
+            checkSum ^= e;
+        }
+        return (int) checkSum;
+    }
+
+    private static int checkSumXor(float[] a) {
+        int checkSum = 0;
+
+        for (float e : a) {
+            checkSum ^= (int) e;
+        }
+        return checkSum;
+    }
+
+    private static int checkSumXor(double[] a) {
+        int checkSum = 0;
+
+        for (double e : a) {
+            checkSum ^= (int) e;
+        }
+        return checkSum;
+    }
+
+    private static int checkSumPlus(Object object) {
+        if (object instanceof int[]) {
+            return checkSumPlus((int[]) object);
+        } else if (object instanceof long[]) {
+            return checkSumPlus((long[]) object);
+        } else if (object instanceof short[]) {
+            return checkSumPlus((short[]) object);
+        } else if (object instanceof byte[]) {
+            return checkSumPlus((byte[]) object);
+        } else if (object instanceof char[]) {
+            return checkSumPlus((char[]) object);
+        } else if (object instanceof float[]) {
+            return checkSumPlus((float[]) object);
+        } else if (object instanceof double[]) {
+            return checkSumPlus((double[]) object);
+        } else if (object instanceof Integer[]) {
+            return checkSumPlus((Integer[]) object);
+        } else {
+            failed("Unknow type of array: " + object + " of class " +
+                object.getClass().getName());
+            return -1;
+        }
+    }
+
+    private static int checkSumPlus(int[] a) {
+        int checkSum = 0;
+
+        for (int e : a) {
+            checkSum += e;
+        }
+        return checkSum;
+    }
+
+    private static int checkSumPlus(long[] a) {
+        long checkSum = 0;
+
+        for (long e : a) {
+            checkSum += e;
+        }
+        return (int) checkSum;
+    }
+
+    private static int checkSumPlus(short[] a) {
+        short checkSum = 0;
+
+        for (short e : a) {
+            checkSum += e;
+        }
+        return (int) checkSum;
+    }
+
+    private static int checkSumPlus(byte[] a) {
+        byte checkSum = 0;
+
+        for (byte e : a) {
+            checkSum += e;
+        }
+        return (int) checkSum;
+    }
+
+    private static int checkSumPlus(char[] a) {
+        char checkSum = 0;
+
+        for (char e : a) {
+            checkSum += e;
+        }
+        return (int) checkSum;
+    }
+
+    private static int checkSumPlus(float[] a) {
+        int checkSum = 0;
+
+        for (float e : a) {
+            checkSum += (int) e;
+        }
+        return checkSum;
+    }
+
+    private static int checkSumPlus(double[] a) {
+        int checkSum = 0;
+
+        for (double e : a) {
+            checkSum += (int) e;
+        }
+        return checkSum;
+    }
+
+    private static int checkSumPlus(Integer[] a) {
+        int checkSum = 0;
+
+        for (Integer e : a) {
+            checkSum += e.intValue();
+        }
+        return checkSum;
+    }
+
+    private static void sortByInsertionSort(Object object) {
+        if (object instanceof int[]) {
+            sortByInsertionSort((int[]) object);
+        } else if (object instanceof long[]) {
+            sortByInsertionSort((long[]) object);
+        } else if (object instanceof short[]) {
+            sortByInsertionSort((short[]) object);
+        } else if (object instanceof byte[]) {
+            sortByInsertionSort((byte[]) object);
+        } else if (object instanceof char[]) {
+            sortByInsertionSort((char[]) object);
+        } else if (object instanceof float[]) {
+            sortByInsertionSort((float[]) object);
+        } else if (object instanceof double[]) {
+            sortByInsertionSort((double[]) object);
+        } else if (object instanceof Integer[]) {
+            sortByInsertionSort((Integer[]) object);
+        } else {
+            failed("Unknow type of array: " + object + " of class " +
+                object.getClass().getName());
+        }
+    }
+
+    private static void sortByInsertionSort(int[] a) {
+        for (int j, i = 1; i < a.length; i++) {
+            int ai = a[i];
+            for (j = i - 1; j >= 0 && ai < a[j]; j--) {
+                a[j + 1] = a[j];
+            }
+            a[j + 1] = ai;
+        }
+    }
+
+    private static void sortByInsertionSort(long[] a) {
+        for (int j, i = 1; i < a.length; i++) {
+            long ai = a[i];
+            for (j = i - 1; j >= 0 && ai < a[j]; j--) {
+                a[j + 1] = a[j];
+            }
+            a[j + 1] = ai;
+        }
+    }
+
+    private static void sortByInsertionSort(short[] a) {
+        for (int j, i = 1; i < a.length; i++) {
+            short ai = a[i];
+            for (j = i - 1; j >= 0 && ai < a[j]; j--) {
+                a[j + 1] = a[j];
+            }
+            a[j + 1] = ai;
+        }
+    }
+
+    private static void sortByInsertionSort(byte[] a) {
+        for (int j, i = 1; i < a.length; i++) {
+            byte ai = a[i];
+            for (j = i - 1; j >= 0 && ai < a[j]; j--) {
+                a[j + 1] = a[j];
+            }
+            a[j + 1] = ai;
+        }
+    }
+
+    private static void sortByInsertionSort(char[] a) {
+        for (int j, i = 1; i < a.length; i++) {
+            char ai = a[i];
+            for (j = i - 1; j >= 0 && ai < a[j]; j--) {
+                a[j + 1] = a[j];
+            }
+            a[j + 1] = ai;
+        }
+    }
+
+    private static void sortByInsertionSort(float[] a) {
+        for (int j, i = 1; i < a.length; i++) {
+            float ai = a[i];
+            for (j = i - 1; j >= 0 && ai < a[j]; j--) {
+                a[j + 1] = a[j];
+            }
+            a[j + 1] = ai;
+        }
+    }
+
+    private static void sortByInsertionSort(double[] a) {
+        for (int j, i = 1; i < a.length; i++) {
+            double ai = a[i];
+            for (j = i - 1; j >= 0 && ai < a[j]; j--) {
+                a[j + 1] = a[j];
+            }
+            a[j + 1] = ai;
+        }
+    }
+
+    private static void sortByInsertionSort(Integer[] a) {
+        for (int j, i = 1; i < a.length; i++) {
+            Integer ai = a[i];
+            for (j = i - 1; j >= 0 && ai < a[j]; j--) {
+                a[j + 1] = a[j];
+            }
+            a[j + 1] = ai;
+        }
+    }
+
+    private static void sort(Object object) {
+        if (object instanceof int[]) {
+            Arrays.parallelSort((int[]) object);
+        } else if (object instanceof long[]) {
+            Arrays.parallelSort((long[]) object);
+        } else if (object instanceof short[]) {
+            Arrays.parallelSort((short[]) object);
+        } else if (object instanceof byte[]) {
+            Arrays.parallelSort((byte[]) object);
+        } else if (object instanceof char[]) {
+            Arrays.parallelSort((char[]) object);
+        } else if (object instanceof float[]) {
+            Arrays.parallelSort((float[]) object);
+        } else if (object instanceof double[]) {
+            Arrays.parallelSort((double[]) object);
+        } else if (object instanceof Integer[]) {
+            Arrays.parallelSort((Integer[]) object);
+        } else {
+            failed("Unknow type of array: " + object + " of class " +
+                object.getClass().getName());
+        }
+    }
+
+    private static void sortSubArray(Object object, int fromIndex, int toIndex) {
+        if (object instanceof int[]) {
+            Arrays.parallelSort((int[]) object, fromIndex, toIndex);
+        } else if (object instanceof long[]) {
+            Arrays.parallelSort((long[]) object, fromIndex, toIndex);
+        } else if (object instanceof short[]) {
+            Arrays.parallelSort((short[]) object, fromIndex, toIndex);
+        } else if (object instanceof byte[]) {
+            Arrays.parallelSort((byte[]) object, fromIndex, toIndex);
+        } else if (object instanceof char[]) {
+            Arrays.parallelSort((char[]) object, fromIndex, toIndex);
+        } else if (object instanceof float[]) {
+            Arrays.parallelSort((float[]) object, fromIndex, toIndex);
+        } else if (object instanceof double[]) {
+            Arrays.parallelSort((double[]) object, fromIndex, toIndex);
+        } else if (object instanceof Integer[]) {
+            Arrays.parallelSort((Integer[]) object, fromIndex, toIndex);
+        } else {
+            failed("Unknow type of array: " + object + " of class " +
+                object.getClass().getName());
+        }
+    }
+
+    private static void checkSubArray(Object object, int fromIndex, int toIndex, int m) {
+        if (object instanceof int[]) {
+            checkSubArray((int[]) object, fromIndex, toIndex, m);
+        } else if (object instanceof long[]) {
+            checkSubArray((long[]) object, fromIndex, toIndex, m);
+        } else if (object instanceof short[]) {
+            checkSubArray((short[]) object, fromIndex, toIndex, m);
+        } else if (object instanceof byte[]) {
+            checkSubArray((byte[]) object, fromIndex, toIndex, m);
+        } else if (object instanceof char[]) {
+            checkSubArray((char[]) object, fromIndex, toIndex, m);
+        } else if (object instanceof float[]) {
+            checkSubArray((float[]) object, fromIndex, toIndex, m);
+        } else if (object instanceof double[]) {
+            checkSubArray((double[]) object, fromIndex, toIndex, m);
+        } else if (object instanceof Integer[]) {
+            checkSubArray((Integer[]) object, fromIndex, toIndex, m);
+        } else {
+            failed("Unknow type of array: " + object + " of class " +
+                object.getClass().getName());
+        }
+    }
+
+    private static void checkSubArray(Integer[] a, int fromIndex, int toIndex, int m) {
+        for (int i = 0; i < fromIndex; i++) {
+            if (a[i].intValue() != 0xDEDA) {
+                failed("Range sort changes left element on position " + i +
+                    ": " + a[i] + ", must be " + 0xDEDA);
+            }
+        }
+
+        for (int i = fromIndex; i < toIndex - 1; i++) {
+            if (a[i].intValue() > a[i + 1].intValue()) {
+                failedSort(i, "" + a[i], "" + a[i + 1]);
+            }
+        }
+
+        for (int i = toIndex; i < a.length; i++) {
+            if (a[i].intValue() != 0xBABA) {
+                failed("Range sort changes right element on position " + i +
+                    ": " + a[i] + ", must be " + 0xBABA);
+            }
+        }
+    }
+
+    private static void checkSubArray(int[] a, int fromIndex, int toIndex, int m) {
+        for (int i = 0; i < fromIndex; i++) {
+            if (a[i] != 0xDEDA) {
+                failed("Range sort changes left element on position " + i +
+                    ": " + a[i] + ", must be " + 0xDEDA);
+            }
+        }
+
+        for (int i = fromIndex; i < toIndex - 1; i++) {
+            if (a[i] > a[i + 1]) {
+                failedSort(i, "" + a[i], "" + a[i + 1]);
+            }
+        }
+
+        for (int i = toIndex; i < a.length; i++) {
+            if (a[i] != 0xBABA) {
+                failed("Range sort changes right element on position " + i +
+                    ": " + a[i] + ", must be " + 0xBABA);
+            }
+        }
+    }
+
+    private static void checkSubArray(byte[] a, int fromIndex, int toIndex, int m) {
+        for (int i = 0; i < fromIndex; i++) {
+            if (a[i] != (byte) 0xDEDA) {
+                failed("Range sort changes left element on position " + i +
+                    ": " + a[i] + ", must be " + 0xDEDA);
+            }
+        }
+
+        for (int i = fromIndex; i < toIndex - 1; i++) {
+            if (a[i] > a[i + 1]) {
+                failedSort(i, "" + a[i], "" + a[i + 1]);
+            }
+        }
+
+        for (int i = toIndex; i < a.length; i++) {
+            if (a[i] != (byte) 0xBABA) {
+                failed("Range sort changes right element on position " + i +
+                    ": " + a[i] + ", must be " + 0xBABA);
+            }
+        }
+    }
+
+    private static void checkSubArray(long[] a, int fromIndex, int toIndex, int m) {
+        for (int i = 0; i < fromIndex; i++) {
+            if (a[i] != (long) 0xDEDA) {
+                failed("Range sort changes left element on position " + i +
+                    ": " + a[i] + ", must be " + 0xDEDA);
+            }
+        }
+
+        for (int i = fromIndex; i < toIndex - 1; i++) {
+            if (a[i] > a[i + 1]) {
+                failedSort(i, "" + a[i], "" + a[i + 1]);
+            }
+        }
+
+        for (int i = toIndex; i < a.length; i++) {
+            if (a[i] != (long) 0xBABA) {
+                failed("Range sort changes right element on position " + i +
+                    ": " + a[i] + ", must be " + 0xBABA);
+            }
+        }
+    }
+
+    private static void checkSubArray(char[] a, int fromIndex, int toIndex, int m) {
+        for (int i = 0; i < fromIndex; i++) {
+            if (a[i] != (char) 0xDEDA) {
+                failed("Range sort changes left element on position " + i +
+                    ": " + a[i] + ", must be " + 0xDEDA);
+            }
+        }
+
+        for (int i = fromIndex; i < toIndex - 1; i++) {
+            if (a[i] > a[i + 1]) {
+                failedSort(i, "" + a[i], "" + a[i + 1]);
+            }
+        }
+
+        for (int i = toIndex; i < a.length; i++) {
+            if (a[i] != (char) 0xBABA) {
+                failed("Range sort changes right element on position " + i +
+                    ": " + a[i] + ", must be " + 0xBABA);
+            }
+        }
+    }
+
+    private static void checkSubArray(short[] a, int fromIndex, int toIndex, int m) {
+        for (int i = 0; i < fromIndex; i++) {
+            if (a[i] != (short) 0xDEDA) {
+                failed("Range sort changes left element on position " + i +
+                    ": " + a[i] + ", must be " + 0xDEDA);
+            }
+        }
+
+        for (int i = fromIndex; i < toIndex - 1; i++) {
+            if (a[i] > a[i + 1]) {
+                failedSort(i, "" + a[i], "" + a[i + 1]);
+            }
+        }
+
+        for (int i = toIndex; i < a.length; i++) {
+            if (a[i] != (short) 0xBABA) {
+                failed("Range sort changes right element on position " + i +
+                    ": " + a[i] + ", must be " + 0xBABA);
+            }
+        }
+    }
+
+    private static void checkSubArray(float[] a, int fromIndex, int toIndex, int m) {
+        for (int i = 0; i < fromIndex; i++) {
+            if (a[i] != (float) 0xDEDA) {
+                failed("Range sort changes left element on position " + i +
+                    ": " + a[i] + ", must be " + 0xDEDA);
+            }
+        }
+
+        for (int i = fromIndex; i < toIndex - 1; i++) {
+            if (a[i] > a[i + 1]) {
+                failedSort(i, "" + a[i], "" + a[i + 1]);
+            }
+        }
+
+        for (int i = toIndex; i < a.length; i++) {
+            if (a[i] != (float) 0xBABA) {
+                failed("Range sort changes right element on position " + i +
+                    ": " + a[i] + ", must be " + 0xBABA);
+            }
+        }
+    }
+
+    private static void checkSubArray(double[] a, int fromIndex, int toIndex, int m) {
+        for (int i = 0; i < fromIndex; i++) {
+            if (a[i] != (double) 0xDEDA) {
+                failed("Range sort changes left element on position " + i +
+                    ": " + a[i] + ", must be " + 0xDEDA);
+            }
+        }
+
+        for (int i = fromIndex; i < toIndex - 1; i++) {
+            if (a[i] > a[i + 1]) {
+                failedSort(i, "" + a[i], "" + a[i + 1]);
+            }
+        }
+
+        for (int i = toIndex; i < a.length; i++) {
+            if (a[i] != (double) 0xBABA) {
+                failed("Range sort changes right element on position " + i +
+                    ": " + a[i] + ", must be " + 0xBABA);
+            }
+        }
+    }
+
+    private static void checkRange(Object object, int m) {
+        if (object instanceof int[]) {
+            checkRange((int[]) object, m);
+        } else if (object instanceof long[]) {
+            checkRange((long[]) object, m);
+        } else if (object instanceof short[]) {
+            checkRange((short[]) object, m);
+        } else if (object instanceof byte[]) {
+            checkRange((byte[]) object, m);
+        } else if (object instanceof char[]) {
+            checkRange((char[]) object, m);
+        } else if (object instanceof float[]) {
+            checkRange((float[]) object, m);
+        } else if (object instanceof double[]) {
+            checkRange((double[]) object, m);
+        } else if (object instanceof Integer[]) {
+            checkRange((Integer[]) object, m);
+        } else {
+            failed("Unknow type of array: " + object + " of class " +
+                object.getClass().getName());
+        }
+    }
+
+    private static void checkRange(Integer[] a, int m) {
+        try {
+            Arrays.parallelSort(a, m + 1, m);
+
+            failed("ParallelSort does not throw IllegalArgumentException " +
+                " as expected: fromIndex = " + (m + 1) +
+                " toIndex = " + m);
+        }
+        catch (IllegalArgumentException iae) {
+            try {
+                Arrays.parallelSort(a, -m, a.length);
+
+                failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+                    " as expected: fromIndex = " + (-m));
+            }
+            catch (ArrayIndexOutOfBoundsException aoe) {
+                try {
+                    Arrays.parallelSort(a, 0, a.length + m);
+
+                    failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+                        " as expected: toIndex = " + (a.length + m));
+                }
+                catch (ArrayIndexOutOfBoundsException aie) {
+                    return;
+                }
+            }
+        }
+    }
+
+    private static void checkRange(int[] a, int m) {
+        try {
+            Arrays.parallelSort(a, m + 1, m);
+
+            failed("ParallelSort does not throw IllegalArgumentException " +
+                " as expected: fromIndex = " + (m + 1) +
+                " toIndex = " + m);
+        }
+        catch (IllegalArgumentException iae) {
+            try {
+                Arrays.parallelSort(a, -m, a.length);
+
+                failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+                    " as expected: fromIndex = " + (-m));
+            }
+            catch (ArrayIndexOutOfBoundsException aoe) {
+                try {
+                    Arrays.parallelSort(a, 0, a.length + m);
+
+                    failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+                        " as expected: toIndex = " + (a.length + m));
+                }
+                catch (ArrayIndexOutOfBoundsException aie) {
+                    return;
+                }
+            }
+        }
+    }
+
+    private static void checkRange(long[] a, int m) {
+        try {
+            Arrays.parallelSort(a, m + 1, m);
+
+            failed("ParallelSort does not throw IllegalArgumentException " +
+                " as expected: fromIndex = " + (m + 1) +
+                " toIndex = " + m);
+        }
+        catch (IllegalArgumentException iae) {
+            try {
+                Arrays.parallelSort(a, -m, a.length);
+
+                failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+                    " as expected: fromIndex = " + (-m));
+            }
+            catch (ArrayIndexOutOfBoundsException aoe) {
+                try {
+                    Arrays.parallelSort(a, 0, a.length + m);
+
+                    failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+                        " as expected: toIndex = " + (a.length + m));
+                }
+                catch (ArrayIndexOutOfBoundsException aie) {
+                    return;
+                }
+            }
+        }
+    }
+
+    private static void checkRange(byte[] a, int m) {
+        try {
+            Arrays.parallelSort(a, m + 1, m);
+
+            failed("ParallelSort does not throw IllegalArgumentException " +
+                " as expected: fromIndex = " + (m + 1) +
+                " toIndex = " + m);
+        }
+        catch (IllegalArgumentException iae) {
+            try {
+                Arrays.parallelSort(a, -m, a.length);
+
+                failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+                    " as expected: fromIndex = " + (-m));
+            }
+            catch (ArrayIndexOutOfBoundsException aoe) {
+                try {
+                    Arrays.parallelSort(a, 0, a.length + m);
+
+                    failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+                        " as expected: toIndex = " + (a.length + m));
+                }
+                catch (ArrayIndexOutOfBoundsException aie) {
+                    return;
+                }
+            }
+        }
+    }
+
+    private static void checkRange(short[] a, int m) {
+        try {
+            Arrays.parallelSort(a, m + 1, m);
+
+            failed("ParallelSort does not throw IllegalArgumentException " +
+                " as expected: fromIndex = " + (m + 1) +
+                " toIndex = " + m);
+        }
+        catch (IllegalArgumentException iae) {
+            try {
+                Arrays.parallelSort(a, -m, a.length);
+
+                failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+                    " as expected: fromIndex = " + (-m));
+            }
+            catch (ArrayIndexOutOfBoundsException aoe) {
+                try {
+                    Arrays.parallelSort(a, 0, a.length + m);
+
+                    failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+                        " as expected: toIndex = " + (a.length + m));
+                }
+                catch (ArrayIndexOutOfBoundsException aie) {
+                    return;
+                }
+            }
+        }
+    }
+
+    private static void checkRange(char[] a, int m) {
+        try {
+            Arrays.parallelSort(a, m + 1, m);
+
+            failed("ParallelSort does not throw IllegalArgumentException " +
+                " as expected: fromIndex = " + (m + 1) +
+                " toIndex = " + m);
+        }
+        catch (IllegalArgumentException iae) {
+            try {
+                Arrays.parallelSort(a, -m, a.length);
+
+                failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+                    " as expected: fromIndex = " + (-m));
+            }
+            catch (ArrayIndexOutOfBoundsException aoe) {
+                try {
+                    Arrays.parallelSort(a, 0, a.length + m);
+
+                    failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+                        " as expected: toIndex = " + (a.length + m));
+                }
+                catch (ArrayIndexOutOfBoundsException aie) {
+                    return;
+                }
+            }
+        }
+    }
+
+    private static void checkRange(float[] a, int m) {
+        try {
+            Arrays.parallelSort(a, m + 1, m);
+
+            failed("ParallelSort does not throw IllegalArgumentException " +
+                " as expected: fromIndex = " + (m + 1) +
+                " toIndex = " + m);
+        }
+        catch (IllegalArgumentException iae) {
+            try {
+                Arrays.parallelSort(a, -m, a.length);
+
+                failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+                    " as expected: fromIndex = " + (-m));
+            }
+            catch (ArrayIndexOutOfBoundsException aoe) {
+                try {
+                    Arrays.parallelSort(a, 0, a.length + m);
+
+                    failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+                        " as expected: toIndex = " + (a.length + m));
+                }
+                catch (ArrayIndexOutOfBoundsException aie) {
+                    return;
+                }
+            }
+        }
+    }
+
+    private static void checkRange(double[] a, int m) {
+        try {
+            Arrays.parallelSort(a, m + 1, m);
+
+            failed("ParallelSort does not throw IllegalArgumentException " +
+                " as expected: fromIndex = " + (m + 1) +
+                " toIndex = " + m);
+        }
+        catch (IllegalArgumentException iae) {
+            try {
+                Arrays.parallelSort(a, -m, a.length);
+
+                failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+                    " as expected: fromIndex = " + (-m));
+            }
+            catch (ArrayIndexOutOfBoundsException aoe) {
+                try {
+                    Arrays.parallelSort(a, 0, a.length + m);
+
+                    failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+                        " as expected: toIndex = " + (a.length + m));
+                }
+                catch (ArrayIndexOutOfBoundsException aie) {
+                    return;
+                }
+            }
+        }
+    }
+
+    private static void outArray(Object[] a) {
+        for (int i = 0; i < a.length; i++) {
+            out.print(a[i] + " ");
+        }
+        out.println();
+    }
+
+    private static void outArray(int[] a) {
+        for (int i = 0; i < a.length; i++) {
+            out.print(a[i] + " ");
+        }
+        out.println();
+    }
+
+    private static void outArray(float[] a) {
+        for (int i = 0; i < a.length; i++) {
+            out.print(a[i] + " ");
+        }
+        out.println();
+    }
+
+    private static void outArray(double[] a) {
+        for (int i = 0; i < a.length; i++) {
+            out.print(a[i] + " ");
+        }
+        out.println();
+    }
+
+    private static class MyRandom extends Random {
+        MyRandom(long seed) {
+            super(seed);
+            mySeed = seed;
+        }
+
+        long getSeed() {
+            return mySeed;
+        }
+
+        private long mySeed;
+    }
+
+    private static String ourDescription;
+}
--- a/jdk/test/java/util/Collections/EmptyIterator.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/java/util/Collections/EmptyIterator.java	Wed Jul 05 18:34:47 2017 +0200
@@ -23,12 +23,12 @@
 
 /*
  * @test
- * @bug 5017904 6356890
+ * @bug 5017904 6356890 8004928
  * @summary Test empty iterators, enumerations, and collections
  */
 
+import static java.util.Collections.*;
 import java.util.*;
-import static java.util.Collections.*;
 
 public class EmptyIterator {
 
@@ -45,10 +45,13 @@
         testEmptyIterator(emptyTable.values().iterator());
         testEmptyIterator(emptyTable.entrySet().iterator());
 
-        testEmptyEnumeration(javax.swing.tree.DefaultMutableTreeNode
-                             .EMPTY_ENUMERATION);
-        testEmptyEnumeration(javax.swing.text.SimpleAttributeSet
-                             .EMPTY.getAttributeNames());
+        final Enumeration<EmptyIterator> finalEmptyTyped =
+            Collections.emptyEnumeration();
+        testEmptyEnumeration(finalEmptyTyped);
+
+        final Enumeration finalEmptyAbstract =
+            Collections.emptyEnumeration();
+        testEmptyEnumeration(finalEmptyAbstract);
 
         @SuppressWarnings("unchecked") Iterator<?> x =
             new sun.tools.java.MethodSet()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Properties/Compatibility.xml	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd" 
+ [<!ENTITY intEnt 'value3'> ]>
+<?PITarget PIContent?>
+<properties>
+<comment>Property With Other Encoding</comment>
+<entry key="Key1">value1</entry>
+<entry key="Key2"><![CDATA[<value2>]]></entry>
+<entry key="Key3">&intEnt;</entry>
+</properties>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Properties/CompatibilityTest.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8005280 8004371
+ * @summary Compatibility test
+ * @run main CompatibilityTest
+ * @run main/othervm -Dsun.util.spi.XmlPropertiesProvider=jdk.internal.util.xml.BasicXmlPropertiesProvider CompatibilityTest
+ */
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+/**
+ * This is a behavior compatibility test.
+ * Although not defined by the properties.dtd, the constructs
+ * in Compatibility.xml are supported by the regular JDK XML
+ * Provider.
+ *
+ * @author: Joe Wang
+ */
+public class CompatibilityTest {
+
+    public static void main(String[] args) {
+        testInternalDTD();
+    }
+
+    /*
+     * Not in the spec, but the constructs work with the current JDK
+     */
+    static void testInternalDTD() {
+        String src = System.getProperty("test.src");
+        if (src == null) {
+            src = ".";
+        }
+        loadPropertyFile(src + "/Compatibility.xml");
+    }
+
+    /*
+     * 'Store' the populated 'Property' with the specified 'Encoding Type' as an
+     * XML file. Retrieve the same XML file and 'load' onto a new 'Property' object.
+     */
+    static void loadPropertyFile(String filename) {
+        try (InputStream in = new FileInputStream(filename)) {
+            Properties prop = new Properties();
+            prop.loadFromXML(in);
+            verifyProperites(prop);
+        } catch (IOException ex) {
+            fail(ex.getMessage());
+        }
+    }
+
+    /*
+     * This method verifies the first key-value with the original string.
+     */
+    static void verifyProperites(Properties prop) {
+        try {
+            for (String key : prop.stringPropertyNames()) {
+                String val = prop.getProperty(key);
+                if (key.equals("Key1")) {
+                    if (!val.equals("value1")) {
+                        fail("Key:" + key + "'s value: \nExpected: value1\nFound: " + val);
+                    }
+                } else if (key.equals("Key2")) {
+                    if (!val.equals("<value2>")) {
+                        fail("Key:" + key + "'s value: \nExpected: <value2>\nFound: " + val);
+                    }
+                } else if (key.equals("Key3")) {
+                    if (!val.equals("value3")) {
+                        fail("Key:" + key + "'s value: \nExpected: value3\nFound: " + val);
+                    }
+                }
+            }
+        } catch (Exception e) {
+            fail(e.getMessage());
+        }
+
+    }
+
+    static void fail(String err) {
+        throw new RuntimeException(err);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Properties/ConcurrentLoadAndStoreXML.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 8005281
+ * @summary Test that the Properties storeToXML and loadFromXML methods are
+ *   thread safe
+ * @run main ConcurrentLoadAndStoreXML
+ * @run main/othervm -Dsun.util.spi.XmlPropertiesProvider=jdk.internal.util.xml.BasicXmlPropertiesProvider ConcurrentLoadAndStoreXML
+
+ */
+
+import java.io.*;
+import java.util.Properties;
+import java.util.Random;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+
+public class ConcurrentLoadAndStoreXML {
+
+    static final Random RAND = new Random();
+
+    static volatile boolean done;
+
+    /**
+     * Simple task that bashes on storeToXML and loadFromXML until the "done"
+     * flag is set.
+     */
+    static class Basher implements Callable<Void> {
+        final Properties props;
+
+        Basher(Properties props) {
+            this.props = props;
+        }
+
+        public Void call() throws IOException {
+            while (!done) {
+
+                // store as XML format
+                ByteArrayOutputStream out = new ByteArrayOutputStream();
+                props.storeToXML(out, null, "UTF-8");
+
+                // load from XML format
+                Properties p = new Properties();
+                ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
+                p.loadFromXML(in);
+
+                // check that the properties are as expected
+                if (!p.equals(props))
+                    throw new RuntimeException("Properties not equal");
+            }
+            return null;
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        final int NTASKS = 4 + RAND.nextInt(4);
+
+        // create Bashers with Properties of random keys and values
+        Basher[] basher = new Basher[NTASKS];
+        for (int i=0; i<NTASKS; i++) {
+            Properties props = new Properties();
+            for (int j=0; j<RAND.nextInt(100); j++) {
+                String key = "k" + RAND.nextInt(1000);
+                String value = "v" + RAND.nextInt(1000);
+                props.put(key, value);
+            }
+            basher[i] = new Basher(props);
+        }
+
+        ExecutorService pool = Executors.newFixedThreadPool(NTASKS);
+        try {
+            // kick off the bashers
+            Future<Void>[] task = new Future[NTASKS];
+            for (int i=0; i<NTASKS; i++) {
+                task[i] = pool.submit(basher[i]);
+            }
+
+            // give them time to interfere with each each
+            Thread.sleep(2000);
+            done = true;
+
+            // check the result
+            for (int i=0; i<NTASKS; i++) {
+                task[i].get();
+            }
+        } finally {
+            done = true;
+            pool.shutdown();
+        }
+
+    }
+}
--- a/jdk/test/java/util/Properties/LoadAndStoreXML.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/java/util/Properties/LoadAndStoreXML.java	Wed Jul 05 18:34:47 2017 +0200
@@ -23,13 +23,16 @@
 
 /*
  * @test
- * @bug 8000354 8000685
+ * @bug 8000354 8000685 8004371
  * @summary Basic test of storeToXML and loadToXML
+ * @run main LoadAndStoreXML
+ * @run main/othervm -Dsun.util.spi.XmlPropertiesProvider=jdk.internal.util.xml.BasicXmlPropertiesProvider LoadAndStoreXML
  */
 
 import java.io.*;
 import java.util.*;
 import java.security.*;
+import java.nio.file.*;
 
 public class LoadAndStoreXML {
 
@@ -67,9 +70,14 @@
      * read with Properties#loadFromXML.
      */
     static void testLoadAndStore(String encoding) throws IOException {
+        System.out.println("testLoadAndStore, encoding=" + encoding);
+
         Properties props = new Properties();
         props.put("k1", "foo");
         props.put("k2", "bar");
+        props.put("k3", "\\u0020\\u0391\\u0392\\u0393\\u0394\\u0395\\u0396\\u0397");
+        props.put("k4", "\u7532\u9aa8\u6587");
+        props.put("k5", "<java.home>/lib/jaxp.properties");
 
         ByteArrayOutputStream out = new ByteArrayOutputStream();
         props.storeToXML(out, null, encoding);
@@ -89,6 +97,8 @@
      * Test loadFromXML with a document that does not have an encoding declaration
      */
     static void testLoadWithoutEncoding() throws IOException {
+        System.out.println("testLoadWithoutEncoding");
+
         Properties expected = new Properties();
         expected.put("foo", "bar");
 
@@ -107,10 +117,11 @@
         }
     }
 
-     /**
-      * Test loadFromXML with unsupported encoding
-      */
-     static void testLoadWithBadEncoding() throws IOException {
+    /**
+     * Test loadFromXML with unsupported encoding
+     */
+    static void testLoadWithBadEncoding() throws IOException {
+        System.out.println("testLoadWithBadEncoding");
         String s = "<?xml version=\"1.0\" encoding=\"BAD\"?>" +
                    "<!DOCTYPE properties SYSTEM \"http://java.sun.com/dtd/properties.dtd\">" +
                    "<properties>" +
@@ -128,6 +139,7 @@
      * Test storeToXML with unsupported encoding
      */
     static void testStoreWithBadEncoding() throws IOException {
+        System.out.println("testStoreWithBadEncoding");
         Properties props = new Properties();
         props.put("foo", "bar");
         ByteArrayOutputStream out = new ByteArrayOutputStream();
@@ -137,6 +149,26 @@
         } catch (UnsupportedEncodingException expected) { }
     }
 
+    /**
+     * Test loadFromXML with malformed documents
+     */
+    static void testLoadWithMalformedDoc(Path dir) throws IOException {
+        try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, "*.xml")) {
+            for (Path file: stream) {
+                System.out.println("testLoadWithMalformedDoc, file=" + file.getFileName());
+                try (InputStream in = Files.newInputStream(file)) {
+                    Properties props = new Properties();
+                    try {
+                        props.loadFromXML(in);
+                        throw new RuntimeException("InvalidPropertiesFormatException not thrown");
+                    } catch (InvalidPropertiesFormatException x) {
+                        System.out.println(x);
+                    }
+                }
+            }
+        }
+    }
+
     public static void main(String[] args) throws IOException {
 
         testLoadAndStore("UTF-8");
@@ -145,6 +177,12 @@
         testLoadWithBadEncoding();
         testStoreWithBadEncoding();
 
+        // malformed documents
+        String src = System.getProperty("test.src");
+        String subdir = "invalidxml";
+        Path dir = (src == null) ? Paths.get(subdir) : Paths.get(src, subdir);
+        testLoadWithMalformedDoc(dir);
+
         // re-run sanity test with security manager
         Policy orig = Policy.getPolicy();
         Policy p = new SimplePolicy(new RuntimePermission("setSecurityManager"),
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Properties/invalidxml/BadCase.xml	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
+
+<!-- XML tags are case sensitve, opening and closing tags must use same case -->
+
+<properties>
+<entry key="foo">bar</entry>
+<entry key="gus">baz</entry>
+</PROPERTIES>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Properties/invalidxml/BadDocType.xml	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE namevaluepairs SYSTEM "http://java.sun.com/dtd/properties.dtd">
+
+<!-- The root element for a XML properties document is properties -->
+
+<properties>
+<entry key="foo">bar</entry>
+<entry key="gus">baz</entry>
+</properties>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Properties/invalidxml/DTDRootNotMatch.xml	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf8" standalone="no"?>
+<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
+
+<!-- XML tags are case sensitve, the root element should have been in lower case -->
+
+<Properties>
+<comment>comment</comment>
+<entry key="firstKey">value of the first key</entry>
+</Properties>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Properties/invalidxml/IllegalComment.xml	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf8" standalone="no"?>
+<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
+
+<!-- The dtd allows zero or one comment element -->
+
+<properties>
+<comment>comment1</comment>
+<comment>comment2</comment>
+<entry key="firstKey">value of the first key</entry>
+</properties>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Properties/invalidxml/IllegalEntry.xml	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf8" standalone="no"?>
+<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
+
+<!-- The dtd requires 'entry' element, 'Entry' is illegal -->
+
+<properties>
+<comment>comment</comment>
+<Entry key="firstKey">value of the first key</Entry>
+</properties>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Properties/invalidxml/IllegalEntry1.xml	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf8" standalone="no"?>
+<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
+
+<!-- 'entry1' is illegal as per the dtd -->
+
+<properties>
+<comment>comment1</comment>
+
+<entry key="firstkey">value of the first key</entry>
+<entry1 key="secondkey">value of the second key</entry1>
+</properties>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Properties/invalidxml/IllegalKeyAttribute.xml	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf8" standalone="no"?>
+<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
+
+<!-- 'key' attribute is expected. 'key1' is mistyped -->
+
+<properties>
+<comment>comment1</comment>
+<entry key1="typo">value of the first key</entry>
+</properties>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Properties/invalidxml/NoClosingTag.xml	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
+
+<!-- XML elements must having a closing tag -->
+
+<properties>
+<entry key="foo">bar</entry>
+<entry key="gus">baz</entry>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Properties/invalidxml/NoDocType.xml	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+
+<!-- An XML properties document has the DOCTYPE declaration with the properties root element -->
+
+<properties>
+<entry key="foo">bar</entry>
+<entry key="gus">baz</entry>
+</properties>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Properties/invalidxml/NoNamespaceSupport.xml	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf8" standalone="no"?>
+<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
+
+<!-- namespace is not supported -->
+
+<javautil:properties xmlns:javautil="http://java.sun.com/java/util/Properties">
+<javautil:comment>comment1</javautil:comment>
+
+<javautil:entry key="firstkey">value of the first key</javautil:entry>
+<javautil:entry key="secondkey">value of the second key</javautil:entry>
+</javautil:properties>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Properties/invalidxml/NoRoot.xml	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
+
+<!-- XML documents must have a root element -->
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Properties/invalidxml/NotQuoted.xml	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
+
+<!-- XML attribute values must be quoted -->
+
+<properties>
+<entry key=foo>bar</entry>
+<entry key=gus>baz</entry>
+</properties>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Properties/invalidxml/README.txt	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,5 @@
+
+This directory contains test cases for the LoadAndStoreXML test case. Each file
+in this directory should be a malformed XML document that should cause the
+java.util.Properties loadFromXML method to throw InvalidPropertiesFormatException.
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/TimeZone/CLDRDisplayNamesTest.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8005471
+ * @run main/othervm -Djava.locale.providers=CLDR CLDRDisplayNamesTest
+ * @summary Make sure that localized time zone names of CLDR are used
+ * if specified.
+ */
+
+import java.util.*;
+import static java.util.TimeZone.*;
+
+public class CLDRDisplayNamesTest {
+    /*
+     * The first element is a language tag. The rest are localized
+     * display names of America/Los_Angeles copied from the CLDR
+     * resources data. If data change in CLDR, test data below will
+     * need to be changed accordingly.
+     *
+     * Generic names are NOT tested (until they are supported by API).
+     */
+    static final String[][] CLDR_DATA = {
+        {
+            "ja-JP",
+            "\u30a2\u30e1\u30ea\u30ab\u592a\u5e73\u6d0b\u6a19\u6e96\u6642",
+            "PST",
+            "\u30a2\u30e1\u30ea\u30ab\u592a\u5e73\u6d0b\u590f\u6642\u9593",
+            "PDT",
+            //"\u30a2\u30e1\u30ea\u30ab\u592a\u5e73\u6d0b\u6642\u9593",
+            //"PT"
+        },
+        {
+            "zh-CN",
+            "\u592a\u5e73\u6d0b\u6807\u51c6\u65f6\u95f4",
+            "PST",
+            "\u592a\u5e73\u6d0b\u590f\u4ee4\u65f6\u95f4",
+            "PDT",
+            //"\u7f8e\u56fd\u592a\u5e73\u6d0b\u65f6\u95f4",
+            //"PT"
+        },
+        {
+            "de-DE",
+            "Nordamerikanische Westk\u00fcsten-Winterzeit",
+            "PST",
+            "Nordamerikanische Westk\u00fcsten-Sommerzeit",
+            "PDT",
+            //"Nordamerikanische Westk\u00fcstenzeit",
+            //"PT"
+        },
+    };
+
+    public static void main(String[] args) {
+        TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
+        int errors = 0;
+        for (String[] data : CLDR_DATA) {
+            Locale locale = Locale.forLanguageTag(data[0]);
+            for (int i = 1; i < data.length; i++) {
+                int style = ((i % 2) == 1) ? LONG : SHORT;
+                boolean daylight = (i == 3 || i == 4);
+                String name = tz.getDisplayName(daylight, style, locale);
+                if (!data[i].equals(name)) {
+                    System.err.printf("error: got '%s' expected '%s' (style=%d, daylight=%s, locale=%s)%n",
+                                      name, data[i], style, daylight, locale);
+                    errors++;
+                }
+            }
+        }
+        if (errors > 0) {
+            throw new RuntimeException("test failed");
+        }
+    }
+}
--- a/jdk/test/java/util/logging/LoggingDeadlock4.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/java/util/logging/LoggingDeadlock4.java	Wed Jul 05 18:34:47 2017 +0200
@@ -23,11 +23,11 @@
 
 /*
  * @test
- * @bug     6977677
+ * @bug     6977677 8004928
  * @summary Deadlock between LogManager.<clinit> and Logger.getLogger()
  * @author  Daniel D. Daugherty
- * @build LoggingDeadlock4
- * @run main/othervm/timeout=15 -Djava.awt.headless=true LoggingDeadlock4
+ * @compile -XDignore.symbol.file LoggingDeadlock4.java
+ * @run main/othervm/timeout=15 LoggingDeadlock4
  */
 
 import java.util.concurrent.CountDownLatch;
@@ -39,21 +39,16 @@
     private static CountDownLatch lmIsRunning  = new CountDownLatch(1);
     private static CountDownLatch logIsRunning = new CountDownLatch(1);
 
+    // Create a sun.util.logging.PlatformLogger$JavaLogger object
+    // that has to be redirected when the LogManager class
+    // is initialized. This can cause a deadlock between
+    // LogManager.<clinit> and Logger.getLogger().
+    private static final sun.util.logging.PlatformLogger log =
+        sun.util.logging.PlatformLogger.getLogger("java.util.logging");
+
     public static void main(String[] args) {
         System.out.println("main: LoggingDeadlock4 is starting.");
 
-        // Loading the java.awt.Container class will create a
-        // sun.util.logging.PlatformLogger$JavaLogger object
-        // that has to be redirected when the LogManager class
-        // is initialized. This can cause a deadlock between
-        // LogManager.<clinit> and Logger.getLogger().
-        try {
-            Class.forName("java.awt.Container");
-        } catch (ClassNotFoundException cnfe) {
-            throw new RuntimeException("Test failed: could not load"
-                + " java.awt.Container." + cnfe);
-        }
-
         Thread lmThread = new Thread("LogManagerThread") {
             public void run() {
                 // let main know LogManagerThread is running
--- a/jdk/test/java/util/prefs/PrefsSpi.sh	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/java/util/prefs/PrefsSpi.sh	Wed Jul 05 18:34:47 2017 +0200
@@ -87,17 +87,17 @@
 
 case "`uname`" in Windows*|CYGWIN* ) CPS=';';; *) CPS=':';; esac
 
-Sys "$java" "${TESTVMOPTS}" "-cp" "$TESTCLASSES${CPS}extDir/PrefsSpi.jar" \
+Sys "$java" ${TESTVMOPTS} "-cp" "$TESTCLASSES${CPS}extDir/PrefsSpi.jar" \
     -Djava.util.prefs.PreferencesFactory=StubPreferencesFactory \
     -Djava.util.prefs.userRoot=. \
     PrefsSpi "StubPreferences"
-Sys "$java" "${TESTVMOPTS}" "-cp" "$TESTCLASSES" \
+Sys "$java" ${TESTVMOPTS} "-cp" "$TESTCLASSES" \
     -Djava.util.prefs.userRoot=. \
     PrefsSpi "java.util.prefs.*"
-Sys "$java" "${TESTVMOPTS}" "-cp" "$TESTCLASSES${CPS}extDir/PrefsSpi.jar" \
+Sys "$java" ${TESTVMOPTS} "-cp" "$TESTCLASSES${CPS}extDir/PrefsSpi.jar" \
     -Djava.util.prefs.userRoot=. \
     PrefsSpi "StubPreferences"
-Sys "$java" "${TESTVMOPTS}" "-cp" "$TESTCLASSES" "-Djava.ext.dirs=extDir" \
+Sys "$java" ${TESTVMOPTS} "-cp" "$TESTCLASSES" "-Djava.ext.dirs=extDir" \
     -Djava.util.prefs.userRoot=. \
     PrefsSpi "StubPreferences"
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/MBeanInfo/SerializationTest1.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 6783290
+ * @summary Test correct reading of an empty Descriptor.
+ * @author Jaroslav Bachorik
+ * @run clean SerializationTest1
+ * @run build SerializationTest1
+ * @run main SerializationTest1
+ */
+
+import java.io.*;
+import javax.management.*;
+
+public class SerializationTest1 {
+    public static void main(String[] args) throws Exception {
+        MBeanInfo mi1 = new MBeanInfo("",
+                                      "",
+                                      new MBeanAttributeInfo[]{},
+                                      new MBeanConstructorInfo[]{},
+                                      new MBeanOperationInfo[]{},
+                                      new MBeanNotificationInfo[]{},
+                                      ImmutableDescriptor.EMPTY_DESCRIPTOR);
+
+        test(mi1);
+
+        MBeanFeatureInfo mfi2 = new MBeanFeatureInfo("",
+                                                     "",
+                                                     ImmutableDescriptor.EMPTY_DESCRIPTOR);
+
+        test(mfi2);
+    }
+
+    public static void test(Object obj) throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream oos = new ObjectOutputStream(baos);
+        oos.writeObject(obj);
+
+        final boolean[] failed = new boolean[]{false};
+        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+        final ObjectInputStream ois = new ObjectInputStream(bais) {
+            protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
+                System.out.println("*** " + desc.getName());
+                if (desc.getName().equals("[Ljava.lang.Object;")) { // javax.management.Descriptor fields
+                    Thread.dumpStack();
+                    for(StackTraceElement e : Thread.currentThread().getStackTrace()) { // checking for the deserialization location
+                        if (e.getMethodName().equals("skipCustomData")) { // indicates the presence of unread values from the custom object serialization
+                            failed[0] = true;
+                        }
+                    }
+                }
+                return super.resolveClass(desc); //To change body of generated methods, choose Tools | Templates.
+            }
+        };
+        Object newObj = ois.readObject();
+
+        if (failed[0]) {
+            throw new RuntimeException("Zero-length descriptor not read back");
+        }
+    }
+}
--- a/jdk/test/javax/management/remote/mandatory/connection/AddressableTest.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/javax/management/remote/mandatory/connection/AddressableTest.java	Wed Jul 05 18:34:47 2017 +0200
@@ -45,19 +45,36 @@
 
     private static final MBeanServer mbs = MBeanServerFactory.createMBeanServer();
 
+    private static boolean isProtocolSupported(String protocol) {
+        if (protocol.equals("rmi"))
+            return true;
+        if (protocol.equals("iiop")) {
+            try {
+                Class.forName("javax.management.remote.rmi._RMIConnectionImpl_Tie");
+                return true;
+            } catch (ClassNotFoundException x) { }
+        }
+        return false;
+    }
+
     public static void main(String[] args) throws Exception {
         System.out.println(">>> test the new interface Addressable.");
         boolean ok = true;
 
         for (int i = 0; i < protocols.length; i++) {
-            try {
-                test(protocols[i], prefixes[i]);
-
-                System.out.println(">>> Test successed for "+protocols[i]);
-            } catch (Exception e) {
-                System.out.println(">>> Test failed for "+protocols[i]);
-                e.printStackTrace(System.out);
-                ok = false;
+            String protocol = protocols[i];
+            if (isProtocolSupported(protocol)) {
+                try {
+                    test(protocol, prefixes[i]);
+                    System.out.println(">>> Test successed for "+protocols[i]);
+                } catch (Exception e) {
+                    System.out.println(">>> Test failed for "+protocols[i]);
+                    e.printStackTrace(System.out);
+                    ok = false;
+                }
+            } else {
+                System.out.format(">>> Test skipped for %s, protocol not supported%n",
+                    protocol);
             }
         }
 
@@ -65,7 +82,7 @@
             System.out.println(">>> All Test passed.");
         } else {
             System.out.println(">>> Some TESTs FAILED");
-            System.exit(1);
+            throw new RuntimeException("See log for details");
         }
     }
 
--- a/jdk/test/javax/management/remote/mandatory/connection/CloseableTest.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/javax/management/remote/mandatory/connection/CloseableTest.java	Wed Jul 05 18:34:47 2017 +0200
@@ -42,7 +42,6 @@
 import javax.management.remote.rmi.RMIIIOPServerImpl;
 import javax.management.remote.rmi.RMIJRMPServerImpl;
 import javax.management.remote.rmi.RMIServerImpl;
-import org.omg.stub.javax.management.remote.rmi._RMIConnection_Stub;
 
 public class CloseableTest {
     private static final Class closeArray[] = {
@@ -51,26 +50,43 @@
         RMIConnection.class,
         RMIConnectionImpl.class,
         RMIConnectionImpl_Stub.class,
-        _RMIConnection_Stub.class,
         RMIServerImpl.class,
         RMIIIOPServerImpl.class,
         RMIJRMPServerImpl.class
     };
+
+    static int error;
+
+    static void test(Class<?> c) {
+        System.out.println("\nTest " + c);
+        if (Closeable.class.isAssignableFrom(c)) {
+            System.out.println("Test passed!");
+        } else {
+            error++;
+            System.out.println("Test failed!");
+        }
+    }
+
+    static void test(String cn) {
+        try {
+            test(Class.forName(cn));
+        } catch (ClassNotFoundException ignore) {
+            System.out.println("\n" + cn + " not tested.");
+        }
+    }
+
     public static void main(String[] args) throws Exception {
         System.out.println("Test that all the JMX Remote API classes that " +
                            "define\nthe method \"void close() throws " +
                            "IOException;\" extend\nor implement the " +
                            "java.io.Closeable interface.");
-        int error = 0;
-        for (Class c : closeArray) {
-            System.out.println("\nTest " + c);
-            if (Closeable.class.isAssignableFrom(c)) {
-                System.out.println("Test passed!");
-            } else {
-                error++;
-                System.out.println("Test failed!");
-            }
+        for (Class<?> c : closeArray) {
+            test(c);
         }
+
+        // Stub classes not present if RMI-IIOP not supported
+        test("org.omg.stub.javax.management.remote.rmi._RMIConnection_Stub");
+
         if (error > 0) {
             final String msg = "\nTest FAILED! Got " + error + " error(s)";
             System.out.println(msg);
--- a/jdk/test/javax/management/remote/mandatory/connection/ConnectionListenerNullTest.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/javax/management/remote/mandatory/connection/ConnectionListenerNullTest.java	Wed Jul 05 18:34:47 2017 +0200
@@ -39,33 +39,22 @@
 import java.util.Map;
 public class ConnectionListenerNullTest {
 
-    static final boolean optionalFlag;
-    static {
-        Class genericClass = null;
+    static boolean isPresent(String cn) {
         try {
-            genericClass =
-            Class.forName("javax.management.remote.generic.GenericConnector");
+            Class.forName(cn);
+            return true;
         } catch (ClassNotFoundException x) {
-            // NO optional package
+            return false;
         }
-        optionalFlag = (genericClass != null);
     }
 
-    final static String[] mandatoryList = {
-        "service:jmx:rmi://", "service:jmx:iiop://"
-    };
-
-    final static String[] optionalList = {
-        "service:jmx:jmxmp://"
-    };
-
-    public static int test(String[] urls) {
+    public static int test(String... urls) {
         int errCount = 0;
         for (int i=0;i<urls.length;i++) {
             try {
                 final JMXServiceURL url = new JMXServiceURL(urls[i]);
                 final JMXConnector c =
-                    JMXConnectorFactory.newJMXConnector(url,(Map)null);
+                    JMXConnectorFactory.newJMXConnector(url,(Map<String,String>)null);
                 final NotificationListener nl = null;
                 final NotificationFilter   nf = null;
                 final Object               h  = null;
@@ -121,12 +110,19 @@
 
     public static void main(String args[]) {
         int errCount = 0;
-        errCount += test(mandatoryList);
-        if (optionalFlag) errCount += test(optionalList);
+
+        // mandatory
+        errCount += test("service:jmx:rmi://");
+
+        // optional
+        if (isPresent("javax.management.remote.rmi._RMIConnectionImpl_Tie"))
+            errCount += test("service:jmx:iiop://");
+        if (isPresent("javax.management.remote.generic.GenericConnector"))
+            errCount += test("service:jmx:jmxmp://");
+
         if (errCount > 0) {
-            System.err.println("ConnectionListenerNullTest failed: " +
-                               errCount + " error(s) reported.");
-            System.exit(1);
+            throw new RuntimeException("ConnectionListenerNullTest failed: " +
+                errCount + " error(s) reported.");
         }
         System.out.println("ConnectionListenerNullTest passed.");
     }
--- a/jdk/test/javax/management/remote/mandatory/connection/IIOPURLTest.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/javax/management/remote/mandatory/connection/IIOPURLTest.java	Wed Jul 05 18:34:47 2017 +0200
@@ -49,17 +49,24 @@
     public static void main(String[] args) throws Exception {
         JMXServiceURL inputAddr =
             new JMXServiceURL("service:jmx:iiop://");
-        JMXConnectorServer s =
-            JMXConnectorServerFactory.newJMXConnectorServer(inputAddr, null,
-                                                            null);
+        JMXConnectorServer s;
+        try {
+            s = JMXConnectorServerFactory.newJMXConnectorServer(inputAddr, null, null);
+        } catch (java.net.MalformedURLException x) {
+            try {
+                Class.forName("javax.management.remote.rmi._RMIConnectionImpl_Tie");
+                throw new RuntimeException("MalformedURLException thrown but iiop appears to be supported");
+            } catch (ClassNotFoundException expected) { }
+            System.out.println("IIOP protocol not supported, test skipped");
+            return;
+        }
         MBeanServer mbs = MBeanServerFactory.createMBeanServer();
         mbs.registerMBean(s, new ObjectName("a:b=c"));
         s.start();
         JMXServiceURL outputAddr = s.getAddress();
         if (!outputAddr.getURLPath().startsWith("/ior/IOR:")) {
-            System.out.println("URL path should start with \"/ior/IOR:\": " +
-                               outputAddr);
-            System.exit(1);
+            throw new RuntimeException("URL path should start with \"/ior/IOR:\": " +
+                                       outputAddr);
         }
         System.out.println("IIOP URL path looks OK: " + outputAddr);
         JMXConnector c = JMXConnectorFactory.connect(outputAddr);
--- a/jdk/test/javax/management/remote/mandatory/connection/IdleTimeoutTest.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/javax/management/remote/mandatory/connection/IdleTimeoutTest.java	Wed Jul 05 18:34:47 2017 +0200
@@ -52,21 +52,27 @@
 import com.sun.jmx.remote.util.EnvHelp;
 
 public class IdleTimeoutTest {
+
+    static boolean isPresent(String cn) {
+        try {
+            Class.forName(cn);
+            return true;
+        } catch (ClassNotFoundException x) {
+            return false;
+        }
+    }
+
     public static void main(String[] args) throws Exception {
         boolean ok = true;
         List protos;
         if (args.length > 0)
             protos = Arrays.asList(args);
         else {
-            protos =
-                new ArrayList(Arrays.asList(new String[] {"rmi", "iiop"}));
-            try {
-                Class.forName("javax.management.remote.jmxmp." +
-                              "JMXMPConnectorServer");
+            protos = new ArrayList(Arrays.asList(new String[] {"rmi"}));
+            if (isPresent("javax.management.remote.rmi._RMIConnectionImpl_Tie"))
+                protos.add("iiop");
+            if (isPresent("javax.management.remote.jmxmp.JMXMPConnectorServer"))
                 protos.add("jmxmp");
-            } catch (ClassNotFoundException e) {
-                // OK: Optional JMXMP support is not present
-            }
         }
         for (Iterator it = protos.iterator(); it.hasNext(); ) {
             String proto = (String) it.next();
@@ -81,13 +87,13 @@
             }
         }
         if (!ok) {
-            System.out.println("SOME TESTS FAILED");
-            System.exit(1);
+            throw new RuntimeException("Some tests failed - see log for details");
         }
     }
 
     private static long getIdleTimeout(MBeanServer mbs, JMXServiceURL url)
-        throws Exception {
+        throws Exception
+    {
         JMXConnectorServer server =
             JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);
         server.start();
--- a/jdk/test/javax/management/remote/mandatory/connection/MultiThreadDeadLockTest.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/javax/management/remote/mandatory/connection/MultiThreadDeadLockTest.java	Wed Jul 05 18:34:47 2017 +0200
@@ -253,4 +253,3 @@
         System.out.println("===Leave the method: " + m);
     }
 }
-
--- a/jdk/test/javax/management/remote/mandatory/connectorServer/SetMBeanServerForwarder.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/javax/management/remote/mandatory/connectorServer/SetMBeanServerForwarder.java	Wed Jul 05 18:34:47 2017 +0200
@@ -40,27 +40,16 @@
 
 public class SetMBeanServerForwarder {
 
-    static final boolean optionalFlag;
-    static {
-        Class genericClass = null;
+    static boolean isPresent(String cn) {
         try {
-            genericClass =
-            Class.forName("javax.management.remote.generic.GenericConnector");
+            Class.forName(cn);
+            return true;
         } catch (ClassNotFoundException x) {
-            // NO optional package
+            return false;
         }
-        optionalFlag = (genericClass != null);
     }
 
-    final static String[] mandatoryList = {
-        "service:jmx:rmi://", "service:jmx:iiop://"
-    };
-
-    final static String[] optionalList = {
-        "service:jmx:jmxmp://"
-    };
-
-    public static int test(String[] urls) {
+    public static int test(String... urls) {
         int errorCount = 0;
         for (int i=0;i<urls.length;i++) {
             try {
@@ -241,12 +230,19 @@
 
     public static void main(String args[]) {
         int errCount = 0;
-        errCount += test(mandatoryList);
-        if (optionalFlag) errCount += test(optionalList);
+
+        // mandatory
+        errCount += test("service:jmx:rmi://");
+
+        // optional
+        if (isPresent("javax.management.remote.rmi._RMIConnectionImpl_Tie"))
+            errCount += test("service:jmx:iiop://");
+        if (isPresent("javax.management.remote.generic.GenericConnector"))
+            errCount += test("service:jmx:jmxmp://");
+
         if (errCount > 0) {
-            System.err.println("SetMBeanServerForwarder failed: " +
-                               errCount + " error(s) reported.");
-            System.exit(1);
+            throw new RuntimeException("SetMBeanServerForwarder failed: " +
+                                       errCount + " error(s) reported.");
         }
         System.out.println("SetMBeanServerForwarder passed.");
     }
--- a/jdk/test/javax/management/remote/mandatory/loading/MissingClassTest.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/javax/management/remote/mandatory/loading/MissingClassTest.java	Wed Jul 05 18:34:47 2017 +0200
@@ -70,7 +70,6 @@
 import javax.management.remote.JMXConnectorServerFactory;
 import javax.management.remote.JMXServiceURL;
 import javax.management.remote.rmi.RMIConnectorServer;
-import org.omg.CORBA.MARSHAL;
 
 public class MissingClassTest {
     private static final int NNOTIFS = 50;
@@ -84,6 +83,15 @@
 
     private static final Object unserializableObject = Thread.currentThread();
 
+    private static boolean isInstance(Object o, String cn) {
+        try {
+            Class<?> c = Class.forName(cn);
+            return c.isInstance(o);
+        } catch (ClassNotFoundException x) {
+            return false;
+        }
+    }
+
     public static void main(String[] args) throws Exception {
         System.out.println("Test that the client or server end of a " +
                            "connection does not fail if sent an object " +
@@ -118,8 +126,7 @@
         if (ok)
             System.out.println("Test passed");
         else {
-            System.out.println("TEST FAILED");
-            System.exit(1);
+            throw new RuntimeException("TEST FAILED");
         }
     }
 
@@ -133,7 +140,7 @@
 
         JMXConnectorServer cs;
         JMXServiceURL url = new JMXServiceURL(proto, null, 0);
-        Map serverMap = new HashMap();
+        Map<String,Object> serverMap = new HashMap<>();
         serverMap.put(JMXConnectorServerFactory.DEFAULT_CLASS_LOADER,
                       serverLoader);
 
@@ -151,7 +158,7 @@
         }
         cs.start();
         JMXServiceURL addr = cs.getAddress();
-        Map clientMap = new HashMap();
+        Map<String,Object> clientMap = new HashMap<>();
         clientMap.put(JMXConnectorFactory.DEFAULT_CLASS_LOADER,
                       clientLoader);
 
@@ -174,7 +181,7 @@
             ok = false;
         } catch (IOException e) {
             Throwable cause = e.getCause();
-            if (cause instanceof MARSHAL)  // see CR 4935098
+            if (isInstance(cause, "org.omg.CORBA.MARSHAL"))  // see CR 4935098
                 cause = cause.getCause();
             if (cause instanceof ClassNotFoundException) {
                 System.out.println("Success: got an IOException wrapping " +
@@ -188,7 +195,7 @@
         }
 
         System.out.println("Doing queryNames to ensure connection alive");
-        Set names = mbsc.queryNames(null, null);
+        Set<ObjectName> names = mbsc.queryNames(null, null);
         System.out.println("queryNames returned " + names);
 
         System.out.println("Provoke exception of unknown class");
@@ -198,7 +205,7 @@
             ok = false;
         } catch (IOException e) {
             Throwable wrapped = e.getCause();
-            if (wrapped instanceof MARSHAL)  // see CR 4935098
+            if (isInstance(wrapped, "org.omg.CORBA.MARSHAL"))  // see CR 4935098
                 wrapped = wrapped.getCause();
             if (wrapped instanceof ClassNotFoundException) {
                 System.out.println("Success: got an IOException wrapping " +
@@ -251,7 +258,7 @@
                 ok = false;
             } catch (IOException e) {
                 Throwable cause = e.getCause();
-                if (cause instanceof MARSHAL)  // see CR 4935098
+                if (isInstance(cause, "org.omg.CORBA.MARSHAL"))  // see CR 4935098
                     cause = cause.getCause();
                 if (cause instanceof ClassNotFoundException) {
                     System.out.println("Success: got an IOException " +
@@ -584,15 +591,13 @@
             try {
                 new ObjectOutputStream(new ByteArrayOutputStream())
                     .writeObject(tricky);
-                System.out.println("TEST INCORRECT: tricky notif is " +
-                                   "serializable");
-                System.exit(1);
+                throw new RuntimeException("TEST INCORRECT: tricky notif is " +
+                                           "serializable");
             } catch (NotSerializableException e) {
                 // OK: tricky notif is not serializable
             } catch (IOException e) {
-                System.out.println("TEST INCORRECT: tricky notif " +
-                                   "serialization check failed");
-                System.exit(1);
+                throw new RuntimeException("TEST INCORRECT: tricky notif " +
+                                            "serialization check failed");
             }
 
             /* Now shuffle an imaginary deck of cards where K, U, T, and
@@ -629,12 +634,11 @@
             }
             if (knownCount != 0 || unknownCount != 0
                 || trickyCount != 0 || boringCount != 0) {
-                System.out.println("TEST INCORRECT: Shuffle failed: " +
+                throw new RuntimeException("TEST INCORRECT: Shuffle failed: " +
                                    "known=" + knownCount +" unknown=" +
                                    unknownCount + " tricky=" + trickyCount +
                                    " boring=" + boringCount +
                                    " deal=" + notifList);
-                System.exit(1);
             }
             String notifs = notifList.toString();
             System.out.println("Shuffle: " + notifs);
@@ -646,10 +650,8 @@
                 case 't': n = tricky; break;
                 case 'b': n = boring; break;
                 default:
-                    System.out.println("TEST INCORRECT: Bad shuffle char: " +
-                                       notifs.charAt(i));
-                    System.exit(1);
-                    throw new Error();
+                    throw new RuntimeException("TEST INCORRECT: Bad shuffle char: " +
+                                               notifs.charAt(i));
                 }
                 sendNotification(n);
             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/remote/mandatory/notif/ConcurrentModificationTest.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 7120365
+ * @summary test on Concurrent Modification
+ * @author Shanliang JIANG
+ * @run main ConcurrentModificationTest
+ */
+
+import java.net.MalformedURLException;
+import java.util.ConcurrentModificationException;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerFactory;
+import javax.management.Notification;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
+
+/**
+ *
+ */
+public class ConcurrentModificationTest {
+    private static final String[] protocols = {"rmi", "iiop", "jmxmp"};
+    private static int number = 100;
+
+    private static final MBeanServer mbs = MBeanServerFactory.createMBeanServer();
+    private static ObjectName delegateName;
+    private static ObjectName[] timerNames = new ObjectName[number];
+    private static NotificationListener[] listeners = new NotificationListener[number];
+
+    private static Throwable uncaughtException = null;
+
+    public static void main(String[] args) throws Exception {
+        System.out.println(">>> test on Concurrent Modification.");
+
+        Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
+            @Override
+            public void uncaughtException(Thread t, Throwable e) {
+                e.printStackTrace();
+                if (e instanceof ConcurrentModificationException) {
+                    uncaughtException = e;
+                }
+            }
+        });
+
+        delegateName = new ObjectName("JMImplementation:type=MBeanServerDelegate");
+        for (int i=0; i<number; i++) {
+            timerNames[i] = new ObjectName("MBean:name=Timer"+i);
+            listeners[i] = new NotificationListener() {
+                @Override
+                public void handleNotification(Notification notification, Object handback) {
+                    // nothing
+                }
+            };
+        }
+        String errors = "";
+
+        for (int i = 0; i < protocols.length; i++) {
+            uncaughtException = null;
+            System.out.println(">>> Test for protocol " + protocols[i]);
+            test(protocols[i]);
+            if (uncaughtException != null) {
+                if ("".equals(errors)) {
+                    errors = "Failed to " + protocols[i] + ": "+uncaughtException;
+                } else {
+                    errors = errors+", failed to " + protocols[i] + ": "+uncaughtException;
+                }
+                System.out.println(">>> FAILED for protocol " + protocols[i]);
+            } else {
+                System.out.println(">>> PASSED for protocol " + protocols[i]);
+            }
+        }
+
+        if ("".equals(errors)) {
+            System.out.println("All Passed!");
+        } else {
+            System.out.println("!!!!!! Failed.");
+
+            throw new RuntimeException(errors);
+        }
+    }
+
+    private static void test(String proto) throws Exception {
+        JMXServiceURL u = new JMXServiceURL(proto, null, 0);
+        JMXConnectorServer server;
+        JMXConnector client;
+
+        try {
+            server =
+                    JMXConnectorServerFactory.newJMXConnectorServer(u, null, mbs);
+            server.start();
+            JMXServiceURL addr = server.getAddress();
+            client = JMXConnectorFactory.connect(addr, null);
+        } catch (MalformedURLException e) {
+            System.out.println(">>> not support: " + proto);
+            return;
+        }
+
+        final MBeanServerConnection mserver = client.getMBeanServerConnection();
+
+        int count = 0;
+        boolean adding = true;
+        while (uncaughtException == null && count++ < 10) {
+            for (int i = 0; i < number; i++) {
+                listenerOp(mserver, listeners[i], adding);
+                mbeanOp(mserver, timerNames[i], adding);
+            }
+            adding = !adding;
+        }
+
+        if (uncaughtException != null) { // clean
+            for (int i = 0; i < number; i++) {
+                try {
+                    mbeanOp(mserver, timerNames[i], false);
+                } catch (Exception e) {
+                }
+            }
+        }
+        client.close();
+        server.stop();
+    }
+
+    private static void mbeanOp(MBeanServerConnection mserver, ObjectName name, boolean adding)
+            throws Exception {
+        if (adding) {
+            mserver.createMBean("javax.management.timer.Timer", name);
+        } else {
+            mserver.unregisterMBean(name);
+        }
+    }
+
+    private static void listenerOp(MBeanServerConnection mserver, NotificationListener listener, boolean adding)
+            throws Exception {
+        if (adding) {
+            mserver.addNotificationListener(delegateName, listener, null, null);
+        } else {
+            mserver.removeNotificationListener(delegateName, listener);
+        }
+    }
+}
\ No newline at end of file
--- a/jdk/test/javax/management/remote/mandatory/provider/ProviderTest.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/javax/management/remote/mandatory/provider/ProviderTest.java	Wed Jul 05 18:34:47 2017 +0200
@@ -49,13 +49,13 @@
 import provider.JMXConnectorProviderImpl;
 import provider.JMXConnectorServerProviderImpl;
 public class ProviderTest {
+
     public static void main(String[] args) throws Exception {
         System.out.println("Starting ProviderTest");
         MBeanServer mbs = MBeanServerFactory.newMBeanServer();
-        //First do the test with a protocol handled by Service providers
-        JMXServiceURL url =
-            new JMXServiceURL("service:jmx:rmi://");
 
+        // First do the test with a protocol handled by Service providers
+        JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://");
         dotest(url, mbs);
 
         boolean clientCalled = provider.JMXConnectorProviderImpl.called();
@@ -66,16 +66,22 @@
                 System.out.println("Client provider not called");
             if (!serverCalled)
                 System.out.println("Server provider not called");
-            System.out.println("Test Failed");
-            System.exit(1);
+            throw new RuntimeException("Test failed - see log for details");
         }
 
-        //The Service Provider doesn't handle IIOP. Default providers MUST
-        //be called.
-        url =
-            new JMXServiceURL("service:jmx:iiop://");
-
-        dotest(url, mbs);
+        // The Service Provider doesn't handle IIOP. Default providers MUST
+        // be called, which may or may not support IIOP.
+        url = new JMXServiceURL("service:jmx:iiop://");
+        try {
+            dotest(url, mbs);
+        } catch (MalformedURLException e) {
+            try {
+                Class.forName("javax.management.remote.rmi._RMIConnectionImpl_Tie");
+                e.printStackTrace(System.out);
+                throw new RuntimeException("MalformedURLException throw but IIOP appears to be supported");
+            } catch (ClassNotFoundException expected) { }
+            System.out.println("MalformedURLException thrown, IIOP transport not supported");
+        }
 
         // Unsupported protocol.
         JMXConnectorServer server = null;
@@ -87,31 +93,19 @@
                 JMXConnectorServerFactory.newJMXConnectorServer(url,
                                                                 null,
                                                                 mbs);
-            System.out.println("Exception not thrown.");
-            System.exit(1);
-        }catch(MalformedURLException e) {
+            throw new RuntimeException("Exception not thrown.");
+        } catch (MalformedURLException e) {
             System.out.println("Expected MalformedURLException thrown.");
         }
-        catch(Exception e) {
-            e.printStackTrace();
-            System.out.println("Exception thrown : " + e);
-            System.exit(1);
-        }
 
         try {
             client =
                 JMXConnectorFactory.newJMXConnector(url,
                                                     null);
-            System.out.println("Exception not thrown.");
-            System.exit(1);
-        }catch(MalformedURLException e) {
+            throw new RuntimeException("Exception not thrown.");
+        } catch (MalformedURLException e) {
             System.out.println("Expected MalformedURLException thrown.");
         }
-        catch(Exception e) {
-            e.printStackTrace();
-            System.out.println("Exception thrown : " + e);
-            System.exit(1);
-        }
 
         //JMXConnectorProviderException
         url =
@@ -121,60 +115,34 @@
                 JMXConnectorServerFactory.newJMXConnectorServer(url,
                                                                 null,
                                                                 mbs);
-            System.out.println("Exception not thrown.");
-            System.exit(1);
-        }catch(JMXProviderException e) {
+            throw new RuntimeException("Exception not thrown.");
+        } catch(JMXProviderException e) {
             System.out.println("Expected JMXProviderException thrown.");
         }
-        catch(Exception e) {
-            e.printStackTrace();
-            System.out.println("Exception thrown : " + e);
-            System.exit(1);
-        }
 
         try {
             client =
                 JMXConnectorFactory.newJMXConnector(url,
                                                     null);
-            System.out.println("Exception not thrown.");
-            System.exit(1);
+            throw new RuntimeException("Exception not thrown.");
         }catch(JMXProviderException e) {
             System.out.println("Expected JMXProviderException thrown.");
         }
-        catch(Exception e) {
-            e.printStackTrace();
-            System.out.println("Exception thrown : " + e);
-            System.exit(1);
-        }
 
         System.out.println("Test OK");
-        return;
     }
 
     private static void dotest(JMXServiceURL url, MBeanServer mbs)
         throws Exception {
         JMXConnectorServer server = null;
         JMXConnector client = null;
-        try {
-            server =
-                JMXConnectorServerFactory.newJMXConnectorServer(url,
-                                                                null,
-                                                                mbs);
-        }catch(IllegalArgumentException e) {
-            e.printStackTrace();
-            System.exit(1);
-        }
+
+        server = JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);
         server.start();
         JMXServiceURL outputAddr = server.getAddress();
         System.out.println("Server started ["+ outputAddr+ "]");
 
-        try {
-            client =
-                JMXConnectorFactory.newJMXConnector(outputAddr, null);
-        }catch(IllegalArgumentException e) {
-            e.printStackTrace();
-            System.exit(1);
-        }
+        client = JMXConnectorFactory.newJMXConnector(outputAddr, null);
 
         client.connect();
         System.out.println("Client connected");
--- a/jdk/test/javax/management/remote/mandatory/serverError/JMXServerErrorTest.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/javax/management/remote/mandatory/serverError/JMXServerErrorTest.java	Wed Jul 05 18:34:47 2017 +0200
@@ -120,7 +120,7 @@
         try {
             cs=JMXConnectorServerFactory.newJMXConnectorServer(jurl,null,kbs);
         } catch (MalformedURLException m) {
-            if ("jmxmp".equals(jurl.getProtocol())) {
+            if ("jmxmp".equals(jurl.getProtocol()) || "iiop".equals(jurl.getProtocol())) {
                 // OK, we may not have this in the classpath...
                 System.out.println("WARNING: Skipping protocol: " + jurl);
                 return;
--- a/jdk/test/javax/swing/AncestorNotifier/7193219/bug7193219.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/javax/swing/AncestorNotifier/7193219/bug7193219.java	Wed Jul 05 18:34:47 2017 +0200
@@ -30,6 +30,7 @@
 import java.io.*;
 
 import javax.swing.*;
+import javax.swing.plaf.metal.*;
 
 public class bug7193219 {
     private static byte[] serializeGUI() {
@@ -73,6 +74,7 @@
     }
 
     public static void main(String[] args) throws Exception {
+        UIManager.setLookAndFeel(new MetalLookAndFeel());
         SwingUtilities.invokeAndWait(new Runnable() {
             @Override
             public void run() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/JFrame/4962534/bug4962534.html	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,43 @@
+<html>
+<!--
+  Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+  This code is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License version 2 only, as
+  published by the Free Software Foundation.
+
+  This code is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  version 2 for more details (a copy is included in the LICENSE file that
+  accompanied this code).
+
+  You should have received a copy of the GNU General Public License version
+  2 along with this work; if not, write to the Free Software Foundation,
+  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+  Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+  or visit www.oracle.com if you need additional information or have any
+  questions.
+ -->
+
+<!--
+  @test
+  @bug 4962534
+  @summary JFrame dances very badly
+  @author dav@sparc.spb.su area=
+  @run applet bug4962534.html
+  -->
+<head>
+<title>  </title>
+</head>
+<body>
+
+<h1>bug4962534<br>Bug ID: 4962534 </h1>
+
+<p> This is an AUTOMATIC test, simply wait for completion </p>
+
+<APPLET CODE="bug4962534.class" WIDTH=200 HEIGHT=200></APPLET>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/JFrame/4962534/bug4962534.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ test
+ @bug 4962534 7104594
+ @summary JFrame dances very badly
+ @author dav@sparc.spb.su area=
+ @run applet bug4962534.html
+ */
+import java.applet.Applet;
+import java.awt.*;
+import java.awt.event.*;
+import java.util.Random;
+import javax.swing.*;
+import sun.awt.SunToolkit;
+
+public class bug4962534 extends Applet {
+
+    Robot robot;
+    volatile Point framePosition;
+    volatile Point newFrameLocation;
+    JFrame frame;
+    Rectangle gcBounds;
+    Component titleComponent;
+    JLayeredPane lPane;
+    volatile boolean titleFound = false;
+    SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit();
+    public static Object LOCK = new Object();
+
+    @Override
+    public void init() {
+        try {
+            SwingUtilities.invokeAndWait(new Runnable() {
+                @Override
+                public void run() {
+                    createAndShowGUI();
+                }
+            });
+        } catch (Exception ex) {
+            throw new RuntimeException("Init failed. " + ex.getMessage());
+        }
+    }//End  init()
+
+    @Override
+    public void start() {
+        validate();
+
+        try {
+            setJLayeredPaneEDT();
+            setTitleComponentEDT();
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            throw new RuntimeException("Test failed. " + ex.getMessage());
+        }
+
+        if (!titleFound) {
+            throw new RuntimeException("Test Failed. Unable to determine title's size.");
+        }
+
+        Random r = new Random();
+
+        for (int iteration = 0; iteration < 10; iteration++) {
+            try {
+                setFramePosEDT();
+            } catch (Exception ex) {
+                ex.printStackTrace();
+                throw new RuntimeException("Test failed.");
+            }
+            try {
+                robot = new Robot();
+                robot.setAutoDelay(70);
+
+                toolkit.realSync();
+
+                robot.mouseMove(framePosition.x + getJFrameWidthEDT() / 2,
+                        framePosition.y + titleComponent.getHeight() / 2);
+                robot.mousePress(InputEvent.BUTTON1_MASK);
+
+                toolkit.realSync();
+
+                gcBounds =
+                        GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()[0].getConfigurations()[0].getBounds();
+
+                robot.mouseMove(framePosition.x + getJFrameWidthEDT() / 2,
+                        framePosition.y + titleComponent.getHeight() / 2);
+
+                toolkit.realSync();
+
+                int multier = gcBounds.height / 2 - 10; //we will not go out the borders
+                for (int i = 0; i < 10; i++) {
+                    robot.mouseMove(gcBounds.width / 2 - (int) (r.nextDouble() * multier), gcBounds.height / 2 - (int) (r.nextDouble() * multier));
+                }
+                robot.mouseRelease(InputEvent.BUTTON1_MASK);
+
+                toolkit.realSync();
+
+            } catch (AWTException e) {
+                throw new RuntimeException("Test Failed. AWTException thrown." + e.getMessage());
+            } catch (Exception e) {
+                e.printStackTrace();
+                throw new RuntimeException("Test Failed.");
+            }
+            System.out.println("Mouse  lies in " + MouseInfo.getPointerInfo().getLocation());
+            boolean frameIsOutOfScreen = false;
+            try {
+                setNewFrameLocationEDT();
+                System.out.println("Now Frame lies in " + newFrameLocation);
+                frameIsOutOfScreen = checkFrameIsOutOfScreenEDT();
+            } catch (Exception ex) {
+                ex.printStackTrace();
+                throw new RuntimeException("Test Failed.");
+            }
+
+            if (frameIsOutOfScreen) {
+                throw new RuntimeException("Test failed. JFrame is out of screen.");
+            }
+
+        } //for iteration
+        System.out.println("Test passed.");
+    }// start()
+
+    private void createAndShowGUI() {
+        try {
+            UIManager.setLookAndFeel(
+                    "javax.swing.plaf.metal.MetalLookAndFeel");
+        } catch (Exception ex) {
+            throw new RuntimeException(ex.getMessage());
+        }
+        JFrame.setDefaultLookAndFeelDecorated(true);
+        frame = new JFrame("JFrame Dance Test");
+        frame.pack();
+        frame.setSize(450, 260);
+        frame.setVisible(true);
+    }
+
+    private void setJLayeredPaneEDT() throws Exception {
+
+        SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
+            public void run() {
+                lPane = frame.getLayeredPane();
+                System.out.println("JFrame's LayeredPane " + lPane);
+            }
+        });
+    }
+
+    private void setTitleComponentEDT() throws Exception {
+
+        SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
+            public void run() {
+                for (int j = 0; j < lPane.getComponentsInLayer(JLayeredPane.FRAME_CONTENT_LAYER.intValue()).length; j++) {
+                    titleComponent = lPane.getComponentsInLayer(JLayeredPane.FRAME_CONTENT_LAYER.intValue())[j];
+                    if (titleComponent.getClass().getName().equals("javax.swing.plaf.metal.MetalTitlePane")) {
+                        titleFound = true;
+                        break;
+                    }
+                }
+            }
+        });
+    }
+
+    private void setFramePosEDT() throws Exception {
+
+        SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
+            public void run() {
+                framePosition = frame.getLocationOnScreen();
+            }
+        });
+    }
+
+    private boolean checkFrameIsOutOfScreenEDT() throws Exception {
+
+        final boolean[] result = new boolean[1];
+
+        SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
+            public void run() {
+                if (newFrameLocation.x > gcBounds.width || newFrameLocation.x < 0
+                    || newFrameLocation.y > gcBounds.height || newFrameLocation.y
+                    < 0) {
+                result[0] = true;
+            }
+            }
+        });
+        return result[0];
+    }
+
+    private void setNewFrameLocationEDT() throws Exception {
+
+        SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
+            public void run() {
+                newFrameLocation = new Point(frame.getLocationOnScreen().x
+                        + frame.getWidth() / 2, frame.getLocationOnScreen().y + titleComponent.getHeight() / 2);
+            }
+        });
+    }
+
+    private int getJFrameWidthEDT() throws Exception {
+
+        final int[] result = new int[1];
+
+        SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
+            public void run() {
+                result[0] = frame.getWidth();
+            }
+        });
+
+        return result[0];
+    }
+}// class
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/java2d/cmm/ColorConvertOp/GrayTest.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug     7124245
+ * @summary Test verifies that color conversion does not distort
+ *          colors in destination image of standard type.
+ *
+ * @run main GrayTest
+ */
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.color.ColorSpace;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorConvertOp;
+
+public class GrayTest {
+    public static void main(String[] args) {
+        GrayTest t = new GrayTest();
+
+        t.doTest(BufferedImage.TYPE_INT_RGB);
+        t.doTest(BufferedImage.TYPE_INT_BGR);
+        t.doTest(BufferedImage.TYPE_INT_ARGB);
+        t.doTest(BufferedImage.TYPE_3BYTE_BGR);
+        t.doTest(BufferedImage.TYPE_4BYTE_ABGR);
+        System.out.println("Test passed.");
+    }
+
+    private static final int w = 3;
+    private static final int h = 3;
+
+    private BufferedImage src;
+    private BufferedImage dst;
+
+    private ColorConvertOp op;
+
+    public GrayTest() {
+        ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
+        op = new ColorConvertOp(cs, null);
+    }
+
+    private void render(Graphics2D g) {
+        g.setColor(Color.red);
+        g.fillRect(0, 0, w, h);
+    }
+
+    private BufferedImage initImage(int type) {
+        BufferedImage img = new BufferedImage(w, h, type);
+        Graphics2D g = img.createGraphics();
+
+        render(g);
+
+        g.dispose();
+
+        return img;
+    }
+
+    public void doTest(int type) {
+        System.out.println("Test for type: " + type);
+        src = initImage(type);
+
+        dst = initImage(type);
+
+        dst = op.filter(src, dst);
+
+        int pixel = dst.getRGB(1, 1);
+        int r = 0xff & (pixel >> 16);
+        int g = 0xff & (pixel >>  8);
+        int b = 0xff & (pixel      );
+
+        System.out.printf("dst: r:%02x, g: %02x, %02x\n",
+                r, g, b);
+
+        if (r != g || r != b) {
+            String msg = String.format("Invalid pixel: %08x", pixel);
+            throw new RuntimeException(msg);
+        }
+        System.out.println("Done.");
+    }
+}
--- a/jdk/test/sun/management/jmxremote/startstop/JMXStartStopDoSomething.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/sun/management/jmxremote/startstop/JMXStartStopDoSomething.java	Wed Jul 05 18:34:47 2017 +0200
@@ -41,7 +41,7 @@
                     System.err.println("Lock is too old. Aborting");
                     return;
                 }
-                Thread.sleep(1);
+                Thread.sleep(500);
             }
 
         } catch (Throwable e) {
--- a/jdk/test/sun/management/jmxremote/startstop/JMXStartStopTest.sh	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/sun/management/jmxremote/startstop/JMXStartStopTest.sh	Wed Jul 05 18:34:47 2017 +0200
@@ -43,7 +43,7 @@
 
 _compile(){
 
-    if [ ! -e ${_testclasses} ]
+    if [ ! -d ${_testclasses} ]
     then
       mkdir -p ${_testclasses} 
     fi   
@@ -53,7 +53,7 @@
     # Compile testcase
     ${TESTJAVA}/bin/javac -d ${_testclasses} JMXStartStopDoSomething.java JMXStartStopTest.java 
 
-    if [ ! -e ${_testclasses}/JMXStartStopTest.class ]
+    if [ ! -f ${_testclasses}/JMXStartStopTest.class ]
     then
       echo "ERROR: Can't compile"
       exit -1
@@ -63,15 +63,22 @@
 _app_start(){
   ${TESTJAVA}/bin/java ${TESTVMOPTS} $* -cp ${_testclasses} JMXStartStopDoSomething  >> ${_logname} 2>&1 &
 
-  npid=`_get_pid`
-  if [ "${npid}" = "" ]
-  then
-     echo "ERROR: Test app not started"
-     if [ "${_jtreg}" = "yes" ]
+  x=0
+  while [ ! -f ${_lockFileName} ]
+  do
+     if [ $x -gt 20 ]
      then
-       exit -1
-     fi  
-  fi
+        echo "ERROR: Test app not started"
+        if [ "${_jtreg}" = "yes" ]
+        then
+           exit -1
+        fi   
+     fi    
+        
+     echo "Waiting JMXStartStopDoSomething to start: $x"
+     x=`expr $x + 1`
+     sleep 1
+  done
 }
 
 _get_pid(){
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/net/www/http/KeepAliveStream/InfiniteLoop.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8004863
+ * @summary Checks for proper close code in KeepAliveStream
+ */
+
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpServer;
+import java.io.*;
+import java.net.*;
+import java.util.concurrent.Phaser;
+
+// Racey test, will not always fail, but if it does then we have a problem.
+
+public class InfiniteLoop {
+
+    public static void main(String[] args) throws Exception {
+        HttpServer server = HttpServer.create(new InetSocketAddress(0), 0);
+        server.createContext("/test/InfiniteLoop", new RespHandler());
+        server.start();
+        try {
+            InetSocketAddress address = server.getAddress();
+            URL url = new URL("http://localhost:" + address.getPort()
+                              + "/test/InfiniteLoop");
+            final Phaser phaser = new Phaser(2);
+            for (int i=0; i<10; i++) {
+                HttpURLConnection uc = (HttpURLConnection)url.openConnection();
+                final InputStream is = uc.getInputStream();
+                final Thread thread = new Thread() {
+                    public void run() {
+                        try {
+                            phaser.arriveAndAwaitAdvance();
+                            while (is.read() != -1)
+                                Thread.sleep(50);
+                        } catch (Exception x) { x.printStackTrace(); }
+                    }};
+                thread.start();
+                phaser.arriveAndAwaitAdvance();
+                is.close();
+                System.out.println("returned from close");
+                thread.join();
+            }
+        } finally {
+            server.stop(0);
+        }
+    }
+
+    static class RespHandler implements HttpHandler {
+        static final int RESP_LENGTH = 32 * 1024;
+        @Override
+        public void handle(HttpExchange t) throws IOException {
+            InputStream is  = t.getRequestBody();
+            byte[] ba = new byte[8192];
+            while(is.read(ba) != -1);
+
+            t.sendResponseHeaders(200, RESP_LENGTH);
+            try (OutputStream os = t.getResponseBody()) {
+                os.write(new byte[RESP_LENGTH]);
+            }
+            t.close();
+        }
+    }
+}
--- a/jdk/test/sun/rmi/runtime/Log/6409194/NoConsoleOutput.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/sun/rmi/runtime/Log/6409194/NoConsoleOutput.java	Wed Jul 05 18:34:47 2017 +0200
@@ -64,7 +64,7 @@
         // (neither on standard output, nor on standard err streams).
         JavaVM vm = new JavaVM(DoRMIStuff.class.getName(),
             "-Djava.util.logging.config.file=" + loggingPropertiesFile,
-                               "", out, err, false);
+                               "", out, err);
         vm.start();
         vm.getVM().waitFor();
 
--- a/jdk/test/sun/security/krb5/auto/DynamicKeytab.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/sun/security/krb5/auto/DynamicKeytab.java	Wed Jul 05 18:34:47 2017 +0200
@@ -110,11 +110,13 @@
             throw new Exception("Should not success");
         } catch (GSSException gsse) {
             System.out.println(gsse);
-            KrbException ke = (KrbException)gsse.getCause();
-            if (ke.returnCode() != Krb5.KRB_AP_ERR_BADKEYVER) {
-                throw new Exception("Not expected failure code: " +
-                        ke.returnCode());
-            }
+            // Since 7197159, different kvno is accepted, this return code
+            // will never be thrown out again.
+            //KrbException ke = (KrbException)gsse.getCause();
+            //if (ke.returnCode() != Krb5.KRB_AP_ERR_BADKEYVER) {
+            //    throw new Exception("Not expected failure code: " +
+            //            ke.returnCode());
+            //}
         }
 
         // Test 8: an empty KDC means revoke all
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/krb5/auto/KvnoNA.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 7197159
+ * @compile -XDignore.symbol.file KvnoNA.java
+ * @run main/othervm KvnoNA
+ * @summary accept different kvno if there no match
+ */
+
+import org.ietf.jgss.GSSException;
+import sun.security.jgss.GSSUtil;
+import sun.security.krb5.KrbException;
+import sun.security.krb5.PrincipalName;
+import sun.security.krb5.internal.ktab.KeyTab;
+import sun.security.krb5.internal.Krb5;
+
+public class KvnoNA {
+
+    public static void main(String[] args)
+            throws Exception {
+
+        OneKDC kdc = new OneKDC(null);
+        kdc.writeJAASConf();
+
+        // In KDC, it's 2
+        char[] pass = "pass2".toCharArray();
+        kdc.addPrincipal(OneKDC.SERVER, pass);
+
+        // In ktab, kvno is 1 or 3, 3 has the same password
+        KeyTab ktab = KeyTab.create(OneKDC.KTAB);
+        PrincipalName p = new PrincipalName(
+            OneKDC.SERVER+"@"+OneKDC.REALM, PrincipalName.KRB_NT_SRV_HST);
+        ktab.addEntry(p, "pass1".toCharArray(), 1, true);
+        ktab.addEntry(p, "pass2".toCharArray(), 3, true);
+        ktab.save();
+
+        Context c, s;
+
+        c = Context.fromUserPass("dummy", "bogus".toCharArray(), false);
+        s = Context.fromJAAS("server");
+
+        c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID);
+        s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID);
+
+        Context.handshake(c, s);
+
+        s.dispose();
+        c.dispose();
+    }
+}
--- a/jdk/test/sun/security/krb5/auto/MoreKvno.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/sun/security/krb5/auto/MoreKvno.java	Wed Jul 05 18:34:47 2017 +0200
@@ -23,8 +23,7 @@
 
 /*
  * @test
- * @bug 6893158
- * @bug 6907425
+ * @bug 6893158 6907425 7197159
  * @run main/othervm MoreKvno
  * @summary AP_REQ check should use key version number
  */
@@ -69,11 +68,13 @@
             go(OneKDC.SERVER, "com.sun.security.jgss.krb5.accept", pass);
             throw new Exception("This test should fail");
         } catch (GSSException gsse) {
-            KrbException ke = (KrbException)gsse.getCause();
-            if (ke.returnCode() != Krb5.KRB_AP_ERR_BADKEYVER) {
-                throw new Exception("Not expected failure code: " +
-                        ke.returnCode());
-            }
+            // Since 7197159, different kvno is accepted, this return code
+            // will never be thrown out again.
+            //KrbException ke = (KrbException)gsse.getCause();
+            //if (ke.returnCode() != Krb5.KRB_AP_ERR_BADKEYVER) {
+            //    throw new Exception("Not expected failure code: " +
+            //            ke.returnCode());
+            //}
         }
     }
 
--- a/jdk/test/sun/security/provider/certpath/DisabledAlgorithms/CPBuilder.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/sun/security/provider/certpath/DisabledAlgorithms/CPBuilder.java	Wed Jul 05 18:34:47 2017 +0200
@@ -21,6 +21,9 @@
  * questions.
  */
 
+// This test case relies on updated static security property, no way to re-use
+// security property in samevm/agentvm mode.
+
 /**
  * @test
  *
@@ -392,6 +395,9 @@
     }
 
     public static void main(String args[]) throws Exception {
+        // reset the security property to make sure that the algorithms
+        // and keys used in this test are not disabled.
+        Security.setProperty("jdk.certpath.disabledAlgorithms", "MD2");
 
         CertPathBuilder builder = CertPathBuilder.getInstance("PKIX");
 
--- a/jdk/test/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorEndEntity.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorEndEntity.java	Wed Jul 05 18:34:47 2017 +0200
@@ -21,6 +21,9 @@
  * questions.
  */
 
+// This test case relies on updated static security property, no way to re-use
+// security property in samevm/agentvm mode.
+
 /**
  * @test
  *
@@ -28,7 +31,7 @@
  * @summary Disable MD2 support.
  *          New CertPathValidatorException.BasicReason enum constant for
  *     constrained algorithm.
- *
+ * @run main/othervm CPValidatorEndEntity
  * @author Xuelei Fan
  */
 
@@ -313,6 +316,10 @@
     }
 
     public static void main(String args[]) throws Exception {
+        // reset the security property to make sure that the algorithms
+        // and keys used in this test are not disabled.
+        Security.setProperty("jdk.certpath.disabledAlgorithms", "MD2");
+
         try {
             validate(endentiry_SHA1withRSA_1024_1024,
                                     intermediate_SHA1withRSA_1024_1024);
--- a/jdk/test/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorIntermediate.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorIntermediate.java	Wed Jul 05 18:34:47 2017 +0200
@@ -21,6 +21,9 @@
  * questions.
  */
 
+// This test case relies on updated static security property, no way to re-use
+// security property in samevm/agentvm mode.
+
 /**
  * @test
  *
@@ -28,7 +31,7 @@
  * @summary Disable MD2 support
  *          new CertPathValidatorException.BasicReason enum constant for
  *     constrained algorithm
- *
+ * @run main/othervm CPValidatorIntermediate
  * @author Xuelei Fan
  */
 
@@ -212,6 +215,10 @@
     }
 
     public static void main(String args[]) throws Exception {
+        // reset the security property to make sure that the algorithms
+        // and keys used in this test are not disabled.
+        Security.setProperty("jdk.certpath.disabledAlgorithms", "MD2");
+
         try {
             validate(intermediate_SHA1withRSA_1024_1024);
             validate(intermediate_SHA1withRSA_1024_512);
--- a/jdk/test/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorTrustAnchor.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorTrustAnchor.java	Wed Jul 05 18:34:47 2017 +0200
@@ -21,6 +21,9 @@
  * questions.
  */
 
+// This test case relies on updated static security property, no way to re-use
+// security property in samevm/agentvm mode.
+
 /**
  * @test
  *
@@ -28,7 +31,7 @@
  * @summary Disable MD2 support
  *          new CertPathValidatorException.BasicReason enum constant for
  *     constrained algorithm
- *
+ * @run main/othervm CPValidatorTrustAnchor
  * @author Xuelei Fan
  */
 
@@ -133,6 +136,10 @@
     }
 
     public static void main(String args[]) throws Exception {
+        // reset the security property to make sure that the algorithms
+        // and keys used in this test are not disabled.
+        Security.setProperty("jdk.certpath.disabledAlgorithms", "MD2");
+
         try {
             validate(trustAnchor_SHA1withRSA_1024);
             validate(trustAnchor_SHA1withRSA_512);
--- a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/ClientHandshaker/RSAExport.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/ClientHandshaker/RSAExport.java	Wed Jul 05 18:34:47 2017 +0200
@@ -21,14 +21,14 @@
  * questions.
  */
 
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
 /*
  * @test
  * @bug 6690018
  * @summary RSAClientKeyExchange NullPointerException
  * @run main/othervm RSAExport
- *
- *     SunJSSE does not support dynamic system properties, no way to re-use
- *     system properties in samevm/agentvm mode.
  */
 
 /*
@@ -199,6 +199,7 @@
 
 import java.io.*;
 import java.net.*;
+import java.security.Security;
 import java.security.KeyStore;
 import java.security.KeyFactory;
 import java.security.cert.Certificate;
@@ -415,6 +416,10 @@
     volatile Exception clientException = null;
 
     public static void main(String[] args) throws Exception {
+        // reset the security property to make sure that the algorithms
+        // and keys used in this test are not disabled.
+        Security.setProperty("jdk.certpath.disabledAlgorithms", "MD2");
+
         if (debug)
             System.setProperty("javax.net.debug", "all");
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/ssl/javax/net/ssl/TLSv12/DisabledShortRSAKeys.java	Wed Jul 05 18:34:47 2017 +0200
@@ -0,0 +1,433 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 7109274
+ * @summary Consider disabling support for X.509 certificates with RSA keys
+ *          less than 1024 bits
+ *
+ * @run main/othervm DisabledShortRSAKeys PKIX TLSv1.2
+ * @run main/othervm DisabledShortRSAKeys SunX509 TLSv1.2
+ * @run main/othervm DisabledShortRSAKeys PKIX TLSv1.1
+ * @run main/othervm DisabledShortRSAKeys SunX509 TLSv1.1
+ * @run main/othervm DisabledShortRSAKeys PKIX TLSv1
+ * @run main/othervm DisabledShortRSAKeys SunX509 TLSv1
+ * @run main/othervm DisabledShortRSAKeys PKIX SSLv3
+ * @run main/othervm DisabledShortRSAKeys SunX509 SSLv3
+ */
+
+import java.net.*;
+import java.util.*;
+import java.io.*;
+import javax.net.ssl.*;
+import java.security.Security;
+import java.security.KeyStore;
+import java.security.KeyFactory;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.spec.*;
+import java.security.interfaces.*;
+import sun.misc.BASE64Decoder;
+
+
+public class DisabledShortRSAKeys {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = true;
+
+    /*
+     * Where do we find the keystores?
+     */
+    // Certificates and key used in the test.
+    static String trustedCertStr =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIICkjCCAfugAwIBAgIBADANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" +
+        "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
+        "MTEwODE5MDE1MjE5WhcNMzIwNzI5MDE1MjE5WjA7MQswCQYDVQQGEwJVUzENMAsG\n" +
+        "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwgZ8wDQYJ\n" +
+        "KoZIhvcNAQEBBQADgY0AMIGJAoGBAM8orG08DtF98TMSscjGsidd1ZoN4jiDpi8U\n" +
+        "ICz+9dMm1qM1d7O2T+KH3/mxyox7Rc2ZVSCaUD0a3CkhPMnlAx8V4u0H+E9sqso6\n" +
+        "iDW3JpOyzMExvZiRgRG/3nvp55RMIUV4vEHOZ1QbhuqG4ebN0Vz2DkRft7+flthf\n" +
+        "vDld6f5JAgMBAAGjgaUwgaIwHQYDVR0OBBYEFLl81dnfp0wDrv0OJ1sxlWzH83Xh\n" +
+        "MGMGA1UdIwRcMFqAFLl81dnfp0wDrv0OJ1sxlWzH83XhoT+kPTA7MQswCQYDVQQG\n" +
+        "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" +
+        "Y2WCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEE\n" +
+        "BQADgYEALlgaH1gWtoBZ84EW8Hu6YtGLQ/L9zIFmHonUPZwn3Pr//icR9Sqhc3/l\n" +
+        "pVTxOINuFHLRz4BBtEylzRIOPzK3tg8XwuLb1zd0db90x3KBCiAL6E6cklGEPwLe\n" +
+        "XYMHDn9eDsaq861Tzn6ZwzMgw04zotPMoZN0mVd/3Qca8UJFucE=\n" +
+        "-----END CERTIFICATE-----";
+
+    static String targetCertStr =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIICNDCCAZ2gAwIBAgIBDDANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" +
+        "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
+        "MTExMTA3MTM1NTUyWhcNMzEwNzI1MTM1NTUyWjBPMQswCQYDVQQGEwJVUzENMAsG\n" +
+        "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxEjAQBgNV\n" +
+        "BAMTCWxvY2FsaG9zdDBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQC3Pb49OSPfOD2G\n" +
+        "HSXFCFx1GJEZfqG9ZUf7xuIi/ra5dLjPGAaoY5QF2QOa8VnOriQCXDfyXHxsuRnE\n" +
+        "OomxL7EVAgMBAAGjeDB2MAsGA1UdDwQEAwID6DAdBgNVHQ4EFgQUXNCJK3/dtCIc\n" +
+        "xb+zlA/JINlvs/MwHwYDVR0jBBgwFoAUuXzV2d+nTAOu/Q4nWzGVbMfzdeEwJwYD\n" +
+        "VR0lBCAwHgYIKwYBBQUHAwEGCCsGAQUFBwMCBggrBgEFBQcDAzANBgkqhkiG9w0B\n" +
+        "AQQFAAOBgQB2qIDUxA2caMPpGtUACZAPRUtrGssCINIfItETXJZCx/cRuZ5sP4D9\n" +
+        "N1acoNDn0hCULe3lhXAeTC9NZ97680yJzregQMV5wATjo1FGsKY30Ma+sc/nfzQW\n" +
+        "+h/7RhYtoG0OTsiaDCvyhI6swkNJzSzrAccPY4+ZgU8HiDLzZTmM3Q==\n" +
+        "-----END CERTIFICATE-----";
+
+    // Private key in the format of PKCS#8, key size is 512 bits.
+    static String targetPrivateKey =
+        "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAtz2+PTkj3zg9hh0l\n" +
+        "xQhcdRiRGX6hvWVH+8biIv62uXS4zxgGqGOUBdkDmvFZzq4kAlw38lx8bLkZxDqJ\n" +
+        "sS+xFQIDAQABAkByx/5Oo2hQ/w2q4L8z+NTRlJ3vdl8iIDtC/4XPnfYfnGptnpG6\n" +
+        "ZThQRvbMZiai0xHQPQMszvAHjZVme1eDl3EBAiEA3aKJHynPVCEJhpfCLWuMwX5J\n" +
+        "1LntwJO7NTOyU5m8rPECIQDTpzn5X44r2rzWBDna/Sx7HW9IWCxNgUD2Eyi2nA7W\n" +
+        "ZQIgJerEorw4aCAuzQPxiGu57PB6GRamAihEAtoRTBQlH0ECIQDN08FgTtnesgCU\n" +
+        "DFYLLcw1CiHvc7fZw4neBDHCrC8NtQIgA8TOUkGnpCZlQ0KaI8KfKWI+vxFcgFnH\n" +
+        "3fnqsTgaUs4=";
+
+    static char passphrase[] = "passphrase".toCharArray();
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide() throws Exception {
+        SSLContext context = generateSSLContext(null, targetCertStr,
+                                            targetPrivateKey);
+        SSLServerSocketFactory sslssf = context.getServerSocketFactory();
+        SSLServerSocket sslServerSocket =
+            (SSLServerSocket)sslssf.createServerSocket(serverPort);
+        serverPort = sslServerSocket.getLocalPort();
+
+        /*
+         * Signal Client, we're ready for his connect.
+         */
+        serverReady = true;
+
+        try (SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept()) {
+            InputStream sslIS = sslSocket.getInputStream();
+            OutputStream sslOS = sslSocket.getOutputStream();
+
+            sslIS.read();
+            sslOS.write('A');
+            sslOS.flush();
+
+            throw new Exception(
+                    "RSA keys shorter than 1024 bits should be disabled");
+        } catch (SSLHandshakeException sslhe) {
+            // the expected exception, ignore
+        }
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        SSLContext context = generateSSLContext(trustedCertStr, null, null);
+        SSLSocketFactory sslsf = context.getSocketFactory();
+
+        try (SSLSocket sslSocket =
+            (SSLSocket)sslsf.createSocket("localhost", serverPort)) {
+
+            // only enable the target protocol
+            sslSocket.setEnabledProtocols(new String[] {enabledProtocol});
+
+            // enable a block cipher
+            sslSocket.setEnabledCipherSuites(
+                new String[] {"TLS_DHE_RSA_WITH_AES_128_CBC_SHA"});
+
+            InputStream sslIS = sslSocket.getInputStream();
+            OutputStream sslOS = sslSocket.getOutputStream();
+
+            sslOS.write('B');
+            sslOS.flush();
+            sslIS.read();
+
+            throw new Exception(
+                    "RSA keys shorter than 1024 bits should be disabled");
+        } catch (SSLHandshakeException sslhe) {
+            // the expected exception, ignore
+        }
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+    private static String tmAlgorithm;        // trust manager
+    private static String enabledProtocol;    // the target protocol
+
+    private static void parseArguments(String[] args) {
+        tmAlgorithm = args[0];
+        enabledProtocol = args[1];
+    }
+
+    private static SSLContext generateSSLContext(String trustedCertStr,
+            String keyCertStr, String keySpecStr) throws Exception {
+
+        // generate certificate from cert string
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+
+        // create a key store
+        KeyStore ks = KeyStore.getInstance("JKS");
+        ks.load(null, null);
+
+        // import the trused cert
+        Certificate trusedCert = null;
+        ByteArrayInputStream is = null;
+        if (trustedCertStr != null) {
+            is = new ByteArrayInputStream(trustedCertStr.getBytes());
+            trusedCert = cf.generateCertificate(is);
+            is.close();
+
+            ks.setCertificateEntry("RSA Export Signer", trusedCert);
+        }
+
+        if (keyCertStr != null) {
+            // generate the private key.
+            PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
+                                new BASE64Decoder().decodeBuffer(keySpecStr));
+            KeyFactory kf = KeyFactory.getInstance("RSA");
+            RSAPrivateKey priKey =
+                    (RSAPrivateKey)kf.generatePrivate(priKeySpec);
+
+            // generate certificate chain
+            is = new ByteArrayInputStream(keyCertStr.getBytes());
+            Certificate keyCert = cf.generateCertificate(is);
+            is.close();
+
+            Certificate[] chain = null;
+            if (trusedCert != null) {
+                chain = new Certificate[2];
+                chain[0] = keyCert;
+                chain[1] = trusedCert;
+            } else {
+                chain = new Certificate[1];
+                chain[0] = keyCert;
+            }
+
+            // import the key entry.
+            ks.setKeyEntry("Whatever", priKey, passphrase, chain);
+        }
+
+        // create SSL context
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm);
+        tmf.init(ks);
+
+        SSLContext ctx = SSLContext.getInstance("TLS");
+        if (keyCertStr != null && !keyCertStr.isEmpty()) {
+            KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
+            kmf.init(ks, passphrase);
+
+            ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+            ks = null;
+        } else {
+            ctx.init(null, tmf.getTrustManagers(), null);
+        }
+
+        return ctx;
+    }
+
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    public static void main(String[] args) throws Exception {
+        if (debug)
+            System.setProperty("javax.net.debug", "all");
+
+        /*
+         * Get the customized arguments.
+         */
+        parseArguments(args);
+
+        /*
+         * Start the tests.
+         */
+        new DisabledShortRSAKeys();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    DisabledShortRSAKeys() throws Exception {
+        try {
+            if (separateServerThread) {
+                startServer(true);
+                startClient(false);
+            } else {
+                startClient(true);
+                startServer(false);
+            }
+        } catch (Exception e) {
+            // swallow for now.  Show later
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            serverThread.join();
+        } else {
+            clientThread.join();
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         * Which side threw the error?
+         */
+        Exception local;
+        Exception remote;
+        String whichRemote;
+
+        if (separateServerThread) {
+            remote = serverException;
+            local = clientException;
+            whichRemote = "server";
+        } else {
+            remote = clientException;
+            local = serverException;
+            whichRemote = "client";
+        }
+
+        /*
+         * If both failed, return the curthread's exception, but also
+         * print the remote side Exception
+         */
+        if ((local != null) && (remote != null)) {
+            System.out.println(whichRemote + " also threw:");
+            remote.printStackTrace();
+            System.out.println();
+            throw local;
+        }
+
+        if (remote != null) {
+            throw remote;
+        }
+
+        if (local != null) {
+            throw local;
+        }
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            try {
+                doServerSide();
+            } catch (Exception e) {
+                serverException = e;
+            } finally {
+                serverReady = true;
+            }
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            try {
+                doClientSide();
+            } catch (Exception e) {
+                clientException = e;
+            }
+        }
+    }
+}
--- a/jdk/test/sun/security/ssl/javax/net/ssl/TLSv12/ShortRSAKey512.java	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/sun/security/ssl/javax/net/ssl/TLSv12/ShortRSAKey512.java	Wed Jul 05 18:34:47 2017 +0200
@@ -23,6 +23,9 @@
  * questions.
  */
 
+// This test case relies on updated static security property, no way to re-use
+// security property in samevm/agentvm mode.
+
 /*
  * @test
  * @bug 7106773
@@ -38,6 +41,7 @@
 import java.util.*;
 import java.io.*;
 import javax.net.ssl.*;
+import java.security.Security;
 import java.security.KeyStore;
 import java.security.KeyFactory;
 import java.security.cert.Certificate;
@@ -275,6 +279,10 @@
     volatile Exception clientException = null;
 
     public static void main(String[] args) throws Exception {
+        // reset the security property to make sure that the algorithms
+        // and keys used in this test are not disabled.
+        Security.setProperty("jdk.certpath.disabledAlgorithms", "MD2");
+
         if (debug)
             System.setProperty("javax.net.debug", "all");
 
--- a/jdk/test/sun/security/tools/jarsigner/concise_jarsigner.sh	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/sun/security/tools/jarsigner/concise_jarsigner.sh	Wed Jul 05 18:34:47 2017 +0200
@@ -44,10 +44,10 @@
     ;;
 esac
 
-# Choose 512-bit RSA to make sure it runs fine and fast on all platforms. In fact,
-# every keyalg/keysize combination is OK for this test.
+# Choose 1024-bit RSA to make sure it runs fine and fast on all platforms. In
+# fact, every keyalg/keysize combination is OK for this test.
 
-KT="$TESTJAVA${FS}bin${FS}keytool -storepass changeit -keypass changeit -keystore js.jks -keyalg rsa -keysize 512"
+KT="$TESTJAVA${FS}bin${FS}keytool -storepass changeit -keypass changeit -keystore js.jks -keyalg rsa -keysize 1024"
 JAR=$TESTJAVA${FS}bin${FS}jar
 JARSIGNER=$TESTJAVA${FS}bin${FS}jarsigner
 JAVAC=$TESTJAVA${FS}bin${FS}javac
--- a/jdk/test/sun/tools/jrunscript/common.sh	Fri Dec 28 18:39:09 2012 -0800
+++ b/jdk/test/sun/tools/jrunscript/common.sh	Wed Jul 05 18:34:47 2017 +0200
@@ -63,8 +63,4 @@
     JRUNSCRIPT="${TESTJAVA}/bin/jrunscript"
     JAVAC="${TESTJAVA}/bin/javac"
     JAVA="${TESTJAVA}/bin/java"
-    # needed to get full headless behavior on Mac
-    if [ "$OS" = "Darwin" ]; then
-        export AWT_TOOLKIT=XToolkit
-    fi
 }