Merge jdk8-b71
authorduke
Wed, 05 Jul 2017 18:34:52 +0200
changeset 14968 a41ada2ed4ef
parent 14967 a3f11e8a60ae (diff)
parent 14874 8cfff77c5990 (current diff)
child 14969 67ab2e8b974a
child 14970 a521fc006ff6
child 14971 371ef2925907
child 14973 21fe12436601
child 14975 e927c8725ba4
child 14977 c65f0fb0d9de
child 14979 1cd43fe99320
child 14981 e905c5894743
child 14987 071cd56ff1ed
child 14992 e9db4be29324
child 14996 421c63041fe6
child 15033 acc6a1f8bd37
child 15077 9f187c910f83
child 15346 3f6fd93fec9a
Merge
--- a/.hgtags-top-repo	Wed Jul 05 18:33:59 2017 +0200
+++ b/.hgtags-top-repo	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/common/makefiles/javadoc/NON_CORE_PKGS.gmk	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/corba/.hgtags	Wed Jul 05 18:34:52 2017 +0200
@@ -191,3 +191,4 @@
 394515ad2a55d4d54df990b36065505d3e7a3cbb jdk8-b67
 82000531feaa7baef76b6406099e5cd88943d635 jdk8-b68
 22ddcac208a8dea894a16887d04f3ca4d3c5d267 jdk8-b69
+603cceb495c8133d47b26a7502d51c7d8a67d76b jdk8-b70
--- a/hotspot/.hgtags	Wed Jul 05 18:33:59 2017 +0200
+++ b/hotspot/.hgtags	Wed Jul 05 18:34:52 2017 +0200
@@ -303,3 +303,4 @@
 b6c9c0109a608eedbb6b868d260952990e3c91fe hs25-b13
 cb8a4e04bc8c104de8a2f67463c7e31232bf8d68 jdk8-b69
 990bbd393c239d95310ccc38094e57923bbf1d4a hs25-b14
+e94068d4ff52849c8aa0786a53a59b63d1312a39 jdk8-b70
--- a/jaxp/.hgtags	Wed Jul 05 18:33:59 2017 +0200
+++ b/jaxp/.hgtags	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jaxp/src/com/sun/org/apache/xalan/internal/xslt/EnvironmentCheck.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jaxp/src/com/sun/org/apache/xerces/internal/impl/Version.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jaxp/src/com/sun/org/apache/xerces/internal/impl/XMLDocumentFragmentScannerImpl.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jaxp/src/com/sun/org/apache/xerces/internal/impl/XMLEntityScanner.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jaxp/src/javax/xml/transform/FactoryFinder.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jaxp/src/javax/xml/validation/SchemaFactoryFinder.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jaxp/src/javax/xml/xpath/XPathFactoryFinder.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jaxws/.hgtags	Wed Jul 05 18:34:52 2017 +0200
@@ -191,3 +191,4 @@
 eb06aa51dfc225614dba2d89ae7ca6cedddff982 jdk8-b67
 d3fe408f3a9ad250bc9a4e9365bdfc3f28c1d3f4 jdk8-b68
 756323c990115a9c0341d67b10f2d52c6370e35d jdk8-b69
+3b1c2733d47ee9f8c530925df4041c59f9ee5a31 jdk8-b70
--- a/jdk/.hgtags	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/.hgtags	Wed Jul 05 18:34:52 2017 +0200
@@ -191,3 +191,4 @@
 ce9b02a3a17edd1983201002cfa0f364e4ab7524 jdk8-b67
 53fb43e4d614c92310e1fb00ec41d1960fd9facf jdk8-b68
 a8012d8d7e9c5035de0bdd4887dc9f7c54008f21 jdk8-b69
+a996b57e554198f4592a5f3c30f2f9f4075e545d jdk8-b70
--- a/jdk/make/common/Release.gmk	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/make/common/Release.gmk	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/make/common/internal/Defs-langtools.gmk	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/make/docs/NON_CORE_PKGS.gmk	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/make/java/java/FILES_java.gmk	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/make/jdk/Makefile	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ /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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/make/netbeans/jmx/build.properties	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/makefiles/CreateJars.gmk	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CEmbeddedFrame.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/com/sun/jmx/remote/internal/ClientCommunicatorAdmin.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/com/sun/jmx/remote/internal/IIOPHelper.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/com/sun/security/auth/login/ConfigFile.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/java/beans/DefaultPersistenceDelegate.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/java/beans/EventSetDescriptor.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/java/beans/MethodDescriptor.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/java/beans/Statement.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/java/lang/Class.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/java/lang/reflect/Constructor.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/java/lang/reflect/Executable.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/java/lang/reflect/Field.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/java/lang/reflect/Member.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/java/lang/reflect/Method.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/java/net/URLConnection.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/java/util/Arrays.java	Wed Jul 05 18:34:52 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:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/java/util/Calendar.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/java/util/Properties.java	Wed Jul 05 18:34:52 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:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/java/util/concurrent/ForkJoinPool.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/java/util/concurrent/ForkJoinTask.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/java/util/concurrent/ForkJoinWorkerThread.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/javax/management/MBeanFeatureInfo.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/javax/management/MBeanInfo.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/javax/management/remote/JMXConnectorFactory.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/javax/management/remote/JMXConnectorServerFactory.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/javax/management/remote/rmi/RMIConnector.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/javax/management/remote/rmi/RMIConnectorServer.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/javax/management/remote/rmi/package.html	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/javax/security/auth/kerberos/package.html	Wed Jul 05 18:34:52 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:52 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:52 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:52 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:52 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:52 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:52 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:52 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:52 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:52 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:52 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:52 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:52 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:52 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:52 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:52 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:52 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:52 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:52 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:52 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:52 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:52 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:52 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:52 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:52 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:52 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:52 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:52 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:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMS.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/sun/net/www/http/KeepAliveStream.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/sun/security/krb5/EncryptionKey.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/sun/security/provider/ConfigSpiFile.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/sun/text/bidi/BidiBase.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNamesBundle.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/demo/java2d/J2DBench/build.xml	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/demo/java2d/J2DBench/src/j2dbench/J2DBench.java	Wed Jul 05 18:34:52 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:52 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:52 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:52 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:52 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:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/lib/security/java.security-linux	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/lib/security/java.security-macosx	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/lib/security/java.security-solaris	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/lib/security/java.security-windows	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/solaris/classes/sun/awt/X11/XBaseWindow.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/solaris/classes/sun/awt/X11/XConstants.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/solaris/classes/sun/awt/X11/XToolkit.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/solaris/classes/sun/awt/X11/XWindow.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/solaris/classes/sun/awt/X11/XlibUtil.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/src/windows/native/sun/windows/awt_Debug.cpp	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/ProblemList.txt	Wed Jul 05 18:34:52 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:52 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:52 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:52 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:52 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:52 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:52 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:52 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:52 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:52 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:52 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:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/java/io/Serializable/resolveProxyClass/NonPublicInterface.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/java/lang/Throwable/LegacyChainedExceptionSerialization.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/java/lang/management/CompilationMXBean/Basic.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/java/lang/reflect/Generics/Probe.java	Wed Jul 05 18:34:52 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:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/java/lang/reflect/Proxy/ClassRestrictions.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/java/rmi/testlibrary/JavaVM.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/java/rmi/testlibrary/StreamPipe.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/java/security/cert/CertPathBuilder/targetConstraints/BuildEEBasicConstraints.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/java/security/cert/pkix/policyChanges/TestPolicy.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/java/text/Bidi/BidiConformance.java	Wed Jul 05 18:34:52 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:52 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:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/java/util/Collections/EmptyIterator.java	Wed Jul 05 18:34:52 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:52 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:52 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:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/java/util/Properties/LoadAndStoreXML.java	Wed Jul 05 18:34:52 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:52 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:52 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:52 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:52 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:52 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:52 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:52 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:52 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:52 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:52 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:52 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:52 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:52 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:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/java/util/logging/LoggingDeadlock4.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/java/util/prefs/PrefsSpi.sh	Wed Jul 05 18:34:52 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:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/javax/management/remote/mandatory/connection/AddressableTest.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/javax/management/remote/mandatory/connection/CloseableTest.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/javax/management/remote/mandatory/connection/ConnectionListenerNullTest.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/javax/management/remote/mandatory/connection/IIOPURLTest.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/javax/management/remote/mandatory/connection/IdleTimeoutTest.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/javax/management/remote/mandatory/connection/MultiThreadDeadLockTest.java	Wed Jul 05 18:34:52 2017 +0200
@@ -253,4 +253,3 @@
         System.out.println("===Leave the method: " + m);
     }
 }
-
--- a/jdk/test/javax/management/remote/mandatory/connectorServer/SetMBeanServerForwarder.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/javax/management/remote/mandatory/connectorServer/SetMBeanServerForwarder.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/javax/management/remote/mandatory/loading/MissingClassTest.java	Wed Jul 05 18:34:52 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:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/javax/management/remote/mandatory/provider/ProviderTest.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/javax/management/remote/mandatory/serverError/JMXServerErrorTest.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/javax/swing/AncestorNotifier/7193219/bug7193219.java	Wed Jul 05 18:34:52 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:52 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:52 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:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/sun/management/jmxremote/startstop/JMXStartStopDoSomething.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/sun/management/jmxremote/startstop/JMXStartStopTest.sh	Wed Jul 05 18:34:52 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:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/sun/rmi/runtime/Log/6409194/NoConsoleOutput.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/sun/security/krb5/auto/DynamicKeytab.java	Wed Jul 05 18:34:52 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:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/sun/security/krb5/auto/MoreKvno.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/sun/security/provider/certpath/DisabledAlgorithms/CPBuilder.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorEndEntity.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorIntermediate.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorTrustAnchor.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/ClientHandshaker/RSAExport.java	Wed Jul 05 18:34:52 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:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/sun/security/ssl/javax/net/ssl/TLSv12/ShortRSAKey512.java	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/sun/security/tools/jarsigner/concise_jarsigner.sh	Wed Jul 05 18:34:52 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	Wed Jul 05 18:33:59 2017 +0200
+++ b/jdk/test/sun/tools/jrunscript/common.sh	Wed Jul 05 18:34:52 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
 }
--- a/langtools/.hgtags	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/.hgtags	Wed Jul 05 18:34:52 2017 +0200
@@ -191,3 +191,4 @@
 303b09787a69136cd2019f9edfed3f308572e9fc jdk8-b67
 014a6a11dfe5ddc23ec8c76bb42ac998dbf49acb jdk8-b68
 d7360bf35ee1f40ff78c2e83a22b5446ee464346 jdk8-b69
+47f71d7c124f24c2fe2dfc49865b332345b458ed jdk8-b70
--- a/langtools/make/build.properties	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/make/build.properties	Wed Jul 05 18:34:52 2017 +0200
@@ -68,7 +68,7 @@
 # set the following to -version to verify the versions of javac being used
 javac.version.opt =
 # in time, there should be no exceptions to -Xlint:all
-javac.lint.opts = -Xlint:all,-deprecation -Werror
+javac.lint.opts = -Xlint:all -Werror
 
 # options for the <javadoc> task for javac
 #javadoc.jls3.url=http://java.sun.com/docs/books/jls/
@@ -117,7 +117,8 @@
         javax/lang/model/ \
         javax/tools/ \
         com/sun/source/ \
-        com/sun/tools/javac/
+        com/sun/tools/javac/ \
+        com/sun/tools/doclint/
 
 javac.tests = \
         tools/javac
--- a/langtools/src/share/classes/com/sun/javadoc/ClassDoc.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/javadoc/ClassDoc.java	Wed Jul 05 18:34:52 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 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
@@ -66,6 +66,12 @@
     boolean isExternalizable();
 
     /**
+     * Return true if this class can be used as a target type of a lambda expression
+     * or method reference.
+     */
+    boolean isFunctionalInterface();
+
+    /**
      * Return the serialization methods for this class or
      * interface.
      *
--- a/langtools/src/share/classes/com/sun/javadoc/MethodDoc.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/javadoc/MethodDoc.java	Wed Jul 05 18:34:52 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 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
@@ -39,6 +39,11 @@
     boolean isAbstract();
 
     /**
+     * Return true if this method is default
+     */
+    boolean isDefault();
+
+    /**
      * Get return type.
      *
      * @return the return type of this method, null if it
--- a/langtools/src/share/classes/com/sun/source/util/DocTrees.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/source/util/DocTrees.java	Wed Jul 05 18:34:52 2017 +0200
@@ -45,9 +45,7 @@
      * @throws IllegalArgumentException if the task does not support the Trees API.
      */
     public static DocTrees instance(CompilationTask task) {
-        if (!task.getClass().getName().equals("com.sun.tools.javac.api.JavacTaskImpl"))
-            throw new IllegalArgumentException();
-        return (DocTrees) getJavacTrees(CompilationTask.class, task);
+        return (DocTrees) Trees.instance(task);
     }
 
     /**
--- a/langtools/src/share/classes/com/sun/source/util/JavacTask.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/source/util/JavacTask.java	Wed Jul 05 18:34:52 2017 +0200
@@ -139,6 +139,7 @@
      * @see com.sun.source.util.Trees#getTypeMirror
      */
     public abstract TypeMirror getTypeMirror(Iterable<? extends Tree> path);
+
     /**
      * Get a utility object for dealing with program elements.
      */
--- a/langtools/src/share/classes/com/sun/source/util/Plugin.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/source/util/Plugin.java	Wed Jul 05 18:34:52 2017 +0200
@@ -56,9 +56,9 @@
     String getName();
 
     /**
-     * Invoke the plug-in for a given compilation task.
+     * Initialize the plug-in for a given compilation task.
      * @param task The compilation task that has just been started
      * @param args Arguments, if any, for the plug-in
      */
-    void call(JavacTask task, String... args);
+    void init(JavacTask task, String... args);
 }
--- a/langtools/src/share/classes/com/sun/source/util/TreePath.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/source/util/TreePath.java	Wed Jul 05 18:34:52 2017 +0200
@@ -60,14 +60,20 @@
                 this.path = path;
             }
         }
+
         class PathFinder extends TreePathScanner<TreePath,Tree> {
             public TreePath scan(Tree tree, Tree target) {
-                if (tree == target)
+                if (tree == target) {
                     throw new Result(new TreePath(getCurrentPath(), target));
+                }
                 return super.scan(tree, target);
             }
         }
 
+        if (path.getLeaf() == target) {
+            return path;
+        }
+
         try {
             new PathFinder().scan(path, target);
         } catch (Result result) {
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractMemberWriter.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractMemberWriter.java	Wed Jul 05 18:34:52 2017 +0200
@@ -239,7 +239,14 @@
         if ((member.isField() || member.isMethod()) &&
             writer instanceof ClassWriterImpl &&
             ((ClassWriterImpl) writer).getClassDoc().isInterface()) {
-            mod = Util.replaceText(mod, "public", "").trim();
+            // This check for isDefault() and the default modifier needs to be
+            // added for it to appear on the method details section. Once the
+            // default modifier is added to the Modifier list on DocEnv and once
+            // it is updated to use the javax.lang.model.element.Modifier, we
+            // will need to remove this.
+            mod = (member.isMethod() && ((MethodDoc)member).isDefault()) ?
+                    Util.replaceText(mod, "public", "default").trim() :
+                    Util.replaceText(mod, "public", "").trim();
         }
         if(mod.length() > 0) {
             htmltree.addContent(mod);
@@ -313,8 +320,18 @@
             code.addContent(configuration.getText("doclet.Package_private"));
             code.addContent(" ");
         }
-        if (member.isMethod() && ((MethodDoc)member).isAbstract()) {
-            code.addContent("abstract ");
+        if (member.isMethod()) {
+            if (((MethodDoc)member).isAbstract()) {
+                code.addContent("abstract ");
+            }
+            // This check for isDefault() and the default modifier needs to be
+            // added for it to appear on the "Modifier and Type" column in the
+            // method summary section. Once the default modifier is added
+            // to the Modifier list on DocEnv and once it is updated to use the
+            // javax.lang.model.element.Modifier, we will need to remove this.
+            else if (((MethodDoc)member).isDefault()) {
+                code.addContent("default ");
+            }
         }
         if (member.isStatic()) {
             code.addContent("static ");
@@ -547,6 +564,9 @@
             methodType = (classdoc.isInterface() || ((MethodDoc)member).isAbstract()) ?
                     methodType | MethodTypes.ABSTRACT.value() :
                     methodType | MethodTypes.CONCRETE.value();
+            if (((MethodDoc)member).isDefault()) {
+                methodType = methodType | MethodTypes.DEFAULT.value();
+            }
             if (Util.isDeprecated(member) || Util.isDeprecated(classdoc)) {
                 methodType = methodType | MethodTypes.DEPRECATED.value();
             }
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassWriterImpl.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassWriterImpl.java	Wed Jul 05 18:34:52 2017 +0200
@@ -516,6 +516,20 @@
     /**
      * {@inheritDoc}
      */
+    public void addFunctionalInterfaceInfo (Content classInfoTree) {
+        if (classDoc.isFunctionalInterface()) {
+            Content dt = HtmlTree.DT(getResource("doclet.Functional_Interface"));
+            Content dl = HtmlTree.DL(dt);
+            Content dd = new HtmlTree(HtmlTag.DD);
+            dd.addContent(getResource("doclet.Functional_Interface_Message"));
+            dl.addContent(dd);
+            classInfoTree.addContent(dl);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
     public void addClassDeprecationInfo(Content classInfoTree) {
         Content hr = new HtmlTree(HtmlTag.HR);
         classInfoTree.addContent(hr);
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/resources/standard.properties	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/resources/standard.properties	Wed Jul 05 18:34:52 2017 +0200
@@ -90,6 +90,8 @@
 doclet.Subclasses=Direct Known Subclasses:
 doclet.Subinterfaces=All Known Subinterfaces:
 doclet.Implementing_Classes=All Known Implementing Classes:
+doclet.Functional_Interface=Functional Interface:
+doclet.Functional_Interface_Message=This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference. 
 doclet.also=also
 doclet.Frames=Frames
 doclet.No_Frames=No Frames
--- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/ClassWriter.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/ClassWriter.java	Wed Jul 05 18:34:52 2017 +0200
@@ -117,6 +117,13 @@
     public void addInterfaceUsageInfo(Content classInfoTree);
 
     /**
+     * If this is an functional interface, display appropriate message.
+     *
+     * @param classInfoTree content tree to which the documentation will be added
+     */
+    public void addFunctionalInterfaceInfo(Content classInfoTree);
+
+    /**
      * If this is an inner class or interface, add the enclosing class or
      * interface.
      *
--- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/ClassBuilder.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/ClassBuilder.java	Wed Jul 05 18:34:52 2017 +0200
@@ -236,6 +236,16 @@
     }
 
     /**
+     * If this is an functional interface, display appropriate message.
+     *
+     * @param node the XML element that specifies which components to document
+     * @param classInfoTree the content tree to which the documentation will be added
+     */
+    public void buildFunctionalInterfaceInfo(XMLNode node, Content classInfoTree) {
+        writer.addFunctionalInterfaceInfo(classInfoTree);
+    }
+
+    /**
      * If this class is deprecated, build the appropriate information.
      *
      * @param node the XML element that specifies which components to document
--- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclet.xml	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclet.xml	Wed Jul 05 18:34:52 2017 +0200
@@ -85,6 +85,7 @@
             <SubInterfacesInfo/>
             <InterfaceUsageInfo/>
             <NestedClassInfo/>
+            <FunctionalInterfaceInfo/>
             <DeprecationInfo/>
             <ClassSignature/>
             <ClassDescription/>
--- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/MethodTypes.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/MethodTypes.java	Wed Jul 05 18:34:52 2017 +0200
@@ -36,7 +36,8 @@
     INSTANCE(0x2, "Instance Methods", "t2", false),
     ABSTRACT(0x4, "Abstract Methods", "t3", false),
     CONCRETE(0x8, "Concrete Methods", "t4", false),
-    DEPRECATED(0x10, "Deprecated Methods", "t5", false);
+    DEFAULT(0x10, "Default Methods", "t5", false),
+    DEPRECATED(0x20, "Deprecated Methods", "t6", false);
 
     private final int value;
     private final String text;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/doclint/Checker.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,754 @@
+/*
+ * 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 com.sun.tools.doclint;
+
+import java.util.regex.Matcher;
+import com.sun.source.doctree.LinkTree;
+import java.net.URI;
+import java.util.regex.Pattern;
+import java.io.IOException;
+import com.sun.tools.javac.tree.DocPretty;
+import java.io.StringWriter;
+import java.util.Deque;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.tools.Diagnostic.Kind;
+
+import com.sun.source.doctree.AttributeTree;
+import com.sun.source.doctree.AuthorTree;
+import com.sun.source.doctree.DocCommentTree;
+import com.sun.source.doctree.DocTree;
+import com.sun.source.doctree.EndElementTree;
+import com.sun.source.doctree.EntityTree;
+import com.sun.source.doctree.ErroneousTree;
+import com.sun.source.doctree.IdentifierTree;
+import com.sun.source.doctree.InheritDocTree;
+import com.sun.source.doctree.ParamTree;
+import com.sun.source.doctree.ReferenceTree;
+import com.sun.source.doctree.ReturnTree;
+import com.sun.source.doctree.SerialDataTree;
+import com.sun.source.doctree.SerialFieldTree;
+import com.sun.source.doctree.SinceTree;
+import com.sun.source.doctree.StartElementTree;
+import com.sun.source.doctree.TextTree;
+import com.sun.source.doctree.ThrowsTree;
+import com.sun.source.doctree.VersionTree;
+import com.sun.source.util.DocTreeScanner;
+import com.sun.source.util.TreePath;
+import com.sun.tools.doclint.HtmlTag.AttrKind;
+import java.net.URISyntaxException;
+import static com.sun.tools.doclint.Messages.Group.*;
+
+
+/**
+ * Validate a doc comment.
+ *
+ * <p><b>This is NOT part of any supported API.
+ * If you write code that depends on this, you do so at your own
+ * risk.  This code and its internal interfaces are subject to change
+ * or deletion without notice.</b></p>
+ */
+public class Checker extends DocTreeScanner<Void, Void> {
+    final Env env;
+
+    Set<Element> foundParams = new HashSet<Element>();
+    Set<TypeMirror> foundThrows = new HashSet<TypeMirror>();
+    Set<String> foundAnchors = new HashSet<String>();
+    boolean foundInheritDoc = false;
+    boolean foundReturn = false;
+
+    enum Flag {
+        TABLE_HAS_CAPTION,
+        HAS_ELEMENT,
+        HAS_TEXT
+    }
+
+    static class TagStackItem {
+        final DocTree tree; // typically, but not always, StartElementTree
+        final HtmlTag tag;
+        final Set<HtmlTag.Attr> attrs;
+        final Set<Flag> flags;
+        TagStackItem(DocTree tree, HtmlTag tag) {
+            this.tree = tree;
+            this.tag = tag;
+            attrs = EnumSet.noneOf(HtmlTag.Attr.class);
+            flags = EnumSet.noneOf(Flag.class);
+        }
+        @Override
+        public String toString() {
+            return String.valueOf(tag);
+        }
+    }
+
+    private Deque<TagStackItem> tagStack; // TODO: maybe want to record starting tree as well
+    private HtmlTag currHeaderTag;
+
+    // <editor-fold defaultstate="collapsed" desc="Top level">
+
+    Checker(Env env) {
+        env.getClass();
+        this.env = env;
+        tagStack = new LinkedList<TagStackItem>();
+    }
+
+    public Void scan(DocCommentTree tree, TreePath p) {
+        env.setCurrent(p, tree);
+
+        boolean isOverridingMethod = !env.currOverriddenMethods.isEmpty();
+
+        if (tree == null) {
+            if (!isSynthetic() && !isOverridingMethod)
+                reportMissing("dc.missing.comment");
+            return null;
+        }
+
+        tagStack.clear();
+        currHeaderTag = null;
+
+        foundParams.clear();
+        foundThrows.clear();
+        foundInheritDoc = false;
+        foundReturn = false;
+
+        scan(tree, (Void) null);
+
+        if (!isOverridingMethod) {
+            switch (env.currElement.getKind()) {
+                case METHOD:
+                case CONSTRUCTOR: {
+                    ExecutableElement ee = (ExecutableElement) env.currElement;
+                    checkParamsDocumented(ee.getTypeParameters());
+                    checkParamsDocumented(ee.getParameters());
+                    switch (ee.getReturnType().getKind()) {
+                        case VOID:
+                        case NONE:
+                            break;
+                        default:
+                            if (!foundReturn
+                                    && !foundInheritDoc
+                                    && !env.types.isSameType(ee.getReturnType(), env.java_lang_Void)) {
+                                reportMissing("dc.missing.return");
+                            }
+                    }
+                    checkThrowsDocumented(ee.getThrownTypes());
+                }
+            }
+        }
+
+        return null;
+    }
+
+    private void reportMissing(String code, Object... args) {
+        env.messages.report(MISSING, Kind.WARNING, env.currPath.getLeaf(), code, args);
+    }
+
+    @Override
+    public Void visitDocComment(DocCommentTree tree, Void ignore) {
+        super.visitDocComment(tree, ignore);
+        for (TagStackItem tsi: tagStack) {
+            if (tsi.tree.getKind() == DocTree.Kind.START_ELEMENT
+                    && tsi.tag.endKind == HtmlTag.EndKind.REQUIRED) {
+                StartElementTree t = (StartElementTree) tsi.tree;
+                env.messages.error(HTML, t, "dc.tag.not.closed", t.getName());
+            }
+        }
+        return null;
+    }
+    // </editor-fold>
+
+    // <editor-fold defaultstate="collapsed" desc="Text and entities.">
+
+    @Override
+    public Void visitText(TextTree tree, Void ignore) {
+        if (!tree.getBody().trim().isEmpty()) {
+            markEnclosingTag(Flag.HAS_TEXT);
+        }
+        return null;
+    }
+
+    @Override
+    public Void visitEntity(EntityTree tree, Void ignore) {
+        markEnclosingTag(Flag.HAS_TEXT);
+        String name = tree.getName().toString();
+        if (name.startsWith("#")) {
+            int v = name.toLowerCase().startsWith("#x")
+                    ? Integer.parseInt(name.substring(2), 16)
+                    : Integer.parseInt(name.substring(1), 10);
+            if (!Entity.isValid(v)) {
+                env.messages.error(HTML, tree, "dc.entity.invalid", name);
+            }
+        } else if (!Entity.isValid(name)) {
+            env.messages.error(HTML, tree, "dc.entity.invalid", name);
+        }
+        return null;
+    }
+
+    // </editor-fold>
+
+    // <editor-fold defaultstate="collapsed" desc="HTML elements">
+
+    @Override
+    public Void visitStartElement(StartElementTree tree, Void ignore) {
+        markEnclosingTag(Flag.HAS_ELEMENT);
+        final Name treeName = tree.getName();
+        final HtmlTag t = HtmlTag.get(treeName);
+        if (t == null) {
+            env.messages.error(HTML, tree, "dc.tag.unknown", treeName);
+        } else {
+            // tag specific checks
+            switch (t) {
+                // check for out of sequence headers, such as <h1>...</h1>  <h3>...</h3>
+                case H1: case H2: case H3: case H4: case H5: case H6:
+                    checkHeader(tree, t);
+                    break;
+                // <p> inside <pre>
+                case P:
+                    TagStackItem top = tagStack.peek();
+                    if (top != null && top.tag == HtmlTag.PRE)
+                        env.messages.warning(HTML, tree, "dc.tag.p.in.pre");
+                    break;
+            }
+
+            // check that only block tags and inline tags are used,
+            // and that blocks tags are not used within inline tags
+            switch (t.blockType) {
+                case INLINE:
+                    break;
+                case BLOCK:
+                    TagStackItem top = tagStack.peek();
+                    if (top != null && top.tag != null && top.tag.blockType == HtmlTag.BlockType.INLINE) {
+                        switch (top.tree.getKind()) {
+                            case START_ELEMENT: {
+                                Name name = ((StartElementTree) top.tree).getName();
+                                env.messages.error(HTML, tree, "dc.tag.not.allowed.inline.element",
+                                        treeName, name);
+                                break;
+                            }
+                            case LINK:
+                            case LINK_PLAIN: {
+                                String name = top.tree.getKind().tagName;
+                                env.messages.error(HTML, tree, "dc.tag.not.allowed.inline.tag",
+                                        treeName, name);
+                                break;
+                            }
+                            default:
+                                env.messages.error(HTML, tree, "dc.tag.not.allowed.inline.other",
+                                        treeName);
+                        }
+                    }
+                    break;
+                case OTHER:
+                    env.messages.error(HTML, tree, "dc.tag.not.allowed", treeName);
+                    break;
+                default:
+                    throw new AssertionError();
+            }
+
+            if (t.flags.contains(HtmlTag.Flag.NO_NEST)) {
+                for (TagStackItem i: tagStack) {
+                    if (t == i.tag) {
+                        env.messages.warning(HTML, tree, "dc.tag.nested.not.allowed", treeName);
+                        break;
+                    }
+                }
+            }
+        }
+
+        // check for self closing tags, such as <a id="name"/>
+        if (tree.isSelfClosing()) {
+            env.messages.error(HTML, tree, "dc.tag.self.closing", treeName);
+        }
+
+        try {
+            TagStackItem parent = tagStack.peek();
+            TagStackItem top = new TagStackItem(tree, t);
+            tagStack.push(top);
+
+            super.visitStartElement(tree, ignore);
+
+            // handle attributes that may or may not have been found in start element
+            if (t != null) {
+                switch (t) {
+                    case CAPTION:
+                        if (parent != null && parent.tag == HtmlTag.TABLE)
+                            parent.flags.add(Flag.TABLE_HAS_CAPTION);
+                        break;
+
+                    case IMG:
+                        if (!top.attrs.contains(HtmlTag.Attr.ALT))
+                            env.messages.error(ACCESSIBILITY, tree, "dc.no.alt.attr.for.image");
+                        break;
+                }
+            }
+
+            return null;
+        } finally {
+
+            if (t == null || t.endKind == HtmlTag.EndKind.NONE)
+                tagStack.pop();
+        }
+    }
+
+    private void checkHeader(StartElementTree tree, HtmlTag tag) {
+        // verify the new tag
+        if (getHeaderLevel(tag) > getHeaderLevel(currHeaderTag) + 1) {
+            if (currHeaderTag == null) {
+                env.messages.error(ACCESSIBILITY, tree, "dc.tag.header.sequence.1", tag);
+            } else {
+                env.messages.error(ACCESSIBILITY, tree, "dc.tag.header.sequence.2",
+                    tag, currHeaderTag);
+            }
+        }
+
+        currHeaderTag = tag;
+    }
+
+    private int getHeaderLevel(HtmlTag tag) {
+        if (tag == null)
+            return 0;
+        switch (tag) {
+            case H1: return 1;
+            case H2: return 2;
+            case H3: return 3;
+            case H4: return 4;
+            case H5: return 5;
+            case H6: return 6;
+            default: throw new IllegalArgumentException();
+        }
+    }
+
+    @Override
+    public Void visitEndElement(EndElementTree tree, Void ignore) {
+        final Name treeName = tree.getName();
+        final HtmlTag t = HtmlTag.get(treeName);
+        if (t == null) {
+            env.messages.error(HTML, tree, "dc.tag.unknown", treeName);
+        } else if (t.endKind == HtmlTag.EndKind.NONE) {
+            env.messages.error(HTML, tree, "dc.tag.end.not.permitted", treeName);
+        } else if (tagStack.isEmpty()) {
+            env.messages.error(HTML, tree, "dc.tag.end.unexpected", treeName);
+        } else {
+            while (!tagStack.isEmpty()) {
+                TagStackItem top = tagStack.peek();
+                if (t == top.tag) {
+                    switch (t) {
+                        case TABLE:
+                            if (!top.attrs.contains(HtmlTag.Attr.SUMMARY)
+                                    && !top.flags.contains(Flag.TABLE_HAS_CAPTION)) {
+                                env.messages.error(ACCESSIBILITY, tree,
+                                        "dc.no.summary.or.caption.for.table");
+                            }
+                    }
+                    if (t.flags.contains(HtmlTag.Flag.EXPECT_CONTENT)
+                            && !top.flags.contains(Flag.HAS_TEXT)
+                            && !top.flags.contains(Flag.HAS_ELEMENT)) {
+                        env.messages.warning(HTML, tree, "dc.tag.empty", treeName);
+                    }
+                    if (t.flags.contains(HtmlTag.Flag.NO_TEXT)
+                            && top.flags.contains(Flag.HAS_TEXT)) {
+                        env.messages.error(HTML, tree, "dc.text.not.allowed", treeName);
+                    }
+                    tagStack.pop();
+                    break;
+                } else if (top.tag == null || top.tag.endKind != HtmlTag.EndKind.REQUIRED) {
+                    tagStack.pop();
+                } else {
+                    boolean found = false;
+                    for (TagStackItem si: tagStack) {
+                        if (si.tag == t) {
+                            found = true;
+                            break;
+                        }
+                    }
+                    if (found && top.tree.getKind() == DocTree.Kind.START_ELEMENT) {
+                        env.messages.error(HTML, top.tree, "dc.tag.start.unmatched",
+                                ((StartElementTree) top.tree).getName());
+                        tagStack.pop();
+                    } else {
+                        env.messages.error(HTML, tree, "dc.tag.end.unexpected", treeName);
+                        break;
+                    }
+                }
+            }
+        }
+
+        return super.visitEndElement(tree, ignore);
+    }
+    // </editor-fold>
+
+    // <editor-fold defaultstate="collapsed" desc="HTML attributes">
+
+    @Override @SuppressWarnings("fallthrough")
+    public Void visitAttribute(AttributeTree tree, Void ignore) {
+        HtmlTag currTag = tagStack.peek().tag;
+        if (currTag != null) {
+            Name name = tree.getName();
+            HtmlTag.Attr attr = currTag.getAttr(name);
+            if (attr != null) {
+                boolean first = tagStack.peek().attrs.add(attr);
+                if (!first)
+                    env.messages.error(HTML, tree, "dc.attr.repeated", name);
+            }
+            AttrKind k = currTag.getAttrKind(name);
+            switch (k) {
+                case OK:
+                    break;
+
+                case INVALID:
+                    env.messages.error(HTML, tree, "dc.attr.unknown", name);
+                    break;
+
+                case OBSOLETE:
+                    env.messages.warning(ACCESSIBILITY, tree, "dc.attr.obsolete", name);
+                    break;
+
+                case USE_CSS:
+                    env.messages.warning(ACCESSIBILITY, tree, "dc.attr.obsolete.use.css", name);
+                    break;
+            }
+
+            if (attr != null) {
+                switch (attr) {
+                    case NAME:
+                        if (currTag != HtmlTag.A) {
+                            break;
+                        }
+                    // fallthrough
+                    case ID:
+                        String value = getAttrValue(tree);
+                        if (!validName.matcher(value).matches()) {
+                            env.messages.error(HTML, tree, "dc.invalid.anchor", value);
+                        }
+                        if (!foundAnchors.add(value)) {
+                            env.messages.error(HTML, tree, "dc.anchor.already.defined", value);
+                        }
+                        break;
+
+                    case HREF:
+                        if (currTag == HtmlTag.A) {
+                            String v = getAttrValue(tree);
+                            if (v == null || v.isEmpty()) {
+                                env.messages.error(HTML, tree, "dc.attr.lacks.value");
+                            } else {
+                                Matcher m = docRoot.matcher(v);
+                                if (m.matches()) {
+                                    String rest = m.group(2);
+                                    if (!rest.isEmpty())
+                                        checkURI(tree, rest);
+                                } else {
+                                    checkURI(tree, v);
+                                }
+                            }
+                        }
+                        break;
+                }
+            }
+        }
+
+        // TODO: basic check on value
+
+        return super.visitAttribute(tree, ignore);
+    }
+
+    // http://www.w3.org/TR/html401/types.html#type-name
+    private static final Pattern validName = Pattern.compile("[A-Za-z][A-Za-z0-9-_:.]*");
+
+    // pattern to remove leading {@docRoot}/?
+    private static final Pattern docRoot = Pattern.compile("(?i)(\\{@docRoot *\\}/?)?(.*)");
+
+    private String getAttrValue(AttributeTree tree) {
+        if (tree.getValue() == null)
+            return null;
+
+        StringWriter sw = new StringWriter();
+        try {
+            new DocPretty(sw).print(tree.getValue());
+        } catch (IOException e) {
+            // cannot happen
+        }
+        // ignore potential use of entities for now
+        return sw.toString();
+    }
+
+    private void checkURI(AttributeTree tree, String uri) {
+        try {
+            URI u = new URI(uri);
+        } catch (URISyntaxException e) {
+            env.messages.error(HTML, tree, "dc.invalid.uri", uri);
+        }
+    }
+    // </editor-fold>
+
+    // <editor-fold defaultstate="collapsed" desc="javadoc tags">
+
+    @Override
+    public Void visitAuthor(AuthorTree tree, Void ignore) {
+        warnIfEmpty(tree, tree.getName());
+        return super.visitAuthor(tree, ignore);
+    }
+
+    @Override
+    public Void visitInheritDoc(InheritDocTree tree, Void ignore) {
+        // TODO: verify on overridden method
+        foundInheritDoc = true;
+        return super.visitInheritDoc(tree, ignore);
+    }
+
+    @Override
+    public Void visitLink(LinkTree tree, Void ignore) {
+        // simulate inline context on tag stack
+        HtmlTag t = (tree.getKind() == DocTree.Kind.LINK)
+                ? HtmlTag.CODE : HtmlTag.SPAN;
+        tagStack.push(new TagStackItem(tree, t));
+        try {
+            return super.visitLink(tree, ignore);
+        } finally {
+            tagStack.pop();
+        }
+    }
+
+    @Override
+    public Void visitParam(ParamTree tree, Void ignore) {
+        boolean typaram = tree.isTypeParameter();
+        IdentifierTree nameTree = tree.getName();
+        Element e = env.currElement;
+        switch (e.getKind()) {
+            case METHOD: case CONSTRUCTOR: {
+                ExecutableElement ee = (ExecutableElement) e;
+                checkParamDeclared(nameTree, typaram ? ee.getTypeParameters() : ee.getParameters());
+                break;
+            }
+
+            case CLASS: case INTERFACE: {
+                TypeElement te = (TypeElement) e;
+                if (typaram) {
+                    checkParamDeclared(nameTree, te.getTypeParameters());
+                } else {
+                    env.messages.error(REFERENCE, tree, "dc.invalid.param");
+                }
+                break;
+            }
+
+            default:
+                env.messages.error(REFERENCE, tree, "dc.invalid.param");
+                break;
+        }
+        warnIfEmpty(tree, tree.getDescription());
+        return super.visitParam(tree, ignore);
+    }
+    // where
+    private void checkParamDeclared(IdentifierTree nameTree, List<? extends Element> list) {
+        Name name = nameTree.getName();
+        boolean found = false;
+        for (Element e: list) {
+            if (name.equals(e.getSimpleName())) {
+                foundParams.add(e);
+                found = true;
+            }
+        }
+        if (!found)
+            env.messages.error(REFERENCE, nameTree, "dc.param.name.not.found");
+    }
+
+    private void checkParamsDocumented(List<? extends Element> list) {
+        if (foundInheritDoc)
+            return;
+
+        for (Element e: list) {
+            if (!foundParams.contains(e)) {
+                CharSequence paramName = (e.getKind() == ElementKind.TYPE_PARAMETER)
+                        ? "<" + e.getSimpleName() + ">"
+                        : e.getSimpleName();
+                reportMissing("dc.missing.param", paramName);
+            }
+        }
+    }
+
+    @Override
+    public Void visitReference(ReferenceTree tree, Void ignore) {
+        Element e = env.trees.getElement(env.currPath, tree);
+        if (e == null)
+            env.messages.error(REFERENCE, tree, "dc.ref.not.found");
+        return super.visitReference(tree, ignore);
+    }
+
+    @Override
+    public Void visitReturn(ReturnTree tree, Void ignore) {
+        Element e = env.trees.getElement(env.currPath);
+        if (e.getKind() != ElementKind.METHOD
+                || ((ExecutableElement) e).getReturnType().getKind() == TypeKind.VOID)
+            env.messages.error(REFERENCE, tree, "dc.invalid.return");
+        foundReturn = true;
+        warnIfEmpty(tree, tree.getDescription());
+        return super.visitReturn(tree, ignore);
+    }
+
+    @Override
+    public Void visitSerialData(SerialDataTree tree, Void ignore) {
+        warnIfEmpty(tree, tree.getDescription());
+        return super.visitSerialData(tree, ignore);
+    }
+
+    @Override
+    public Void visitSerialField(SerialFieldTree tree, Void ignore) {
+        warnIfEmpty(tree, tree.getDescription());
+        return super.visitSerialField(tree, ignore);
+    }
+
+    @Override
+    public Void visitSince(SinceTree tree, Void ignore) {
+        warnIfEmpty(tree, tree.getBody());
+        return super.visitSince(tree, ignore);
+    }
+
+    @Override
+    public Void visitThrows(ThrowsTree tree, Void ignore) {
+        ReferenceTree exName = tree.getExceptionName();
+        Element ex = env.trees.getElement(env.currPath, exName);
+        if (ex == null) {
+            env.messages.error(REFERENCE, tree, "dc.ref.not.found");
+        } else if (ex.asType().getKind() == TypeKind.DECLARED
+                && env.types.isAssignable(ex.asType(), env.java_lang_Throwable)) {
+            switch (env.currElement.getKind()) {
+                case CONSTRUCTOR:
+                case METHOD:
+                    if (isCheckedException(ex.asType())) {
+                        ExecutableElement ee = (ExecutableElement) env.currElement;
+                        checkThrowsDeclared(exName, ex.asType(), ee.getThrownTypes());
+                    }
+                    break;
+                default:
+                    env.messages.error(REFERENCE, tree, "dc.invalid.throws");
+            }
+        } else {
+            env.messages.error(REFERENCE, tree, "dc.invalid.throws");
+        }
+        warnIfEmpty(tree, tree.getDescription());
+        return scan(tree.getDescription(), ignore);
+    }
+
+    private void checkThrowsDeclared(ReferenceTree tree, TypeMirror t, List<? extends TypeMirror> list) {
+        boolean found = false;
+        for (TypeMirror tl : list) {
+            if (env.types.isAssignable(t, tl)) {
+                foundThrows.add(tl);
+                found = true;
+            }
+        }
+        if (!found)
+            env.messages.error(REFERENCE, tree, "dc.exception.not.thrown", t);
+    }
+
+    private void checkThrowsDocumented(List<? extends TypeMirror> list) {
+        if (foundInheritDoc)
+            return;
+
+        for (TypeMirror tl: list) {
+            if (isCheckedException(tl) && !foundThrows.contains(tl))
+                reportMissing("dc.missing.throws", tl);
+        }
+    }
+
+    @Override
+    public Void visitVersion(VersionTree tree, Void ignore) {
+        warnIfEmpty(tree, tree.getBody());
+        return super.visitVersion(tree, ignore);
+    }
+
+    @Override
+    public Void visitErroneous(ErroneousTree tree, Void ignore) {
+        env.messages.error(SYNTAX, tree, null, tree.getDiagnostic().getMessage(null));
+        return null;
+    }
+    // </editor-fold>
+
+    // <editor-fold defaultstate="collapsed" desc="Utility methods">
+
+    private boolean isCheckedException(TypeMirror t) {
+        return !(env.types.isAssignable(t, env.java_lang_Error)
+                || env.types.isAssignable(t, env.java_lang_RuntimeException));
+    }
+
+    private boolean isSynthetic() {
+        switch (env.currElement.getKind()) {
+            case CONSTRUCTOR:
+                // A synthetic default constructor has the same pos as the
+                // enclosing class
+                TreePath p = env.currPath;
+                return env.getPos(p) == env.getPos(p.getParentPath());
+        }
+        return false;
+    }
+
+    void markEnclosingTag(Flag flag) {
+        TagStackItem top = tagStack.peek();
+        if (top != null)
+            top.flags.add(flag);
+    }
+
+    String toString(TreePath p) {
+        StringBuilder sb = new StringBuilder("TreePath[");
+        toString(p, sb);
+        sb.append("]");
+        return sb.toString();
+    }
+
+    void toString(TreePath p, StringBuilder sb) {
+        TreePath parent = p.getParentPath();
+        if (parent != null) {
+            toString(parent, sb);
+            sb.append(",");
+        }
+       sb.append(p.getLeaf().getKind()).append(":").append(env.getPos(p)).append(":S").append(env.getStartPos(p));
+    }
+
+    void warnIfEmpty(DocTree tree, List<? extends DocTree> list) {
+        for (DocTree d: list) {
+            switch (d.getKind()) {
+                case TEXT:
+                    if (!((TextTree) d).getBody().trim().isEmpty())
+                        return;
+                    break;
+                default:
+                    return;
+            }
+        }
+        env.messages.warning(SYNTAX, tree, "dc.empty", tree.getKind().tagName);
+    }
+    // </editor-fold>
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/doclint/DocLint.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,376 @@
+/*
+ * 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 com.sun.tools.doclint;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.lang.model.element.Name;
+import javax.tools.StandardLocation;
+
+import com.sun.source.doctree.DocCommentTree;
+import com.sun.source.tree.ClassTree;
+import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.tree.MethodTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.tree.VariableTree;
+import com.sun.source.util.JavacTask;
+import com.sun.source.util.Plugin;
+import com.sun.source.util.TaskEvent;
+import com.sun.source.util.TaskListener;
+import com.sun.source.util.TreePath;
+import com.sun.source.util.TreePathScanner;
+import com.sun.tools.javac.api.JavacTaskImpl;
+import com.sun.tools.javac.api.JavacTool;
+import com.sun.tools.javac.file.JavacFileManager;
+import com.sun.tools.javac.main.JavaCompiler;
+import com.sun.tools.javac.util.Context;
+
+/**
+ * Multi-function entry point for the doc check utility.
+ *
+ * This class can be invoked in the following ways:
+ * <ul>
+ * <li>From the command line
+ * <li>From javac, as a plugin
+ * <li>Directly, via a simple API
+ * </ul>
+ *
+ * <p><b>This is NOT part of any supported API.
+ * If you write code that depends on this, you do so at your own
+ * risk.  This code and its internal interfaces are subject to change
+ * or deletion without notice.</b></p>
+ */
+public class DocLint implements Plugin {
+
+    public static final String XMSGS_OPTION = "-Xmsgs";
+    public static final String XMSGS_CUSTOM_PREFIX = "-Xmsgs:";
+    private static final String STATS = "-stats";
+
+    // <editor-fold defaultstate="collapsed" desc="Command-line entry point">
+    public static void main(String... args) {
+        try {
+            new DocLint().run(args);
+        } catch (BadArgs e) {
+            System.err.println(e.getMessage());
+            System.exit(1);
+        } catch (IOException e) {
+            System.err.println(e);
+            System.exit(2);
+        }
+    }
+
+    // </editor-fold>
+
+    // <editor-fold defaultstate="collapsed" desc="Simple API">
+
+    public static class BadArgs extends Exception {
+        private static final long serialVersionUID = 0;
+        BadArgs(String code, Object... args) {
+            this.code = code;
+            this.args = args;
+        }
+
+        final String code;
+        final Object[] args;
+    }
+
+    /**
+     * Simple API entry point.
+     */
+    public void run(String... args) throws BadArgs, IOException {
+        PrintWriter out = new PrintWriter(System.out);
+        try {
+            run(out, args);
+        } finally {
+            out.flush();
+        }
+    }
+
+    public void run(PrintWriter out, String... args) throws BadArgs, IOException {
+        env = new Env();
+        processArgs(args);
+
+        if (needHelp)
+            showHelp(out);
+
+        if (javacFiles.isEmpty()) {
+            if (!needHelp)
+                System.out.println("no files given");
+        }
+
+        JavacTool tool = JavacTool.create();
+
+        JavacFileManager fm = new JavacFileManager(new Context(), false, null);
+        fm.setSymbolFileEnabled(false);
+        fm.setLocation(StandardLocation.PLATFORM_CLASS_PATH, javacBootClassPath);
+        fm.setLocation(StandardLocation.CLASS_PATH, javacClassPath);
+        fm.setLocation(StandardLocation.SOURCE_PATH, javacSourcePath);
+
+        JavacTask task = tool.getTask(out, fm, null, javacOpts, null,
+                fm.getJavaFileObjectsFromFiles(javacFiles));
+        Iterable<? extends CompilationUnitTree> units = task.parse();
+        ((JavacTaskImpl) task).enter();
+
+        env.init(task);
+        checker = new Checker(env);
+
+        DeclScanner ds = new DeclScanner() {
+            @Override
+            void visitDecl(Tree tree, Name name) {
+                TreePath p = getCurrentPath();
+                DocCommentTree dc = env.trees.getDocCommentTree(p);
+
+                checker.scan(dc, p);
+            }
+        };
+
+        ds.scan(units, null);
+
+        reportStats(out);
+
+        Context ctx = ((JavacTaskImpl) task).getContext();
+        JavaCompiler c = JavaCompiler.instance(ctx);
+        c.printCount("error", c.errorCount());
+        c.printCount("warn", c.warningCount());
+    }
+
+    void processArgs(String... args) throws BadArgs {
+        javacOpts = new ArrayList<String>();
+        javacFiles = new ArrayList<File>();
+
+        if (args.length == 0)
+            needHelp = true;
+
+        for (int i = 0; i < args.length; i++) {
+            String arg = args[i];
+            if (arg.matches("-Xmax(errs|warns)") && i + 1 < args.length) {
+                if (args[++i].matches("[0-9]+")) {
+                    javacOpts.add(arg);
+                    javacOpts.add(args[i]);
+                } else {
+                    throw new BadArgs("dc.bad.value.for.option", arg, args[i]);
+                }
+            } else if (arg.equals(STATS)) {
+                env.messages.setStatsEnabled(true);
+            } else if (arg.matches("-bootclasspath") && i + 1 < args.length) {
+                javacBootClassPath = splitPath(args[++i]);
+            } else if (arg.matches("-classpath") && i + 1 < args.length) {
+                javacClassPath = splitPath(args[++i]);
+            } else if (arg.matches("-sourcepath") && i + 1 < args.length) {
+                javacSourcePath = splitPath(args[++i]);
+            } else if (arg.equals(XMSGS_OPTION)) {
+                env.messages.setOptions(null);
+            } else if (arg.startsWith(XMSGS_CUSTOM_PREFIX)) {
+                env.messages.setOptions(arg.substring(arg.indexOf(":") + 1));
+            } else if (arg.equals("-h") || arg.equals("-help") || arg.equals("--help")
+                    || arg.equals("-?") || arg.equals("-usage")) {
+                needHelp = true;
+            } else if (arg.startsWith("-")) {
+                throw new BadArgs("dc.bad.option", arg);
+            } else {
+                while (i < args.length)
+                    javacFiles.add(new File(args[i++]));
+            }
+        }
+    }
+
+    void showHelp(PrintWriter out) {
+        out.println("Usage:");
+        out.println("    doclint [options] source-files...");
+        out.println("");
+        out.println("Options:");
+        out.println("  -Xmsgs  ");
+        out.println("    Same as -Xmsgs:all");
+        out.println("  -Xmsgs:values");
+        out.println("    Specify categories of issues to be checked, where 'values'");
+        out.println("    is a comma-separated list of any of the following:");
+        out.println("      reference      show places where comments contain incorrect");
+        out.println("                     references to Java source code elements");
+        out.println("      syntax         show basic syntax errors within comments");
+        out.println("      html           show issues with HTML tags and attributes");
+        out.println("      accessibility  show issues for accessibility");
+        out.println("      missing        show issues with missing documentation");
+        out.println("      all            all of the above");
+        out.println("    Precede a value with '-' to negate it");
+        out.println("    Categories may be qualified by one of:");
+        out.println("      /public /protected /package /private");
+        out.println("    For positive categories (not beginning with '-')");
+        out.println("    the qualifier applies to that access level and above.");
+        out.println("    For negative categories (beginning with '-')");
+        out.println("    the qualifier applies to that access level and below.");
+        out.println("    If a qualifier is missing, the category applies to");
+        out.println("    all access levels.");
+        out.println("    For example, -Xmsgs:all,-syntax/private");
+        out.println("    This will enable all messages, except syntax errors");
+        out.println("    in the doc comments of private methods.");
+        out.println("    If no -Xmsgs options are provided, the default is");
+        out.println("    equivalent to -Xmsgs:all/protected, meaning that");
+        out.println("    all messages are reported for protected and public");
+        out.println("    declarations only. ");
+        out.println("  -h -help --help -usage -?");
+        out.println("    Show this message.");
+        out.println("");
+        out.println("The following javac options are also supported");
+        out.println("  -bootclasspath, -classpath, -sourcepath, -Xmaxerrs, -Xmaxwarns");
+        out.println("");
+        out.println("To run doclint on part of a project, put the compiled classes for your");
+        out.println("project on the classpath (or bootclasspath), then specify the source files");
+        out.println("to be checked on the command line.");
+    }
+
+    List<File> splitPath(String path) {
+        List<File> files = new ArrayList<File>();
+        for (String f: path.split(File.separator)) {
+            if (f.length() > 0)
+                files.add(new File(f));
+        }
+        return files;
+    }
+
+    List<File> javacBootClassPath;
+    List<File> javacClassPath;
+    List<File> javacSourcePath;
+    List<String> javacOpts;
+    List<File> javacFiles;
+    boolean needHelp = false;
+
+    // </editor-fold>
+
+    // <editor-fold defaultstate="collapsed" desc="javac Plugin">
+
+    @Override
+    public String getName() {
+        return "doclint";
+    }
+
+    @Override
+    public void init(JavacTask task, String... args) {
+        init(task, args, true);
+    }
+
+    // </editor-fold>
+
+    // <editor-fold defaultstate="collapsed" desc="Embedding API">
+
+    public void init(JavacTask task, String[] args, boolean addTaskListener) {
+        env = new Env();
+        for (int i = 0; i < args.length; i++) {
+            String arg = args[i];
+            if (arg.equals(XMSGS_OPTION)) {
+                env.messages.setOptions(null);
+            } else if (arg.startsWith(XMSGS_CUSTOM_PREFIX)) {
+                env.messages.setOptions(arg.substring(arg.indexOf(":") + 1));
+            } else
+                throw new IllegalArgumentException(arg);
+        }
+        env.init(task);
+
+        checker = new Checker(env);
+
+        if (addTaskListener) {
+            final DeclScanner ds = new DeclScanner() {
+                @Override
+                void visitDecl(Tree tree, Name name) {
+                    TreePath p = getCurrentPath();
+                    DocCommentTree dc = env.trees.getDocCommentTree(p);
+
+                    checker.scan(dc, p);
+                }
+            };
+
+            TaskListener tl = new TaskListener() {
+                @Override
+                public void started(TaskEvent e) {
+                    return;
+                }
+
+                @Override
+                public void finished(TaskEvent e) {
+                    switch (e.getKind()) {
+                        case ENTER:
+                            ds.scan(e.getCompilationUnit(), null);
+                    }
+                }
+            };
+
+            task.addTaskListener(tl);
+        }
+    }
+
+    public void scan(TreePath p) {
+        DocCommentTree dc = env.trees.getDocCommentTree(p);
+        checker.scan(dc, p);
+    }
+
+    public void reportStats(PrintWriter out) {
+        env.messages.reportStats(out);
+    }
+
+    // </editor-fold>
+
+    Env env;
+    Checker checker;
+
+    public static boolean isValidOption(String opt) {
+        if (opt.equals(XMSGS_OPTION))
+           return true;
+        if (opt.startsWith(XMSGS_CUSTOM_PREFIX))
+           return Messages.Options.isValidOptions(opt.substring(XMSGS_CUSTOM_PREFIX.length()));
+        return false;
+    }
+
+    // <editor-fold defaultstate="collapsed" desc="DeclScanner">
+
+    static abstract class DeclScanner extends TreePathScanner<Void, Void> {
+        abstract void visitDecl(Tree tree, Name name);
+
+        @Override
+        public Void visitClass(ClassTree tree, Void ignore) {
+            visitDecl(tree, tree.getSimpleName());
+            return super.visitClass(tree, ignore);
+        }
+
+        @Override
+        public Void visitMethod(MethodTree tree, Void ignore) {
+            visitDecl(tree, tree.getName());
+            //return super.visitMethod(tree, ignore);
+            return null;
+        }
+
+        @Override
+        public Void visitVariable(VariableTree tree, Void ignore) {
+            visitDecl(tree, tree.getName());
+            return super.visitVariable(tree, ignore);
+        }
+    }
+
+    // </editor-fold>
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/doclint/Entity.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,326 @@
+/*
+ * 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 com.sun.tools.doclint;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Table of entities defined in HTML 4.01.
+ *
+ * <p> Derived from
+ * <a href="http://www.w3.org/TR/html4/sgml/entities.html">Character entity references in HTML 4</a>.
+ *
+ * The name of the member follows the name of the entity,
+ * except when it clashes with a keyword, in which case
+ * it is prefixed by '_'.
+ *
+ * <p><b>This is NOT part of any supported API.
+ * If you write code that depends on this, you do so at your own
+ * risk.  This code and its internal interfaces are subject to change
+ * or deletion without notice.</b></p>
+ */
+enum Entity {
+    nbsp(160),
+    iexcl(161),
+    cent(162),
+    pound(163),
+    curren(164),
+    yen(165),
+    brvbar(166),
+    sect(167),
+    uml(168),
+    copy(169),
+    ordf(170),
+    laquo(171),
+    not(172),
+    shy(173),
+    reg(174),
+    macr(175),
+    deg(176),
+    plusmn(177),
+    sup2(178),
+    sup3(179),
+    acute(180),
+    micro(181),
+    para(182),
+    middot(183),
+    cedil(184),
+    sup1(185),
+    ordm(186),
+    raquo(187),
+    frac14(188),
+    frac12(189),
+    frac34(190),
+    iquest(191),
+    Agrave(192),
+    Aacute(193),
+    Acirc(194),
+    Atilde(195),
+    Auml(196),
+    Aring(197),
+    AElig(198),
+    Ccedil(199),
+    Egrave(200),
+    Eacute(201),
+    Ecirc(202),
+    Euml(203),
+    Igrave(204),
+    Iacute(205),
+    Icirc(206),
+    Iuml(207),
+    ETH(208),
+    Ntilde(209),
+    Ograve(210),
+    Oacute(211),
+    Ocirc(212),
+    Otilde(213),
+    Ouml(214),
+    times(215),
+    Oslash(216),
+    Ugrave(217),
+    Uacute(218),
+    Ucirc(219),
+    Uuml(220),
+    Yacute(221),
+    THORN(222),
+    szlig(223),
+    agrave(224),
+    aacute(225),
+    acirc(226),
+    atilde(227),
+    auml(228),
+    aring(229),
+    aelig(230),
+    ccedil(231),
+    egrave(232),
+    eacute(233),
+    ecirc(234),
+    euml(235),
+    igrave(236),
+    iacute(237),
+    icirc(238),
+    iuml(239),
+    eth(240),
+    ntilde(241),
+    ograve(242),
+    oacute(243),
+    ocirc(244),
+    otilde(245),
+    ouml(246),
+    divide(247),
+    oslash(248),
+    ugrave(249),
+    uacute(250),
+    ucirc(251),
+    uuml(252),
+    yacute(253),
+    thorn(254),
+    yuml(255),
+    fnof(402),
+    Alpha(913),
+    Beta(914),
+    Gamma(915),
+    Delta(916),
+    Epsilon(917),
+    Zeta(918),
+    Eta(919),
+    Theta(920),
+    Iota(921),
+    Kappa(922),
+    Lambda(923),
+    Mu(924),
+    Nu(925),
+    Xi(926),
+    Omicron(927),
+    Pi(928),
+    Rho(929),
+    Sigma(931),
+    Tau(932),
+    Upsilon(933),
+    Phi(934),
+    Chi(935),
+    Psi(936),
+    Omega(937),
+    alpha(945),
+    beta(946),
+    gamma(947),
+    delta(948),
+    epsilon(949),
+    zeta(950),
+    eta(951),
+    theta(952),
+    iota(953),
+    kappa(954),
+    lambda(955),
+    mu(956),
+    nu(957),
+    xi(958),
+    omicron(959),
+    pi(960),
+    rho(961),
+    sigmaf(962),
+    sigma(963),
+    tau(964),
+    upsilon(965),
+    phi(966),
+    chi(967),
+    psi(968),
+    omega(969),
+    thetasym(977),
+    upsih(978),
+    piv(982),
+    bull(8226),
+    hellip(8230),
+    prime(8242),
+    Prime(8243),
+    oline(8254),
+    frasl(8260),
+    weierp(8472),
+    image(8465),
+    real(8476),
+    trade(8482),
+    alefsym(8501),
+    larr(8592),
+    uarr(8593),
+    rarr(8594),
+    darr(8595),
+    harr(8596),
+    crarr(8629),
+    lArr(8656),
+    uArr(8657),
+    rArr(8658),
+    dArr(8659),
+    hArr(8660),
+    forall(8704),
+    part(8706),
+    exist(8707),
+    empty(8709),
+    nabla(8711),
+    isin(8712),
+    notin(8713),
+    ni(8715),
+    prod(8719),
+    sum(8721),
+    minus(8722),
+    lowast(8727),
+    radic(8730),
+    prop(8733),
+    infin(8734),
+    ang(8736),
+    and(8743),
+    or(8744),
+    cap(8745),
+    cup(8746),
+    _int(8747),
+    there4(8756),
+    sim(8764),
+    cong(8773),
+    asymp(8776),
+    ne(8800),
+    equiv(8801),
+    le(8804),
+    ge(8805),
+    sub(8834),
+    sup(8835),
+    nsub(8836),
+    sube(8838),
+    supe(8839),
+    oplus(8853),
+    otimes(8855),
+    perp(8869),
+    sdot(8901),
+    lceil(8968),
+    rceil(8969),
+    lfloor(8970),
+    rfloor(8971),
+    lang(9001),
+    rang(9002),
+    loz(9674),
+    spades(9824),
+    clubs(9827),
+    hearts(9829),
+    diams(9830),
+    quot(34),
+    amp(38),
+    lt(60),
+    gt(62),
+    OElig(338),
+    oelig(339),
+    Scaron(352),
+    scaron(353),
+    Yuml(376),
+    circ(710),
+    tilde(732),
+    ensp(8194),
+    emsp(8195),
+    thinsp(8201),
+    zwnj(8204),
+    zwj(8205),
+    lrm(8206),
+    rlm(8207),
+    ndash(8211),
+    mdash(8212),
+    lsquo(8216),
+    rsquo(8217),
+    sbquo(8218),
+    ldquo(8220),
+    rdquo(8221),
+    bdquo(8222),
+    dagger(8224),
+    Dagger(8225),
+    permil(8240),
+    lsaquo(8249),
+    rsaquo(8250),
+    euro(8364);
+
+    int code;
+
+    private Entity(int code) {
+        this.code = code;
+    }
+
+    static boolean isValid(String name) {
+        return names.containsKey(name);
+    }
+
+    static boolean isValid(int code) {
+        // allow numeric codes for standard ANSI characters
+        return codes.containsKey(code) || ( 32 <= code && code < 2127);
+    }
+
+    private static final Map<String,Entity> names = new HashMap<String,Entity>();
+    private static final Map<Integer,Entity> codes = new HashMap<Integer,Entity>();
+    static {
+        for (Entity e: values()) {
+            String name = e.name();
+            int code = e.code;
+            if (name.startsWith("_")) name = name.substring(1);
+            names.put(name, e);
+            codes.put(code, e);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/doclint/Env.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,166 @@
+/*
+ * 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 com.sun.tools.doclint;
+
+
+import java.util.Set;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+
+import com.sun.source.doctree.DocCommentTree;
+import com.sun.source.util.DocTrees;
+import com.sun.source.util.JavacTask;
+import com.sun.source.util.SourcePositions;
+import com.sun.source.util.TreePath;
+import com.sun.tools.javac.model.JavacTypes;
+import com.sun.tools.javac.tree.JCTree;
+
+/**
+ * Utility container for current execution environment,
+ * providing the current declaration and its doc comment.
+ *
+ * <p><b>This is NOT part of any supported API.
+ * If you write code that depends on this, you do so at your own
+ * risk.  This code and its internal interfaces are subject to change
+ * or deletion without notice.</b></p>
+ */
+public class Env {
+    /**
+     * Access kinds for declarations.
+     */
+    public enum AccessKind {
+        PRIVATE,
+        PACKAGE,
+        PROTECTED,
+        PUBLIC;
+
+        static boolean accepts(String opt) {
+            for (AccessKind g: values())
+                if (opt.equals(g.name().toLowerCase())) return true;
+            return false;
+        }
+
+        static AccessKind of(Set<Modifier> mods) {
+            if (mods.contains(Modifier.PUBLIC))
+                return AccessKind.PUBLIC;
+            else if (mods.contains(Modifier.PROTECTED))
+                return AccessKind.PROTECTED;
+            else if (mods.contains(Modifier.PRIVATE))
+                return AccessKind.PRIVATE;
+            else
+                return AccessKind.PACKAGE;
+        }
+    };
+
+    /** Message handler. */
+    final Messages messages;
+
+    // Utility classes
+    DocTrees trees;
+    Elements elements;
+    Types types;
+
+    // Types used when analysing doc comments.
+    TypeMirror java_lang_Error;
+    TypeMirror java_lang_RuntimeException;
+    TypeMirror java_lang_Throwable;
+    TypeMirror java_lang_Void;
+
+    /** The path for the declaration containing the comment currently being analyzed. */
+    TreePath currPath;
+    /** The element for the declaration containing the comment currently being analyzed. */
+    Element currElement;
+    /** The comment current being analyzed. */
+    DocCommentTree currDocComment;
+    /**
+     * The access kind of the declaration containing the comment currently being analyzed.
+     * This is the minimum (most restrictive) access kind of the declaration iteself
+     * and that of its containers. For example, a public method in a private class is
+     * noted as private.
+     */
+    AccessKind currAccess;
+    /** The set of methods, if any, that the current declaration overrides. */
+    Set<? extends ExecutableElement> currOverriddenMethods;
+
+    Env() {
+        messages = new Messages(this);
+    }
+
+    void init(JavacTask task) {
+        init(DocTrees.instance(task), task.getElements(), task.getTypes());
+    }
+
+    void init(DocTrees trees, Elements elements, Types types) {
+        this.trees = trees;
+        this.elements = elements;
+        this.types = types;
+        java_lang_Error = elements.getTypeElement("java.lang.Error").asType();
+        java_lang_RuntimeException = elements.getTypeElement("java.lang.RuntimeException").asType();
+        java_lang_Throwable = elements.getTypeElement("java.lang.Throwable").asType();
+        java_lang_Void = elements.getTypeElement("java.lang.Void").asType();
+    }
+
+    /** Set the current declaration and its doc comment. */
+    void setCurrent(TreePath path, DocCommentTree comment) {
+        currPath = path;
+        currDocComment = comment;
+        currElement = trees.getElement(currPath);
+        currOverriddenMethods = ((JavacTypes) types).getOverriddenMethods(currElement);
+
+        AccessKind ak = null;
+        for (TreePath p = path; p != null; p = p.getParentPath()) {
+            Element e = trees.getElement(p);
+            if (e != null) {
+                ak = min(ak, AccessKind.of(e.getModifiers()));
+            }
+        }
+        currAccess = ak;
+    }
+
+    AccessKind getAccessKind() {
+        return currAccess;
+    }
+
+    long getPos(TreePath p) {
+        return ((JCTree) p.getLeaf()).pos;
+    }
+
+    long getStartPos(TreePath p) {
+        SourcePositions sp = trees.getSourcePositions();
+        return sp.getStartPosition(p.getCompilationUnit(), p.getLeaf());
+    }
+
+    private <T extends Comparable<T>> T min(T item1, T item2) {
+        return (item1 == null) ? item2
+                : (item2 == null) ? item1
+                : item1.compareTo(item2) <= 0 ? item1 : item2;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/doclint/HtmlTag.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,356 @@
+/*
+ * Copyright (c) 2010, 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 com.sun.tools.doclint;
+
+import java.util.Set;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.lang.model.element.Name;
+
+import static com.sun.tools.doclint.HtmlTag.Attr.*;
+
+/**
+ * Enum representing HTML tags.
+ *
+ * The intent of this class is to embody the semantics of W3C HTML 4.01
+ * to the extent supported/used by javadoc.
+ *
+ * This is derivative of com.sun.tools.doclets.formats.html.markup.HtmlTag.
+ * Eventually, these two should be merged back together, and possibly made
+ * public.
+ *
+ * @see <a href="http://www.w3.org/TR/REC-html40/">HTML 4.01 Specification</a>
+ * @author Bhavesh Patel
+ * @author Jonathan Gibbons (revised)
+ */
+public enum HtmlTag {
+    A(BlockType.INLINE, EndKind.REQUIRED,
+            attrs(AttrKind.OK, HREF, TARGET, NAME)),
+
+    B(BlockType.INLINE, EndKind.REQUIRED,
+            EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
+
+    BLOCKQUOTE,
+
+    BODY(BlockType.OTHER, EndKind.REQUIRED),
+
+    BR(BlockType.INLINE, EndKind.NONE,
+            attrs(AttrKind.USE_CSS, CLEAR)),
+
+    CAPTION(EnumSet.of(Flag.EXPECT_CONTENT)),
+
+    CENTER,
+
+    CITE(BlockType.INLINE, EndKind.REQUIRED,
+            EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
+
+    CODE(BlockType.INLINE, EndKind.REQUIRED,
+            EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
+
+    DD(BlockType.BLOCK, EndKind.OPTIONAL,
+            EnumSet.of(Flag.EXPECT_CONTENT)),
+
+    DIV,
+
+    DL(BlockType.BLOCK, EndKind.REQUIRED,
+            EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_TEXT),
+            attrs(AttrKind.USE_CSS, COMPACT)),
+
+    DT(BlockType.BLOCK, EndKind.OPTIONAL,
+            EnumSet.of(Flag.EXPECT_CONTENT)),
+
+    EM(BlockType.INLINE, EndKind.REQUIRED,
+            EnumSet.of(Flag.NO_NEST)),
+
+    FONT(BlockType.INLINE, EndKind.REQUIRED, // tag itself is deprecated
+            EnumSet.of(Flag.EXPECT_CONTENT),
+            attrs(AttrKind.USE_CSS, SIZE, COLOR, FACE)),
+
+    FRAME(BlockType.OTHER, EndKind.NONE),
+
+    FRAMESET(BlockType.OTHER, EndKind.REQUIRED),
+
+    H1,
+    H2,
+    H3,
+    H4,
+    H5,
+    H6,
+
+    HEAD(BlockType.OTHER, EndKind.REQUIRED),
+
+    HR(BlockType.BLOCK, EndKind.NONE),
+
+    HTML(BlockType.OTHER, EndKind.REQUIRED),
+
+    I(BlockType.INLINE, EndKind.REQUIRED,
+            EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
+
+    IMG(BlockType.INLINE, EndKind.NONE,
+            attrs(AttrKind.OK, SRC, ALT, HEIGHT, WIDTH),
+            attrs(AttrKind.OBSOLETE, NAME),
+            attrs(AttrKind.USE_CSS, ALIGN, HSPACE, VSPACE, BORDER)),
+
+    LI(BlockType.BLOCK, EndKind.OPTIONAL),
+
+    LINK(BlockType.OTHER, EndKind.NONE),
+
+    MENU,
+
+    META(BlockType.OTHER, EndKind.NONE),
+
+    NOFRAMES(BlockType.OTHER, EndKind.REQUIRED),
+
+    NOSCRIPT(BlockType.OTHER, EndKind.REQUIRED),
+
+    OL(BlockType.BLOCK, EndKind.REQUIRED,
+            EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_TEXT),
+            attrs(AttrKind.USE_CSS, START, TYPE)),
+
+    P(BlockType.BLOCK, EndKind.OPTIONAL,
+            EnumSet.of(Flag.EXPECT_CONTENT),
+            attrs(AttrKind.USE_CSS, ALIGN)),
+
+    PRE(EnumSet.of(Flag.EXPECT_CONTENT)),
+
+    SCRIPT(BlockType.OTHER, EndKind.REQUIRED),
+
+    SMALL(BlockType.INLINE, EndKind.REQUIRED),
+
+    SPAN(BlockType.INLINE, EndKind.REQUIRED,
+            EnumSet.of(Flag.EXPECT_CONTENT)),
+
+    STRONG(BlockType.INLINE, EndKind.REQUIRED,
+            EnumSet.of(Flag.EXPECT_CONTENT)),
+
+    SUB(BlockType.INLINE, EndKind.REQUIRED,
+            EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
+
+    SUP(BlockType.INLINE, EndKind.REQUIRED,
+            EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
+
+    TABLE(BlockType.BLOCK, EndKind.REQUIRED,
+            EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_TEXT),
+            attrs(AttrKind.OK, SUMMARY, Attr.FRAME, RULES, BORDER,
+                CELLPADDING, CELLSPACING),
+            attrs(AttrKind.USE_CSS, ALIGN, WIDTH, BGCOLOR)),
+
+    TBODY(BlockType.BLOCK, EndKind.REQUIRED,
+            EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_TEXT),
+            attrs(AttrKind.OK, ALIGN, CHAR, CHAROFF, VALIGN)),
+
+    TD(BlockType.BLOCK, EndKind.OPTIONAL,
+            attrs(AttrKind.OK, COLSPAN, ROWSPAN, HEADERS, SCOPE, ABBR, AXIS,
+                ALIGN, CHAR, CHAROFF, VALIGN),
+            attrs(AttrKind.USE_CSS, WIDTH, BGCOLOR, HEIGHT, NOWRAP)),
+
+    TFOOT(BlockType.BLOCK, EndKind.REQUIRED,
+            attrs(AttrKind.OK, ALIGN, CHAR, CHAROFF, VALIGN)),
+
+    TH(BlockType.BLOCK, EndKind.OPTIONAL,
+            attrs(AttrKind.OK, COLSPAN, ROWSPAN, HEADERS, SCOPE, ABBR, AXIS,
+                ALIGN, CHAR, CHAROFF, VALIGN),
+            attrs(AttrKind.USE_CSS, WIDTH, BGCOLOR, HEIGHT, NOWRAP)),
+
+    THEAD(BlockType.BLOCK, EndKind.REQUIRED,
+            attrs(AttrKind.OK, ALIGN, CHAR, CHAROFF, VALIGN)),
+
+    TITLE(BlockType.OTHER, EndKind.REQUIRED),
+
+    TR(BlockType.BLOCK, EndKind.OPTIONAL,
+            EnumSet.of(Flag.NO_TEXT),
+            attrs(AttrKind.OK, ALIGN, CHAR, CHAROFF, VALIGN),
+            attrs(AttrKind.USE_CSS, BGCOLOR)),
+
+    TT(BlockType.INLINE, EndKind.REQUIRED,
+            EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
+
+    U(BlockType.INLINE, EndKind.REQUIRED,
+            EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)),
+
+    UL(BlockType.BLOCK, EndKind.REQUIRED,
+            EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_TEXT),
+            attrs(AttrKind.USE_CSS, COMPACT, TYPE)),
+
+    VAR(BlockType.INLINE, EndKind.REQUIRED);
+
+    /**
+     * Enum representing the type of HTML element.
+     */
+    public static enum BlockType {
+        BLOCK,
+        INLINE,
+        OTHER;
+    }
+
+    /**
+     * Enum representing HTML end tag requirement.
+     */
+    public static enum EndKind {
+        NONE,
+        OPTIONAL,
+        REQUIRED;
+    }
+
+    public static enum Flag {
+        EXPECT_CONTENT,
+        NO_NEST,
+        NO_TEXT
+    }
+
+    public static enum Attr {
+        ABBR,
+        ALIGN,
+        ALT,
+        AXIS,
+        BGCOLOR,
+        BORDER,
+        CELLSPACING,
+        CELLPADDING,
+        CHAR,
+        CHAROFF,
+        CLEAR,
+        CLASS,
+        COLOR,
+        COLSPAN,
+        COMPACT,
+        FACE,
+        FRAME,
+        HEADERS,
+        HEIGHT,
+        HREF,
+        HSPACE,
+        ID,
+        NAME,
+        NOWRAP,
+        REVERSED,
+        ROWSPAN,
+        RULES,
+        SCOPE,
+        SIZE,
+        SPACE,
+        SRC,
+        START,
+        STYLE,
+        SUMMARY,
+        TARGET,
+        TYPE,
+        VALIGN,
+        VSPACE,
+        WIDTH;
+
+        public String getText() {
+            return name().toLowerCase();
+        }
+
+        static final Map<String,Attr> index = new HashMap<String,Attr>();
+        static {
+            for (Attr t: values()) {
+                index.put(t.name().toLowerCase(), t);
+            }
+        }
+    }
+
+    public static enum AttrKind {
+        INVALID,
+        OBSOLETE,
+        USE_CSS,
+        OK
+    }
+
+    // This class exists to avoid warnings from using parameterized vararg type
+    // Map<Attr,AttrKind> in signature of HtmlTag constructor.
+    private static class AttrMap extends EnumMap<Attr,AttrKind>  {
+        private static final long serialVersionUID = 0;
+        AttrMap() {
+            super(Attr.class);
+        }
+    }
+
+
+    public final BlockType blockType;
+    public final EndKind endKind;
+    public final Set<Flag> flags;
+    private final Map<Attr,AttrKind> attrs;
+
+
+    HtmlTag() {
+        this(BlockType.BLOCK, EndKind.REQUIRED);
+    }
+
+    HtmlTag(Set<Flag> flags) {
+        this(BlockType.BLOCK, EndKind.REQUIRED, flags);
+    }
+
+    HtmlTag(BlockType blockType, EndKind endKind, AttrMap... attrMaps) {
+        this(blockType, endKind, Collections.<Flag>emptySet(), attrMaps);
+    }
+
+    HtmlTag(BlockType blockType, EndKind endKind, Set<Flag> flags, AttrMap... attrMaps) {
+        this.blockType = blockType;
+        this.endKind = endKind;this.flags = flags;
+        this.attrs = new EnumMap<Attr,AttrKind>(Attr.class);
+        for (Map<Attr,AttrKind> m: attrMaps)
+            this.attrs.putAll(m);
+        attrs.put(Attr.CLASS, AttrKind.OK);
+        attrs.put(Attr.ID, AttrKind.OK);
+        attrs.put(Attr.STYLE, AttrKind.OK);
+    }
+
+    public String getText() {
+        return name().toLowerCase();
+    }
+
+    public Attr getAttr(Name attrName) {
+        return Attr.index.get(attrName.toString().toLowerCase());
+    }
+
+    public AttrKind getAttrKind(Name attrName) {
+        AttrKind k = attrs.get(getAttr(attrName)); // null-safe
+        return (k == null) ? AttrKind.INVALID : k;
+    }
+
+    private static AttrMap attrs(AttrKind k, Attr... attrs) {
+        AttrMap map = new AttrMap();
+        for (Attr a: attrs) map.put(a, k);
+        return map;
+    }
+
+    private static final Map<String,HtmlTag> index = new HashMap<String,HtmlTag>();
+    static {
+        for (HtmlTag t: values()) {
+            index.put(t.name().toLowerCase(), t);
+        }
+    }
+
+    static HtmlTag get(Name tagName) {
+        return index.get(tagName.toString().toLowerCase());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/doclint/Messages.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,348 @@
+/*
+ * 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 com.sun.tools.doclint;
+
+import java.io.PrintWriter;
+import java.text.MessageFormat;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import javax.tools.Diagnostic;
+
+import com.sun.source.doctree.DocTree;
+import com.sun.source.tree.Tree;
+import com.sun.tools.doclint.Env.AccessKind;
+
+/**
+ * Message reporting for DocLint.
+ *
+ * Options are used to filter out messages based on group and access level.
+ * Support can be enabled for accumulating statistics of different kinds of
+ * messages.
+ *
+ * <p><b>This is NOT part of any supported API.
+ * If you write code that depends on this, you do so at your own
+ * risk.  This code and its internal interfaces are subject to change
+ * or deletion without notice.</b></p>
+ */
+public class Messages {
+    /**
+     * Groups used to categorize messages, so that messages in each group
+     * can be enabled or disabled via options.
+     */
+    public enum Group {
+        ACCESSIBILITY,
+        HTML,
+        MISSING,
+        SYNTAX,
+        REFERENCE;
+
+        String optName() { return name().toLowerCase(); }
+        String notOptName() { return "-" + optName(); }
+
+        static boolean accepts(String opt) {
+            for (Group g: values())
+                if (opt.equals(g.optName())) return true;
+            return false;
+        }
+    };
+
+    private final Options options;
+    private final Stats stats;
+
+    ResourceBundle bundle;
+    Env env;
+
+    Messages(Env env) {
+        this.env = env;
+        String name = getClass().getPackage().getName() + ".resources.doclint";
+        bundle = ResourceBundle.getBundle(name, Locale.ENGLISH);
+
+        stats = new Stats(bundle);
+        options = new Options(stats);
+    }
+
+    void error(Group group, DocTree tree, String code, Object... args) {
+        report(group, Diagnostic.Kind.ERROR, tree, code, args);
+    }
+
+    void warning(Group group, DocTree tree, String code, Object... args) {
+        report(group, Diagnostic.Kind.WARNING, tree, code, args);
+    }
+
+    void setOptions(String opts) {
+        options.setOptions(opts);
+    }
+
+    void setStatsEnabled(boolean b) {
+        stats.setEnabled(b);
+    }
+
+    void reportStats(PrintWriter out) {
+        stats.report(out);
+    }
+
+    protected void report(Group group, Diagnostic.Kind dkind, DocTree tree, String code, Object... args) {
+        if (options.isEnabled(group, env.currAccess)) {
+            String msg = (code == null) ? (String) args[0] : localize(code, args);
+            env.trees.printMessage(dkind, msg, tree,
+                    env.currDocComment, env.currPath.getCompilationUnit());
+
+            stats.record(group, dkind, code);
+        }
+    }
+
+    protected void report(Group group, Diagnostic.Kind dkind, Tree tree, String code, Object... args) {
+        if (options.isEnabled(group, env.currAccess)) {
+            String msg = localize(code, args);
+            env.trees.printMessage(dkind, msg, tree, env.currPath.getCompilationUnit());
+
+            stats.record(group, dkind, code);
+        }
+    }
+
+    String localize(String code, Object... args) {
+        String msg = bundle.getString(code);
+        if (msg == null) {
+            StringBuilder sb = new StringBuilder();
+            sb.append("message file broken: code=").append(code);
+            if (args.length > 0) {
+                sb.append(" arguments={0}");
+                for (int i = 1; i < args.length; i++) {
+                    sb.append(", {").append(i).append("}");
+                }
+            }
+            msg = sb.toString();
+        }
+        return MessageFormat.format(msg, args);
+    }
+
+    // <editor-fold defaultstate="collapsed" desc="Options">
+
+    /**
+     * Handler for (sub)options specific to message handling.
+     */
+    static class Options {
+        Map<String, Env.AccessKind> map = new HashMap<String, Env.AccessKind>();
+        private final Stats stats;
+
+        static boolean isValidOptions(String opts) {
+            for (String opt: opts.split(",")) {
+                if (!isValidOption(opt.trim().toLowerCase()))
+                    return false;
+            }
+            return true;
+        }
+
+        private static boolean isValidOption(String opt) {
+            if (opt.equals("none") || opt.equals(Stats.OPT))
+                return true;
+
+            int begin = opt.startsWith("-") ? 1 : 0;
+            int sep = opt.indexOf("/");
+            String grp = opt.substring(begin, (sep != -1) ? sep : opt.length());
+            return ((begin == 0 && grp.equals("all")) || Group.accepts(grp))
+                    && ((sep == -1) || AccessKind.accepts(opt.substring(sep + 1)));
+        }
+
+        Options(Stats stats) {
+            this.stats = stats;
+        }
+
+        /** Determine if a message group is enabled for a particular access level. */
+        boolean isEnabled(Group g, Env.AccessKind access) {
+            if (map.isEmpty())
+                map.put("all", Env.AccessKind.PROTECTED);
+
+            Env.AccessKind ak = map.get(g.optName());
+            if (ak != null && access.compareTo(ak) >= 0)
+                return true;
+
+            ak = map.get(ALL);
+            if (ak != null && access.compareTo(ak) >= 0) {
+                ak = map.get(g.notOptName());
+                if (ak == null || access.compareTo(ak) > 0) // note >, not >=
+                    return true;
+            }
+
+            return false;
+        }
+
+        void setOptions(String opts) {
+            if (opts == null)
+                setOption(ALL, Env.AccessKind.PRIVATE);
+            else {
+                for (String opt: opts.split(","))
+                    setOption(opt.trim().toLowerCase());
+            }
+        }
+
+        private void setOption(String arg) throws IllegalArgumentException {
+            if (arg.equals(Stats.OPT)) {
+                stats.setEnabled(true);
+                return;
+            }
+
+            int sep = arg.indexOf("/");
+            if (sep > 0) {
+                Env.AccessKind ak = Env.AccessKind.valueOf(arg.substring(sep + 1).toUpperCase());
+                setOption(arg.substring(0, sep), ak);
+            } else {
+                setOption(arg, null);
+            }
+        }
+
+        private void setOption(String opt, Env.AccessKind ak) {
+            map.put(opt, (ak != null) ? ak
+                    : opt.startsWith("-") ? Env.AccessKind.PUBLIC : Env.AccessKind.PRIVATE);
+        }
+
+        private static final String ALL = "all";
+    }
+
+    // </editor-fold>
+
+    // <editor-fold defaultstate="collapsed" desc="Statistics">
+
+    /**
+     * Optionally record statistics of different kinds of message.
+     */
+    static class Stats {
+        public static final String OPT = "stats";
+        public static final String NO_CODE = "";
+        final ResourceBundle bundle;
+
+        // tables only initialized if enabled
+        int[] groupCounts;
+        int[] dkindCounts;
+        Map<String, Integer> codeCounts;
+
+        Stats(ResourceBundle bundle) {
+            this.bundle = bundle;
+        }
+
+        void setEnabled(boolean b) {
+            if (b) {
+                groupCounts = new int[Messages.Group.values().length];
+                dkindCounts = new int[Diagnostic.Kind.values().length];
+                codeCounts = new HashMap<String, Integer>();
+            } else {
+                groupCounts = null;
+                dkindCounts = null;
+                codeCounts = null;
+            }
+        }
+
+        void record(Messages.Group g, Diagnostic.Kind dkind, String code) {
+            if (codeCounts == null) {
+                return;
+            }
+            groupCounts[g.ordinal()]++;
+            dkindCounts[dkind.ordinal()]++;
+            if (code == null) {
+                code = NO_CODE;
+            }
+            Integer i = codeCounts.get(code);
+            codeCounts.put(code, (i == null) ? 1 : i + 1);
+        }
+
+        void report(PrintWriter out) {
+            if (codeCounts == null) {
+                return;
+            }
+            out.println("By group...");
+            Table groupTable = new Table();
+            for (Messages.Group g : Messages.Group.values()) {
+                groupTable.put(g.optName(), groupCounts[g.ordinal()]);
+            }
+            groupTable.print(out);
+            out.println();
+            out.println("By diagnostic kind...");
+            Table dkindTable = new Table();
+            for (Diagnostic.Kind k : Diagnostic.Kind.values()) {
+                dkindTable.put(k.toString().toLowerCase(), dkindCounts[k.ordinal()]);
+            }
+            dkindTable.print(out);
+            out.println();
+            out.println("By message kind...");
+            Table codeTable = new Table();
+            for (Map.Entry<String, Integer> e : codeCounts.entrySet()) {
+                String code = e.getKey();
+                String msg;
+                try {
+                    msg = code.equals(NO_CODE) ? "OTHER" : bundle.getString(code);
+                } catch (MissingResourceException ex) {
+                    msg = code;
+                }
+                codeTable.put(msg, e.getValue());
+            }
+            codeTable.print(out);
+        }
+
+        /**
+         * A table of (int, String) sorted by decreasing int.
+         */
+        private static class Table {
+
+            private static final Comparator<Integer> DECREASING = new Comparator<Integer>() {
+
+                public int compare(Integer o1, Integer o2) {
+                    return o2.compareTo(o1);
+                }
+            };
+            private final TreeMap<Integer, Set<String>> map = new TreeMap<Integer, Set<String>>(DECREASING);
+
+            void put(String label, int n) {
+                if (n == 0) {
+                    return;
+                }
+                Set<String> labels = map.get(n);
+                if (labels == null) {
+                    map.put(n, labels = new TreeSet<String>());
+                }
+                labels.add(label);
+            }
+
+            void print(PrintWriter out) {
+                for (Map.Entry<Integer, Set<String>> e : map.entrySet()) {
+                    int count = e.getKey();
+                    Set<String> labels = e.getValue();
+                    for (String label : labels) {
+                        out.println(String.format("%6d: %s", count, label));
+                    }
+                }
+            }
+        }
+    }
+    // </editor-fold>
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/doclint/resources/doclint.properties	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,65 @@
+#
+# 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.
+#
+
+dc.anchor.already.defined = anchor already defined: {0}
+dc.attr.lacks.value = attribute lacks value
+dc.attr.obsolete = attribute obsolete: {0}
+dc.attr.obsolete.use.css = attribute obsolete, use CSS instead: {0}
+dc.attr.repeated = repeated attribute: {0}
+dc.attr.unknown = unknown attribute: {0}
+dc.bad.option = bad option: {0}
+dc.bad.value.for.option = bad value for option: {0} {1}
+dc.empty = no description for @{0}
+dc.entity.invalid = invalid entity &{0};
+dc.exception.not.thrown = exception not thrown: {0}
+dc.invalid.anchor = invalid name for anchor: "{0}"
+dc.invalid.param = invalid use of @param
+dc.invalid.return = invalid use of @return
+dc.invalid.throws = invalid use of @throws
+dc.invalid.uri = invalid uri: "{0}"
+dc.missing.comment = no comment
+dc.missing.param = no @param for {0}
+dc.missing.return = no @return
+dc.missing.throws = no @throws for {0}
+dc.no.alt.attr.for.image = no "alt" attribute for image
+dc.no.summary.or.caption.for.table=no summary or caption for table
+dc.param.name.not.found = @param name not found
+dc.ref.not.found = reference not found
+dc.tag.empty = empty <{0}> tag
+dc.tag.end.not.permitted = invalid end tag: </{0}>
+dc.tag.end.unexpected = unexpected end tag: </{0}>
+dc.tag.header.sequence.1 = header used out of sequence: <{0}>
+dc.tag.header.sequence.2 = header used out of sequence: <{0}>
+dc.tag.nested.not.allowed=nested tag not allowed: <{0}>
+dc.tag.not.allowed = element not allowed in documentation comments: <{0}>
+dc.tag.not.allowed.inline.element = block element not allowed within inline element <{1}>: {0}
+dc.tag.not.allowed.inline.tag = block element not allowed within @{1}: {0}
+dc.tag.not.allowed.inline.other = block element not allowed here: {0}
+dc.tag.not.closed= element not closed: {0}
+dc.tag.p.in.pre= unexpected use of <p> inside <pre> element
+dc.tag.self.closing = self-closing element not allowed
+dc.tag.start.unmatched = end tag missing: </{0}>
+dc.tag.unknown = unknown tag: {0}
+dc.text.not.allowed = text not allowed in <{0}> element
--- a/langtools/src/share/classes/com/sun/tools/javac/api/BasicJavacTask.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/api/BasicJavacTask.java	Wed Jul 05 18:34:52 2017 +0200
@@ -57,6 +57,13 @@
     protected Context context;
     private TaskListener taskListener;
 
+    public static JavacTask instance(Context context) {
+        JavacTask instance = context.get(JavacTask.class);
+        if (instance == null)
+            instance = new BasicJavacTask(context, true);
+        return instance;
+    }
+
     public BasicJavacTask(Context c, boolean register) {
         context = c;
         if (register)
--- a/langtools/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java	Wed Jul 05 18:34:52 2017 +0200
@@ -65,7 +65,6 @@
  * @author Jonathan Gibbons
  */
 public class JavacTaskImpl extends BasicJavacTask {
-    private ClientCodeWrapper ccw;
     private Main compilerMain;
     private JavaCompiler compiler;
     private Locale locale;
@@ -85,7 +84,6 @@
                 Context context,
                 List<JavaFileObject> fileObjects) {
         super(null, false);
-        this.ccw = ClientCodeWrapper.instance(context);
         this.compilerMain = compilerMain;
         this.args = args;
         this.classNames = classNames;
--- a/langtools/src/share/classes/com/sun/tools/javac/api/JavacTool.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/api/JavacTool.java	Wed Jul 05 18:34:52 2017 +0200
@@ -159,7 +159,7 @@
         }
     }
 
-    private static void processOptions(Context context,
+    public static void processOptions(Context context,
                                        JavaFileManager fileManager,
                                        Iterable<String> options)
     {
--- a/langtools/src/share/classes/com/sun/tools/javac/api/JavacTrees.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/api/JavacTrees.java	Wed Jul 05 18:34:52 2017 +0200
@@ -84,6 +84,7 @@
 import com.sun.tools.javac.tree.TreeCopier;
 import com.sun.tools.javac.tree.TreeInfo;
 import com.sun.tools.javac.tree.TreeMaker;
+import com.sun.tools.javac.util.Abort;
 import com.sun.tools.javac.util.Assert;
 import com.sun.tools.javac.util.Context;
 import com.sun.tools.javac.util.JCDiagnostic;
@@ -236,19 +237,26 @@
     public Element getElement(TreePath path) {
         JCTree tree = (JCTree) path.getLeaf();
         Symbol sym = TreeInfo.symbolFor(tree);
-        if (sym == null && TreeInfo.isDeclaration(tree)) {
-            for (TreePath p = path; p != null; p = p.getParentPath()) {
-                JCTree t = (JCTree) p.getLeaf();
-                if (t.hasTag(JCTree.Tag.CLASSDEF)) {
-                    JCClassDecl ct = (JCClassDecl) t;
-                    if (ct.sym != null) {
-                        if ((ct.sym.flags_field & Flags.UNATTRIBUTED) != 0) {
-                            attr.attribClass(ct.pos(), ct.sym);
-                            sym = TreeInfo.symbolFor(tree);
+        if (sym == null) {
+            if (TreeInfo.isDeclaration(tree)) {
+                for (TreePath p = path; p != null; p = p.getParentPath()) {
+                    JCTree t = (JCTree) p.getLeaf();
+                    if (t.hasTag(JCTree.Tag.CLASSDEF)) {
+                        JCClassDecl ct = (JCClassDecl) t;
+                        if (ct.sym != null) {
+                            if ((ct.sym.flags_field & Flags.UNATTRIBUTED) != 0) {
+                                attr.attribClass(ct.pos(), ct.sym);
+                                sym = TreeInfo.symbolFor(tree);
+                            }
+                            break;
                         }
-                        break;
                     }
                 }
+            } else if (tree.hasTag(Tag.TOPLEVEL)) {
+                JCCompilationUnit cu = (JCCompilationUnit) tree;
+                if (cu.sourcefile.isNameCompatible("package-info", JavaFileObject.Kind.SOURCE)) {
+                    sym = cu.packge;
+                }
             }
         }
         return sym;
@@ -332,6 +340,8 @@
             } else {
                 return msym;
             }
+        } catch (Abort e) { // may be thrown by Check.completionError in case of bad class file
+            return null;
         } finally {
             log.popDiagnosticHandler(deferredDiagnosticHandler);
         }
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Attribute.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Attribute.java	Wed Jul 05 18:34:52 2017 +0200
@@ -60,6 +60,9 @@
         throw new UnsupportedOperationException();
     }
 
+    public boolean isSynthesized() {
+        return false;
+    }
 
     /** The value for an annotation element of primitive type or String. */
     public static class Constant extends Attribute {
@@ -136,6 +139,18 @@
          *  access this attribute.
          */
         public final List<Pair<MethodSymbol,Attribute>> values;
+
+        private boolean synthesized = false;
+
+        @Override
+        public boolean isSynthesized() {
+            return synthesized;
+        }
+
+        public void setSynthesized(boolean synthesized) {
+            this.synthesized = synthesized;
+        }
+
         public Compound(Type type,
                         List<Pair<MethodSymbol,Attribute>> values) {
             super(type);
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java	Wed Jul 05 18:34:52 2017 +0200
@@ -83,13 +83,13 @@
      *  Attributes of class symbols should be accessed through the accessor
      *  method to make sure that the class symbol is loaded.
      */
-    public List<Attribute.Compound> getAnnotationMirrors() {
-        return Assert.checkNonNull(annotations.getAttributes());
+    public List<Attribute.Compound> getRawAttributes() {
+        return annotations.getAttributes();
     }
 
     /** Fetch a particular annotation from a symbol. */
     public Attribute.Compound attribute(Symbol anno) {
-        for (Attribute.Compound a : getAnnotationMirrors()) {
+        for (Attribute.Compound a : getRawAttributes()) {
             if (a.type.tsym == anno) return a;
         }
         return null;
@@ -447,6 +447,14 @@
     }
 
     /**
+     * This is the implementation for {@code
+     * javax.lang.model.element.Element.getAnnotationMirrors()}.
+     */
+    public final List<Attribute.Compound> getAnnotationMirrors() {
+        return getRawAttributes();
+    }
+
+    /**
      * @deprecated this method should never be used by javac internally.
      */
     @Deprecated
@@ -662,15 +670,21 @@
             return flags_field;
         }
 
-        public List<Attribute.Compound> getAnnotationMirrors() {
+        @Override
+        public List<Attribute.Compound> getRawAttributes() {
             if (completer != null) complete();
             if (package_info != null && package_info.completer != null) {
                 package_info.complete();
-                if (annotations.isEmpty()) {
-                    annotations.setAttributes(package_info.annotations);
+                mergeAttributes();
             }
+            return super.getRawAttributes();
+        }
+
+        private void mergeAttributes() {
+            if (annotations.isEmpty() &&
+                !package_info.annotations.isEmpty()) {
+                annotations.setAttributes(package_info.annotations);
             }
-            return Assert.checkNonNull(annotations.getAttributes());
         }
 
         /** A package "exists" if a type or package that exists has
@@ -770,9 +784,10 @@
             return members_field;
         }
 
-        public List<Attribute.Compound> getAnnotationMirrors() {
+        @Override
+        public List<Attribute.Compound> getRawAttributes() {
             if (completer != null) complete();
-            return Assert.checkNonNull(annotations.getAttributes());
+            return super.getRawAttributes();
         }
 
         public Type erasure(Types types) {
@@ -1353,7 +1368,7 @@
             return defaultValue;
         }
 
-        public List<VarSymbol> getParameters() {
+         public List<VarSymbol> getParameters() {
             return params();
         }
 
@@ -1361,6 +1376,10 @@
             return (flags() & VARARGS) != 0;
         }
 
+        public boolean isDefault() {
+            return (flags() & DEFAULT) != 0;
+        }
+
         public <R, P> R accept(ElementVisitor<R, P> v, P p) {
             return v.visitExecutable(this, p);
         }
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Type.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Type.java	Wed Jul 05 18:34:52 2017 +0200
@@ -302,10 +302,12 @@
      * never complete classes. Where isSameType would complete a
      * class, equals assumes that the two types are different.
      */
+    @Override
     public boolean equals(Object t) {
         return super.equals(t);
     }
 
+    @Override
     public int hashCode() {
         return super.hashCode();
     }
@@ -996,34 +998,6 @@
             return "(" + argtypes + ")" + restype;
         }
 
-        public boolean equals(Object obj) {
-            if (this == obj)
-                return true;
-            if (!(obj instanceof MethodType))
-                return false;
-            MethodType m = (MethodType)obj;
-            List<Type> args1 = argtypes;
-            List<Type> args2 = m.argtypes;
-            while (!args1.isEmpty() && !args2.isEmpty()) {
-                if (!args1.head.equals(args2.head))
-                    return false;
-                args1 = args1.tail;
-                args2 = args2.tail;
-            }
-            if (!args1.isEmpty() || !args2.isEmpty())
-                return false;
-            return restype.equals(m.restype);
-        }
-
-        public int hashCode() {
-            int h = METHOD.ordinal();
-            for (List<Type> thisargs = this.argtypes;
-                 thisargs.tail != null; /*inlined: thisargs.nonEmpty()*/
-                 thisargs = thisargs.tail)
-                h = (h << 5) + thisargs.head.hashCode();
-            return (h << 5) + this.restype.hashCode();
-        }
-
         public List<Type>        getParameterTypes() { return argtypes; }
         public Type              getReturnType()     { return restype; }
         public List<Type>        getThrownTypes()    { return thrown; }
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java	Wed Jul 05 18:34:52 2017 +0200
@@ -1007,11 +1007,11 @@
                     if (!visit(supertype(t), supertype(s)))
                         return false;
 
-                    HashSet<SingletonType> set = new HashSet<SingletonType>();
+                    HashSet<UniqueType> set = new HashSet<UniqueType>();
                     for (Type x : interfaces(t))
-                        set.add(new SingletonType(x));
+                        set.add(new UniqueType(x, Types.this));
                     for (Type x : interfaces(s)) {
-                        if (!set.remove(new SingletonType(x)))
+                        if (!set.remove(new UniqueType(x, Types.this)))
                             return false;
                     }
                     return (set.isEmpty());
@@ -3137,7 +3137,7 @@
             }
             @Override
             public int hashCode() {
-                return 127 * Types.hashCode(t1) + Types.hashCode(t2);
+                return 127 * Types.this.hashCode(t1) + Types.this.hashCode(t2);
             }
             @Override
             public boolean equals(Object obj) {
@@ -3400,7 +3400,7 @@
     /**
      * Compute a hash code on a type.
      */
-    public static int hashCode(Type t) {
+    public int hashCode(Type t) {
         return hashCode.visit(t);
     }
     // where
@@ -3423,6 +3423,16 @@
             }
 
             @Override
+            public Integer visitMethodType(MethodType t, Void ignored) {
+                int h = METHOD.ordinal();
+                for (List<Type> thisargs = t.argtypes;
+                     thisargs.tail != null;
+                     thisargs = thisargs.tail)
+                    h = (h << 5) + visit(thisargs.head);
+                return (h << 5) + visit(t.restype);
+            }
+
+            @Override
             public Integer visitWildcardType(WildcardType t, Void ignored) {
                 int result = t.kind.hashCode();
                 if (t.type != null) {
@@ -4082,21 +4092,28 @@
     /**
      * A wrapper for a type that allows use in sets.
      */
-    class SingletonType {
-        final Type t;
-        SingletonType(Type t) {
-            this.t = t;
-        }
-        public int hashCode() {
-            return Types.hashCode(t);
+    public static class UniqueType {
+        public final Type type;
+        final Types types;
+
+        public UniqueType(Type type, Types types) {
+            this.type = type;
+            this.types = types;
         }
-        public boolean equals(Object obj) {
-            return (obj instanceof SingletonType) &&
-                isSameType(t, ((SingletonType)obj).t);
+
+        public int hashCode() {
+            return types.hashCode(type);
         }
+
+        public boolean equals(Object obj) {
+            return (obj instanceof UniqueType) &&
+                types.isSameType(type, ((UniqueType)obj).type);
+        }
+
         public String toString() {
-            return t.toString();
+            return type.toString();
         }
+
     }
     // </editor-fold>
 
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java	Wed Jul 05 18:34:52 2017 +0200
@@ -400,6 +400,7 @@
             Attribute.Compound c = enterAnnotation(annoTree,
                                                    targetContainerType,
                                                    ctx.env);
+            c.setSynthesized(true);
             return c;
         } else {
             return null; // errors should have been reported elsewhere
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java	Wed Jul 05 18:34:52 2017 +0200
@@ -1405,7 +1405,8 @@
         Type owntype = standaloneConditional ? condType(tree, truetype, falsetype) : pt();
         if (condtype.constValue() != null &&
                 truetype.constValue() != null &&
-                falsetype.constValue() != null) {
+                falsetype.constValue() != null &&
+                !owntype.hasTag(NONE)) {
             //constant folding
             owntype = cfolder.coerce(condtype.isTrue() ? truetype : falsetype, owntype);
         }
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Wed Jul 05 18:34:52 2017 +0200
@@ -692,8 +692,9 @@
         //determine the static bsm args
         Type mtype = makeFunctionalDescriptorType(targetType, true);
         List<Object> staticArgs = List.<Object>of(
-                new Pool.MethodHandle(ClassFile.REF_invokeInterface, types.findDescriptorSymbol(targetType.tsym)),
-                new Pool.MethodHandle(refKind, refSym),
+                new Pool.MethodHandle(ClassFile.REF_invokeInterface,
+                    types.findDescriptorSymbol(targetType.tsym), types),
+                new Pool.MethodHandle(refKind, refSym, types),
                 new MethodType(mtype.getParameterTypes(),
                         mtype.getReturnType(),
                         mtype.getThrownTypes(),
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Wed Jul 05 18:34:52 2017 +0200
@@ -1798,6 +1798,9 @@
 
         if ((kind & TYP) != 0) {
             sym = findType(env, name);
+            if (sym.kind==TYP) {
+                 reportDependence(env.enclClass.sym, sym);
+            }
             if (sym.exists()) return sym;
             else if (sym.kind < bestSoFar.kind) bestSoFar = sym;
         }
@@ -1806,6 +1809,14 @@
         else return bestSoFar;
     }
 
+    /** Report dependencies.
+     * @param from The enclosing class sym
+     * @param to   The found identifier that the class depends on.
+     */
+    public void reportDependence(Symbol from, Symbol to) {
+        // Override if you want to collect the reported dependencies.
+    }
+
     /** Find an identifier in a package which matches a specified kind set.
      *  @param env       The current environment.
      *  @param name      The identifier's name.
@@ -3064,16 +3075,20 @@
             if (hasLocation) {
                 return diags.create(dkind, log.currentSource(), pos,
                         errKey, kindname, idname, //symbol kindname, name
-                        typeargtypes, argtypes, //type parameters and arguments (if any)
+                        typeargtypes, args(argtypes), //type parameters and arguments (if any)
                         getLocationDiag(location, site)); //location kindname, type
             }
             else {
                 return diags.create(dkind, log.currentSource(), pos,
                         errKey, kindname, idname, //symbol kindname, name
-                        typeargtypes, argtypes); //type parameters and arguments (if any)
+                        typeargtypes, args(argtypes)); //type parameters and arguments (if any)
             }
         }
         //where
+        private Object args(List<Type> args) {
+            return args.isEmpty() ? args : methodArguments(args);
+        }
+
         private String getErrorKey(KindName kindname, boolean hasTypeArgs, boolean hasLocation) {
             String key = "cant.resolve";
             String suffix = hasLocation ? ".location" : "";
--- a/langtools/src/share/classes/com/sun/tools/javac/file/ZipFileIndex.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/file/ZipFileIndex.java	Wed Jul 05 18:34:52 2017 +0200
@@ -548,17 +548,15 @@
                 }
 
                 if (i >= 0) {
-                    zipDir = new byte[get4ByteLittleEndian(endbuf, i + 12) + 2];
-                    zipDir[0] = endbuf[i + 10];
-                    zipDir[1] = endbuf[i + 11];
+                    zipDir = new byte[get4ByteLittleEndian(endbuf, i + 12)];
                     int sz = get4ByteLittleEndian(endbuf, i + 16);
                     // a negative offset or the entries field indicates a
                     // potential zip64 archive
-                    if (sz < 0 || get2ByteLittleEndian(zipDir, 0) == 0xffff) {
+                    if (sz < 0 || get2ByteLittleEndian(endbuf, i + 10) == 0xffff) {
                         throw new ZipFormatException("detected a zip64 archive");
                     }
                     zipRandomFile.seek(start + sz);
-                    zipRandomFile.readFully(zipDir, 2, zipDir.length - 2);
+                    zipRandomFile.readFully(zipDir, 0, zipDir.length);
                     return;
                 } else {
                     endbufend = endbufpos + 21;
@@ -568,14 +566,13 @@
         }
 
         private void buildIndex() throws IOException {
-            int entryCount = get2ByteLittleEndian(zipDir, 0);
+            int len = zipDir.length;
 
             // Add each of the files
-            if (entryCount > 0) {
+            if (len > 0) {
                 directories = new LinkedHashMap<RelativeDirectory, DirectoryEntry>();
                 ArrayList<Entry> entryList = new ArrayList<Entry>();
-                int pos = 2;
-                for (int i = 0; i < entryCount; i++) {
+                for (int pos = 0; pos < len; ) {
                     pos = readEntry(pos, entryList, directories);
                 }
 
--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassFile.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassFile.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,6 +26,8 @@
 package com.sun.tools.javac.jvm;
 
 import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.code.Types;
+import com.sun.tools.javac.code.Types.UniqueType;
 import com.sun.tools.javac.util.Name;
 
 
@@ -166,22 +168,29 @@
      */
     public static class NameAndType {
         Name name;
-        Type type;
+        UniqueType uniqueType;
+        Types types;
 
-        NameAndType(Name name, Type type) {
+        NameAndType(Name name, Type type, Types types) {
             this.name = name;
-            this.type = type;
+            this.uniqueType = new UniqueType(type, types);
+            this.types = types;
         }
 
-        public boolean equals(Object other) {
-            return
-                other instanceof NameAndType &&
-                name == ((NameAndType) other).name &&
-                type.equals(((NameAndType) other).type);
+        void setType(Type type) {
+            this.uniqueType = new UniqueType(type, types);
         }
 
+        @Override
+        public boolean equals(Object other) {
+            return (other instanceof NameAndType &&
+                    name == ((NameAndType) other).name &&
+                        uniqueType.equals(((NameAndType) other).uniqueType));
+        }
+
+        @Override
         public int hashCode() {
-            return name.hashCode() * type.hashCode();
+            return name.hashCode() * uniqueType.hashCode();
         }
     }
 }
--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Wed Jul 05 18:34:52 2017 +0200
@@ -488,20 +488,20 @@
         case CONSTANT_Fieldref: {
             ClassSymbol owner = readClassSymbol(getChar(index + 1));
             NameAndType nt = (NameAndType)readPool(getChar(index + 3));
-            poolObj[i] = new VarSymbol(0, nt.name, nt.type, owner);
+            poolObj[i] = new VarSymbol(0, nt.name, nt.uniqueType.type, owner);
             break;
         }
         case CONSTANT_Methodref:
         case CONSTANT_InterfaceMethodref: {
             ClassSymbol owner = readClassSymbol(getChar(index + 1));
             NameAndType nt = (NameAndType)readPool(getChar(index + 3));
-            poolObj[i] = new MethodSymbol(0, nt.name, nt.type, owner);
+            poolObj[i] = new MethodSymbol(0, nt.name, nt.uniqueType.type, owner);
             break;
         }
         case CONSTANT_NameandType:
             poolObj[i] = new NameAndType(
                 readName(getChar(index + 1)),
-                readType(getChar(index + 3)));
+                readType(getChar(index + 3)), types);
             break;
         case CONSTANT_Integer:
             poolObj[i] = getInt(index + 1);
@@ -1224,7 +1224,7 @@
         if (nt == null)
             return null;
 
-        MethodType type = nt.type.asMethodType();
+        MethodType type = nt.uniqueType.type.asMethodType();
 
         for (Scope.Entry e = scope.lookup(nt.name); e.scope != null; e = e.next())
             if (e.sym.kind == MTH && isSameBinaryType(e.sym.type.asMethodType(), type))
@@ -1236,16 +1236,16 @@
         if ((flags & INTERFACE) != 0)
             // no enclosing instance
             return null;
-        if (nt.type.getParameterTypes().isEmpty())
+        if (nt.uniqueType.type.getParameterTypes().isEmpty())
             // no parameters
             return null;
 
         // A constructor of an inner class.
         // Remove the first argument (the enclosing instance)
-        nt.type = new MethodType(nt.type.getParameterTypes().tail,
-                                 nt.type.getReturnType(),
-                                 nt.type.getThrownTypes(),
-                                 syms.methodClass);
+        nt.setType(new MethodType(nt.uniqueType.type.getParameterTypes().tail,
+                                 nt.uniqueType.type.getReturnType(),
+                                 nt.uniqueType.type.getThrownTypes(),
+                                 syms.methodClass));
         // Try searching again
         return findMethod(nt, scope, flags);
     }
@@ -1959,7 +1959,7 @@
 
         if (readAllOfClassFile) {
             for (int i = 1; i < poolObj.length; i++) readPool(i);
-            c.pool = new Pool(poolObj.length, poolObj);
+            c.pool = new Pool(poolObj.length, poolObj, types);
         }
 
         // reset and read rest of classinfo
--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Wed Jul 05 18:34:52 2017 +0200
@@ -39,7 +39,12 @@
 import com.sun.tools.javac.code.Attribute.RetentionPolicy;
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.code.Type.*;
+import com.sun.tools.javac.code.Types.UniqueType;
 import com.sun.tools.javac.file.BaseFileObject;
+import com.sun.tools.javac.jvm.Pool.DynamicMethod;
+import com.sun.tools.javac.jvm.Pool.Method;
+import com.sun.tools.javac.jvm.Pool.MethodHandle;
+import com.sun.tools.javac.jvm.Pool.Variable;
 import com.sun.tools.javac.util.*;
 
 import static com.sun.tools.javac.code.BoundKind.*;
@@ -142,7 +147,7 @@
     /** The bootstrap methods to be written in the corresponding class attribute
      *  (one for each invokedynamic)
      */
-    Map<MethodSymbol, Pool.MethodHandle> bootstrapMethods;
+    Map<DynamicMethod, MethodHandle> bootstrapMethods;
 
     /** The log to use for verbose output.
      */
@@ -477,10 +482,10 @@
         while (i < pool.pp) {
             Object value = pool.pool[i];
             Assert.checkNonNull(value);
-            if (value instanceof Pool.Method)
-                value = ((Pool.Method)value).m;
-            else if (value instanceof Pool.Variable)
-                value = ((Pool.Variable)value).v;
+            if (value instanceof Method)
+                value = ((Method)value).m;
+            else if (value instanceof Variable)
+                value = ((Variable)value).v;
 
             if (value instanceof MethodSymbol) {
                 MethodSymbol m = (MethodSymbol)value;
@@ -493,8 +498,9 @@
                 } else {
                     //invokedynamic
                     DynamicMethodSymbol dynSym = (DynamicMethodSymbol)m;
-                    Pool.MethodHandle handle = new Pool.MethodHandle(dynSym.bsmKind, dynSym.bsm);
-                    bootstrapMethods.put(dynSym, handle);
+                    MethodHandle handle = new MethodHandle(dynSym.bsmKind, dynSym.bsm, types);
+                    DynamicMethod dynMeth = new DynamicMethod(dynSym, types);
+                    bootstrapMethods.put(dynMeth, handle);
                     //init cp entries
                     pool.put(names.BootstrapMethods);
                     pool.put(handle);
@@ -531,7 +537,7 @@
                 NameAndType nt = (NameAndType)value;
                 poolbuf.appendByte(CONSTANT_NameandType);
                 poolbuf.appendChar(pool.put(nt.name));
-                poolbuf.appendChar(pool.put(typeSig(nt.type)));
+                poolbuf.appendChar(pool.put(typeSig(nt.uniqueType.type)));
             } else if (value instanceof Integer) {
                 poolbuf.appendByte(CONSTANT_Integer);
                 poolbuf.appendInt(((Integer)value).intValue());
@@ -549,17 +555,18 @@
             } else if (value instanceof String) {
                 poolbuf.appendByte(CONSTANT_String);
                 poolbuf.appendChar(pool.put(names.fromString((String)value)));
-            } else if (value instanceof MethodType) {
-                MethodType mtype = (MethodType)value;
-                poolbuf.appendByte(CONSTANT_MethodType);
-                poolbuf.appendChar(pool.put(typeSig(mtype)));
-            } else if (value instanceof Type) {
-                Type type = (Type)value;
-                if (type.hasTag(CLASS)) enterInner((ClassSymbol)type.tsym);
-                poolbuf.appendByte(CONSTANT_Class);
-                poolbuf.appendChar(pool.put(xClassName(type)));
-            } else if (value instanceof Pool.MethodHandle) {
-                Pool.MethodHandle ref = (Pool.MethodHandle)value;
+            } else if (value instanceof UniqueType) {
+                Type type = ((UniqueType)value).type;
+                if (type instanceof MethodType) {
+                    poolbuf.appendByte(CONSTANT_MethodType);
+                    poolbuf.appendChar(pool.put(typeSig((MethodType)type)));
+                } else {
+                    if (type.hasTag(CLASS)) enterInner((ClassSymbol)type.tsym);
+                    poolbuf.appendByte(CONSTANT_Class);
+                    poolbuf.appendChar(pool.put(xClassName(type)));
+                }
+            } else if (value instanceof MethodHandle) {
+                MethodHandle ref = (MethodHandle)value;
                 poolbuf.appendByte(CONSTANT_MethodHandle);
                 poolbuf.appendByte(ref.refKind);
                 poolbuf.appendChar(pool.put(ref.refSym));
@@ -589,7 +596,7 @@
         return new NameAndType(fieldName(sym),
                                retrofit
                                ? sym.erasure(types)
-                               : sym.externalType(types));
+                               : sym.externalType(types), types);
         // if we retrofit, then the NameAndType has been read in as is
         // and no change is necessary. If we compile normally, the
         // NameAndType is generated from a symbol reference, and the
@@ -714,7 +721,7 @@
             endAttr(alenIdx);
             acount++;
         }
-        acount += writeJavaAnnotations(sym.getAnnotationMirrors());
+        acount += writeJavaAnnotations(sym.getRawAttributes());
         return acount;
     }
 
@@ -725,7 +732,7 @@
         boolean hasVisible = false;
         boolean hasInvisible = false;
         if (m.params != null) for (VarSymbol s : m.params) {
-            for (Attribute.Compound a : s.getAnnotationMirrors()) {
+            for (Attribute.Compound a : s.getRawAttributes()) {
                 switch (types.getRetention(a)) {
                 case SOURCE: break;
                 case CLASS: hasInvisible = true; break;
@@ -741,7 +748,7 @@
             databuf.appendByte(m.params.length());
             for (VarSymbol s : m.params) {
                 ListBuffer<Attribute.Compound> buf = new ListBuffer<Attribute.Compound>();
-                for (Attribute.Compound a : s.getAnnotationMirrors())
+                for (Attribute.Compound a : s.getRawAttributes())
                     if (types.getRetention(a) == RetentionPolicy.RUNTIME)
                         buf.append(a);
                 databuf.appendChar(buf.length());
@@ -756,7 +763,7 @@
             databuf.appendByte(m.params.length());
             for (VarSymbol s : m.params) {
                 ListBuffer<Attribute.Compound> buf = new ListBuffer<Attribute.Compound>();
-                for (Attribute.Compound a : s.getAnnotationMirrors())
+                for (Attribute.Compound a : s.getRawAttributes())
                     if (types.getRetention(a) == RetentionPolicy.CLASS)
                         buf.append(a);
                 databuf.appendChar(buf.length());
@@ -951,14 +958,16 @@
     void writeBootstrapMethods() {
         int alenIdx = writeAttr(names.BootstrapMethods);
         databuf.appendChar(bootstrapMethods.size());
-        for (Map.Entry<MethodSymbol, Pool.MethodHandle> entry : bootstrapMethods.entrySet()) {
-            DynamicMethodSymbol dsym = (DynamicMethodSymbol)entry.getKey();
+        for (Map.Entry<DynamicMethod, MethodHandle> entry : bootstrapMethods.entrySet()) {
+            DynamicMethod dmeth = entry.getKey();
+            DynamicMethodSymbol dsym = (DynamicMethodSymbol)dmeth.baseSymbol();
             //write BSM handle
             databuf.appendChar(pool.get(entry.getValue()));
             //write static args length
             databuf.appendChar(dsym.staticArgs.length);
             //write static args array
-            for (Object o : dsym.staticArgs) {
+            Object[] uniqueArgs = dmeth.uniqueStaticArgs;
+            for (Object o : uniqueArgs) {
                 databuf.appendChar(pool.get(o));
             }
         }
@@ -1534,7 +1543,7 @@
         pool = c.pool;
         innerClasses = null;
         innerClassesQueue = null;
-        bootstrapMethods = new LinkedHashMap<MethodSymbol, Pool.MethodHandle>();
+        bootstrapMethods = new LinkedHashMap<DynamicMethod, MethodHandle>();
 
         Type supertype = types.supertype(c.type);
         List<Type> interfaces = types.interfaces(c.type);
@@ -1627,7 +1636,7 @@
         }
 
         acount += writeFlagAttrs(c.flags());
-        acount += writeJavaAnnotations(c.getAnnotationMirrors());
+        acount += writeJavaAnnotations(c.getRawAttributes());
         acount += writeEnclosingMethodAttribute(c);
         acount += writeExtraClassAttributes(c);
 
--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/Code.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/Code.java	Wed Jul 05 18:34:52 2017 +0200
@@ -27,6 +27,7 @@
 
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Symbol.*;
+import com.sun.tools.javac.code.Types.UniqueType;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
 
@@ -901,6 +902,7 @@
         if (o instanceof ClassSymbol) return syms.classType;
         if (o instanceof Type.ArrayType) return syms.classType;
         if (o instanceof Type.MethodType) return syms.methodTypeType;
+        if (o instanceof UniqueType) return typeForPool(((UniqueType)o).type);
         if (o instanceof Pool.MethodHandle) return syms.methodHandleType;
         throw new AssertionError(o);
     }
@@ -1030,7 +1032,7 @@
             Object o = pool.pool[od];
             Type t = (o instanceof Symbol)
                 ? ((Symbol)o).erasure(types)
-                : types.erasure(((Type)o));
+                : types.erasure((((UniqueType)o).type));
             state.push(t);
             break; }
         case ldc2w:
--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java	Wed Jul 05 18:34:52 2017 +0200
@@ -94,6 +94,10 @@
         return instance;
     }
 
+    /* Constant pool, reset by genClass.
+     */
+    private Pool pool;
+
     protected Gen(Context context) {
         context.put(genKey, this);
 
@@ -126,6 +130,7 @@
         genCrt = options.isSet(XJCOV);
         debugCode = options.isSet("debugcode");
         allowInvokedynamic = target.hasInvokedynamic() || options.isSet("invokedynamic");
+        pool = new Pool(types);
 
         generateIproxies =
             target.requiresIproxy() ||
@@ -174,10 +179,6 @@
      */
     private boolean useJsrLocally;
 
-    /* Constant pool, reset by genClass.
-     */
-    private Pool pool = new Pool();
-
     /** Code buffer, set by genMethod.
      */
     private Code code;
@@ -705,7 +706,7 @@
         }
         int startpc = code.curPc();
         genStat(tree, env);
-        if (tree.hasTag(BLOCK)) crtFlags |= CRT_BLOCK;
+        if (tree.hasTag(Tag.BLOCK)) crtFlags |= CRT_BLOCK;
         code.crt.put(tree, crtFlags, startpc, code.curPc());
     }
 
--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/Pool.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/Pool.java	Wed Jul 05 18:34:52 2017 +0200
@@ -28,6 +28,9 @@
 import com.sun.tools.javac.code.Kinds;
 import com.sun.tools.javac.code.Symbol;
 import com.sun.tools.javac.code.Symbol.*;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.code.Types;
+import com.sun.tools.javac.code.Types.UniqueType;
 
 import com.sun.tools.javac.util.ArrayUtils;
 import com.sun.tools.javac.util.Assert;
@@ -60,11 +63,14 @@
      */
     Map<Object,Integer> indices;
 
+    Types types;
+
     /** Construct a pool with given number of elements and element array.
      */
-    public Pool(int pp, Object[] pool) {
+    public Pool(int pp, Object[] pool, Types types) {
         this.pp = pp;
         this.pool = pool;
+        this.types = types;
         this.indices = new HashMap<Object,Integer>(pool.length);
         for (int i = 1; i < pp; i++) {
             if (pool[i] != null) indices.put(pool[i], i);
@@ -73,8 +79,8 @@
 
     /** Construct an empty pool.
      */
-    public Pool() {
-        this(1, new Object[64]);
+    public Pool(Types types) {
+        this(1, new Object[64], types);
     }
 
     /** Return the number of entries in the constant pool.
@@ -114,11 +120,13 @@
 
     Object makePoolValue(Object o) {
         if (o instanceof DynamicMethodSymbol) {
-            return new DynamicMethod((DynamicMethodSymbol)o);
+            return new DynamicMethod((DynamicMethodSymbol)o, types);
         } else if (o instanceof MethodSymbol) {
-            return new Method((MethodSymbol)o);
+            return new Method((MethodSymbol)o, types);
         } else if (o instanceof VarSymbol) {
-            return new Variable((VarSymbol)o);
+            return new Variable((VarSymbol)o, types);
+        } else if (o instanceof Type) {
+            return new UniqueType((Type)o, types);
         } else {
             return o;
         }
@@ -134,9 +142,11 @@
 
     static class Method extends DelegatedSymbol {
         MethodSymbol m;
-        Method(MethodSymbol m) {
+        UniqueType uniqueType;
+        Method(MethodSymbol m, Types types) {
             super(m);
             this.m = m;
+            this.uniqueType = new UniqueType(m.type, types);
         }
         public boolean equals(Object other) {
             if (!(other instanceof Method)) return false;
@@ -144,20 +154,22 @@
             return
                 o.name == m.name &&
                 o.owner == m.owner &&
-                o.type.equals(m.type);
+                ((Method)other).uniqueType.equals(uniqueType);
         }
         public int hashCode() {
             return
                 m.name.hashCode() * 33 +
                 m.owner.hashCode() * 9 +
-                m.type.hashCode();
+                uniqueType.hashCode();
         }
     }
 
     static class DynamicMethod extends Method {
+        public Object[] uniqueStaticArgs;
 
-        DynamicMethod(DynamicMethodSymbol m) {
-            super(m);
+        DynamicMethod(DynamicMethodSymbol m, Types types) {
+            super(m, types);
+            uniqueStaticArgs = getUniqueTypeArray(m.staticArgs, types);
         }
 
         @Override
@@ -168,7 +180,8 @@
             DynamicMethodSymbol dm2 = (DynamicMethodSymbol)((DynamicMethod)other).m;
             return dm1.bsm == dm2.bsm &&
                         dm1.bsmKind == dm2.bsmKind &&
-                        Arrays.equals(dm1.staticArgs, dm2.staticArgs);
+                        Arrays.equals(uniqueStaticArgs,
+                            ((DynamicMethod)other).uniqueStaticArgs);
         }
 
         @Override
@@ -178,17 +191,31 @@
             hash += dm.bsmKind * 7 +
                     dm.bsm.hashCode() * 11;
             for (int i = 0; i < dm.staticArgs.length; i++) {
-                hash += (dm.staticArgs[i].hashCode() * 23);
+                hash += (uniqueStaticArgs[i].hashCode() * 23);
             }
             return hash;
         }
+
+        private Object[] getUniqueTypeArray(Object[] objects, Types types) {
+            Object[] result = new Object[objects.length];
+            for (int i = 0; i < objects.length; i++) {
+                if (objects[i] instanceof Type) {
+                    result[i] = new UniqueType((Type)objects[i], types);
+                } else {
+                    result[i] = objects[i];
+                }
+            }
+            return result;
+        }
     }
 
     static class Variable extends DelegatedSymbol {
         VarSymbol v;
-        Variable(VarSymbol v) {
+        UniqueType uniqueType;
+        Variable(VarSymbol v, Types types) {
             super(v);
             this.v = v;
+            this.uniqueType = new UniqueType(v.type, types);
         }
         public boolean equals(Object other) {
             if (!(other instanceof Variable)) return false;
@@ -196,13 +223,13 @@
             return
                 o.name == v.name &&
                 o.owner == v.owner &&
-                o.type.equals(v.type);
+                ((Variable)other).uniqueType.equals(uniqueType);
         }
         public int hashCode() {
             return
                 v.name.hashCode() * 33 +
                 v.owner.hashCode() * 9 +
-                v.type.hashCode();
+                uniqueType.hashCode();
         }
     }
 
@@ -214,9 +241,12 @@
         /** Reference symbol */
         Symbol refSym;
 
-        public MethodHandle(int refKind, Symbol refSym) {
+        UniqueType uniqueType;
+
+        public MethodHandle(int refKind, Symbol refSym, Types types) {
             this.refKind = refKind;
             this.refSym = refSym;
+            this.uniqueType = new UniqueType(this.refSym.type, types);
             checkConsistent();
         }
         public boolean equals(Object other) {
@@ -227,14 +257,14 @@
             return
                 o.name == refSym.name &&
                 o.owner == refSym.owner &&
-                o.type.equals(refSym.type);
+                ((MethodHandle)other).uniqueType.equals(uniqueType);
         }
         public int hashCode() {
             return
                 refKind * 65 +
                 refSym.name.hashCode() * 33 +
                 refSym.owner.hashCode() * 9 +
-                refSym.type.hashCode();
+                uniqueType.hashCode();
         }
 
         /**
--- a/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Wed Jul 05 18:34:52 2017 +0200
@@ -928,6 +928,16 @@
         }
     }
 
+    /**
+     * Set needRootClasses to true, in JavaCompiler subclass constructor
+     * that want to collect public apis of classes supplied on the command line.
+     */
+    protected boolean needRootClasses = false;
+
+    /**
+     * The list of classes explicitly supplied on the command line for compilation.
+     * Not always populated.
+     */
     private List<JCClassDecl> rootClasses;
 
     /**
@@ -984,9 +994,10 @@
             }
         }
 
-        //If generating source, remember the classes declared in
-        //the original compilation units listed on the command line.
-        if (sourceOutput || stubOutput) {
+        // If generating source, or if tracking public apis,
+        // then remember the classes declared in
+        // the original compilation units listed on the command line.
+        if (needRootClasses || sourceOutput || stubOutput) {
             ListBuffer<JCClassDecl> cdefs = lb();
             for (JCCompilationUnit unit : roots) {
                 for (List<JCTree> defs = unit.defs;
@@ -1247,6 +1258,12 @@
                 attr.postAttr(env.tree);
             }
             compileStates.put(env, CompileState.ATTR);
+            if (rootClasses != null && rootClasses.contains(env.enclClass)) {
+                // This was a class that was explicitly supplied for compilation.
+                // If we want to capture the public api of this class,
+                // then now is a good time to do it.
+                reportPublicApi(env.enclClass.sym);
+            }
         }
         finally {
             log.useSource(prev);
@@ -1255,6 +1272,14 @@
         return env;
     }
 
+    /** Report the public api of a class that was supplied explicitly for compilation,
+     *  for example on the command line to javac.
+     * @param sym The symbol of the class.
+     */
+    public void reportPublicApi(ClassSymbol sym) {
+       // Override to collect the reported public api.
+    }
+
     /**
      * Perform dataflow checks on attributed parse trees.
      * These include checks for definite assignment and unreachable statements.
@@ -1675,7 +1700,7 @@
 
     /** Print numbers of errors and warnings.
      */
-    protected void printCount(String kind, int count) {
+    public void printCount(String kind, int count) {
         if (count != 0) {
             String key;
             if (count == 1)
--- a/langtools/src/share/classes/com/sun/tools/javac/main/Main.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/main/Main.java	Wed Jul 05 18:34:52 2017 +0200
@@ -44,6 +44,8 @@
 
 import com.sun.source.util.JavacTask;
 import com.sun.source.util.Plugin;
+import com.sun.tools.doclint.DocLint;
+import com.sun.tools.javac.api.BasicJavacTask;
 import com.sun.tools.javac.code.Source;
 import com.sun.tools.javac.file.CacheFSInfo;
 import com.sun.tools.javac.file.JavacFileManager;
@@ -428,6 +430,7 @@
             if (batchMode)
                 CacheFSInfo.preRegister(context);
 
+            // FIXME: this code will not be invoked if using JavacTask.parse/analyze/generate
             // invoke any available plugins
             String plugins = options.get(PLUGIN);
             if (plugins != null) {
@@ -448,7 +451,7 @@
                             try {
                                 if (task == null)
                                     task = JavacTask.instance(pEnv);
-                                plugin.call(task, p.tail.toArray(new String[p.tail.size()]));
+                                plugin.init(task, p.tail.toArray(new String[p.tail.size()]));
                             } catch (Throwable ex) {
                                 if (apiMode)
                                     throw new RuntimeException(ex);
@@ -464,10 +467,31 @@
                 }
             }
 
-            fileManager = context.get(JavaFileManager.class);
+            comp = JavaCompiler.instance(context);
 
-            comp = JavaCompiler.instance(context);
-            if (comp == null) return Result.SYSERR;
+            // FIXME: this code will not be invoked if using JavacTask.parse/analyze/generate
+            String xdoclint = options.get(XDOCLINT);
+            String xdoclintCustom = options.get(XDOCLINT_CUSTOM);
+            if (xdoclint != null || xdoclintCustom != null) {
+                Set<String> doclintOpts = new LinkedHashSet<String>();
+                if (xdoclint != null)
+                    doclintOpts.add(DocLint.XMSGS_OPTION);
+                if (xdoclintCustom != null) {
+                    for (String s: xdoclintCustom.split("\\s+")) {
+                        if (s.isEmpty())
+                            continue;
+                        doclintOpts.add(s.replace(XDOCLINT_CUSTOM.text, DocLint.XMSGS_CUSTOM_PREFIX));
+                    }
+                }
+                if (!(doclintOpts.size() == 1
+                        && doclintOpts.iterator().next().equals(DocLint.XMSGS_CUSTOM_PREFIX + "none"))) {
+                    JavacTask t = BasicJavacTask.instance(context);
+                    new DocLint().init(t, doclintOpts.toArray(new String[doclintOpts.size()]));
+                    comp.keepComments = true;
+                }
+            }
+
+            fileManager = context.get(JavaFileManager.class);
 
             if (!files.isEmpty()) {
                 // add filenames to fileObjects
--- a/langtools/src/share/classes/com/sun/tools/javac/main/Option.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/main/Option.java	Wed Jul 05 18:34:52 2017 +0200
@@ -25,28 +25,30 @@
 
 package com.sun.tools.javac.main;
 
+import java.io.File;
+import java.io.FileWriter;
+import java.io.PrintWriter;
 import java.util.Collections;
-import com.sun.tools.javac.util.Log.PrefixKind;
-import com.sun.tools.javac.util.Log.WriterKind;
-import com.sun.tools.javac.util.Log;
+import java.util.EnumSet;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+import javax.lang.model.SourceVersion;
+
+import com.sun.tools.doclint.DocLint;
 import com.sun.tools.javac.code.Lint;
 import com.sun.tools.javac.code.Source;
 import com.sun.tools.javac.code.Type;
 import com.sun.tools.javac.jvm.Target;
+import com.sun.tools.javac.processing.JavacProcessingEnvironment;
+import com.sun.tools.javac.util.Log;
+import com.sun.tools.javac.util.Log.PrefixKind;
+import com.sun.tools.javac.util.Log.WriterKind;
 import com.sun.tools.javac.util.Options;
-import com.sun.tools.javac.processing.JavacProcessingEnvironment;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.PrintWriter;
-import java.util.EnumSet;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Set;
-import javax.lang.model.SourceVersion;
-
 import static com.sun.tools.javac.main.Option.ChoiceKind.*;
+import static com.sun.tools.javac.main.Option.OptionGroup.*;
 import static com.sun.tools.javac.main.Option.OptionKind.*;
-import static com.sun.tools.javac.main.Option.OptionGroup.*;
 
 /**
  * Options for javac. The specific Option to handle a command-line option
@@ -79,6 +81,24 @@
     XLINT_CUSTOM("-Xlint:", "opt.Xlint.suboptlist",
             EXTENDED,   BASIC, ANYOF, getXLintChoices()),
 
+    XDOCLINT("-Xdoclint", "opt.Xdoclint", EXTENDED, BASIC),
+
+    XDOCLINT_CUSTOM("-Xdoclint:", "opt.Xdoclint.subopts", "opt.Xdoclint.custom", EXTENDED, BASIC) {
+        @Override
+        public boolean matches(String option) {
+            return DocLint.isValidOption(
+                    option.replace(XDOCLINT_CUSTOM.text, DocLint.XMSGS_CUSTOM_PREFIX));
+        }
+
+        @Override
+        public boolean process(OptionHelper helper, String option) {
+            String prev = helper.get(XDOCLINT_CUSTOM);
+            String next = (prev == null) ? option : (prev + " " + option);
+            helper.put(XDOCLINT_CUSTOM.text, next);
+            return false;
+        }
+    },
+
     // -nowarn is retained for command-line backward compatibility
     NOWARN("-nowarn", "opt.nowarn", STANDARD, BASIC) {
         @Override
--- a/langtools/src/share/classes/com/sun/tools/javac/model/JavacTypes.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/model/JavacTypes.java	Wed Jul 05 18:34:52 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 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,11 +25,16 @@
 
 package com.sun.tools.javac.model;
 
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Set;
-import java.util.EnumSet;
+
 import javax.lang.model.element.*;
 import javax.lang.model.type.*;
+
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.util.*;
@@ -301,4 +306,31 @@
             throw new IllegalArgumentException(o.toString());
         return clazz.cast(o);
     }
+
+    public Set<MethodSymbol> getOverriddenMethods(Element elem) {
+        if (elem.getKind() != ElementKind.METHOD
+                || elem.getModifiers().contains(Modifier.STATIC)
+                || elem.getModifiers().contains(Modifier.PRIVATE))
+            return Collections.emptySet();
+
+        if (!(elem instanceof MethodSymbol))
+            throw new IllegalArgumentException();
+
+        MethodSymbol m = (MethodSymbol) elem;
+        ClassSymbol origin = (ClassSymbol) m.owner;
+
+        Set<MethodSymbol> results = new LinkedHashSet<MethodSymbol>();
+        for (Type t : types.closure(origin.type)) {
+            if (t != origin.type) {
+                ClassSymbol c = (ClassSymbol) t.tsym;
+                for (Scope.Entry e = c.members().lookup(m.name); e.scope != null; e = e.next()) {
+                    if (e.sym.kind == Kinds.MTH && m.overrides(e.sym, origin, types, true)) {
+                        results.add((MethodSymbol) e.sym);
+                    }
+                }
+            }
+        }
+
+        return results;
+    }
 }
--- a/langtools/src/share/classes/com/sun/tools/javac/parser/DocCommentParser.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/parser/DocCommentParser.java	Wed Jul 05 18:34:52 2017 +0200
@@ -25,15 +25,12 @@
 
 package com.sun.tools.javac.parser;
 
-import com.sun.tools.javac.util.Filter;
 import java.text.BreakIterator;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.LinkedList;
 import java.util.Locale;
 import java.util.Map;
-import java.util.Queue;
 import java.util.Set;
 
 import com.sun.source.doctree.AttributeTree.ValueKind;
@@ -52,7 +49,6 @@
 import com.sun.tools.javac.tree.DocTreeMaker;
 import com.sun.tools.javac.tree.JCTree;
 import com.sun.tools.javac.util.DiagnosticSource;
-import com.sun.tools.javac.util.JCDiagnostic;
 import com.sun.tools.javac.util.List;
 import com.sun.tools.javac.util.ListBuffer;
 import com.sun.tools.javac.util.Log;
@@ -736,7 +732,9 @@
             nextChar();
             return m.at(p).Entity(names.fromChars(buf, namep, bp - namep - 1));
         } else {
-            String code = checkSemi ? "dc.missing.semicolon" : "dc.bad.entity";
+            String code = checkSemi
+                    ? "dc.missing.semicolon"
+                    : "dc.bad.entity";
             return erroneous(code, p);
         }
     }
@@ -888,8 +886,10 @@
     }
 
     protected void addPendingText(ListBuffer<DCTree> list, int textEnd) {
-        if (textStart != -1 && textStart <= textEnd) {
-            list.add(m.at(textStart).Text(newString(textStart, textEnd + 1)));
+        if (textStart != -1) {
+            if (textStart <= textEnd) {
+                list.add(m.at(textStart).Text(newString(textStart, textEnd + 1)));
+            }
             textStart = -1;
         }
     }
@@ -1196,6 +1196,16 @@
                                 return m.at(pos).See(html);
                             break;
 
+                        case '@':
+                            if (newline)
+                                throw new ParseException("dc.no.content");
+                            break;
+
+                        case EOI:
+                            if (bp == buf.length - 1)
+                                throw new ParseException("dc.no.content");
+                            break;
+
                         default:
                             if (isJavaIdentifierStart(ch) || ch == '#') {
                                 DCReference ref = reference(true);
--- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Wed Jul 05 18:34:52 2017 +0200
@@ -2364,6 +2364,9 @@
 compiler.err.dc.missing.semicolon=\
     semicolon missing
 
+compiler.err.dc.no.content=\
+    no content
+
 compiler.err.dc.no.tag.name=\
     no tag name after '@'
 
--- a/langtools/src/share/classes/com/sun/tools/javac/resources/javac.properties	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/resources/javac.properties	Wed Jul 05 18:34:52 2017 +0200
@@ -138,6 +138,14 @@
     Enable recommended warnings
 javac.opt.Xlint.suboptlist=\
     Enable or disable specific warnings
+javac.opt.Xdoclint=\
+    Enable recommended checks for problems in javadoc comments
+javac.opt.Xdoclint.subopts = \
+    (all|[-]<group>)[/<access>]
+javac.opt.Xdoclint.custom=\n\
+\        Enable or disable specific checks for problems in javadoc comments,\n\
+\        where <group> is one of accessibility, html, reference, or syntax,\n\
+\        and <access> is one of public, protected, package, or private.
 javac.opt.Xstdout=\
     Redirect standard output
 javac.opt.X=\
--- a/langtools/src/share/classes/com/sun/tools/javac/sym/CreateSymbols.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/sym/CreateSymbols.java	Wed Jul 05 18:34:52 2017 +0200
@@ -33,6 +33,7 @@
 import com.sun.tools.javac.code.Attribute;
 import com.sun.tools.javac.code.Symtab;
 import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.code.Types;
 import com.sun.tools.javac.jvm.ClassReader;
 import com.sun.tools.javac.jvm.ClassWriter;
 import com.sun.tools.javac.jvm.Pool;
@@ -173,7 +174,8 @@
                                    List.<Pair<Symbol.MethodSymbol,Attribute>>nil());
 
         Type.moreInfo = true;
-        Pool pool = new Pool();
+        Types types = Types.instance(task.getContext());
+        Pool pool = new Pool(types);
         for (JavaFileObject file : fm.list(jarLocation, "", EnumSet.of(CLASS), true)) {
             String className = fm.inferBinaryName(jarLocation, file);
             int index = className.lastIndexOf('.');
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/DCTree.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/DCTree.java	Wed Jul 05 18:34:52 2017 +0200
@@ -36,6 +36,8 @@
 import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition;
 import com.sun.tools.javac.util.List;
 import com.sun.tools.javac.util.Name;
+import java.io.IOException;
+import java.io.StringWriter;
 import javax.tools.JavaFileObject;
 
 /**
@@ -65,6 +67,21 @@
         return new SimpleDiagnosticPosition(dc.comment.getSourcePos(pos));
     }
 
+    /** Convert a tree to a pretty-printed string. */
+    @Override
+    public String toString() {
+        StringWriter s = new StringWriter();
+        try {
+            new DocPretty(s).print(this);
+        }
+        catch (IOException e) {
+            // should never happen, because StringWriter is defined
+            // never to throw any IOExceptions
+            throw new AssertionError(e);
+        }
+        return s.toString();
+    }
+
     public static class DCDocComment extends DCTree implements DocCommentTree {
         final Comment comment; // required for the implicit source pos table
 
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/DocPretty.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/DocPretty.java	Wed Jul 05 18:34:52 2017 +0200
@@ -81,7 +81,7 @@
     /**
      * Print list.
      */
-    protected void print(List<? extends DocTree> list) throws IOException {
+    public void print(List<? extends DocTree> list) throws IOException {
         for (DocTree t: list) {
             print(t);
         }
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,6 +26,7 @@
 package com.sun.tools.javac.tree;
 
 
+
 import com.sun.source.tree.Tree;
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.comp.AttrContext;
@@ -330,6 +331,13 @@
         return (docComments == null) ? null : docComments.getCommentText(tree);
     }
 
+    public static DCTree.DCDocComment getCommentTree(Env<?> env, JCTree tree) {
+        DocCommentTable docComments = (tree.hasTag(JCTree.Tag.TOPLEVEL))
+                ? ((JCCompilationUnit) tree).docComments
+                : env.toplevel.docComments;
+        return (docComments == null) ? null : docComments.getCommentTree(tree);
+    }
+
     /** The position of the first statement in a block, or the position of
      *  the block itself if it is empty.
      */
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Wed Jul 05 18:34:52 2017 +0200
@@ -684,7 +684,7 @@
     public JCVariableDecl VarDef(VarSymbol v, JCExpression init) {
         return (JCVariableDecl)
             new JCVariableDecl(
-                Modifiers(v.flags(), Annotations(v.getAnnotationMirrors())),
+                Modifiers(v.flags(), Annotations(v.getRawAttributes())),
                 v.name,
                 Type(v.type),
                 init,
@@ -800,7 +800,7 @@
     public JCMethodDecl MethodDef(MethodSymbol m, Type mtype, JCBlock body) {
         return (JCMethodDecl)
             new JCMethodDecl(
-                Modifiers(m.flags(), Annotations(m.getAnnotationMirrors())),
+                Modifiers(m.flags(), Annotations(m.getRawAttributes())),
                 m.name,
                 Type(mtype.getReturnType()),
                 TypeParams(mtype.getTypeArguments()),
--- a/langtools/src/share/classes/com/sun/tools/javadoc/ClassDocImpl.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javadoc/ClassDocImpl.java	Wed Jul 05 18:34:52 2017 +0200
@@ -276,6 +276,10 @@
         return false;
     }
 
+    public boolean isFunctionalInterface() {
+        return env.types.isFunctionalInterface(tsym);
+    }
+
     /**
      * Return the package that this class is contained in.
      */
--- a/langtools/src/share/classes/com/sun/tools/javadoc/MethodDocImpl.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javadoc/MethodDocImpl.java	Wed Jul 05 18:34:52 2017 +0200
@@ -76,6 +76,13 @@
     }
 
     /**
+     * Return true if this method is default
+     */
+    public boolean isDefault() {
+        return (sym.flags() & Flags.DEFAULT) != 0;
+    }
+
+    /**
      * Return true if this method is abstract
      */
     public boolean isAbstract() {
--- a/langtools/src/share/classes/com/sun/tools/javadoc/PackageDocImpl.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javadoc/PackageDocImpl.java	Wed Jul 05 18:34:52 2017 +0200
@@ -288,9 +288,9 @@
      * Return an empty array if there are none.
      */
     public AnnotationDesc[] annotations() {
-        AnnotationDesc res[] = new AnnotationDesc[sym.getAnnotationMirrors().length()];
+        AnnotationDesc res[] = new AnnotationDesc[sym.getRawAttributes().length()];
         int i = 0;
-        for (Attribute.Compound a : sym.getAnnotationMirrors()) {
+        for (Attribute.Compound a : sym.getRawAttributes()) {
             res[i++] = new AnnotationDescImpl(env, a);
         }
         return res;
--- a/langtools/src/share/classes/com/sun/tools/javadoc/ParameterImpl.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javadoc/ParameterImpl.java	Wed Jul 05 18:34:52 2017 +0200
@@ -99,9 +99,9 @@
      * Return an empty array if there are none.
      */
     public AnnotationDesc[] annotations() {
-        AnnotationDesc res[] = new AnnotationDesc[sym.getAnnotationMirrors().length()];
+        AnnotationDesc res[] = new AnnotationDesc[sym.getRawAttributes().length()];
         int i = 0;
-        for (Attribute.Compound a : sym.getAnnotationMirrors()) {
+        for (Attribute.Compound a : sym.getRawAttributes()) {
             res[i++] = new AnnotationDescImpl(env, a);
         }
         return res;
--- a/langtools/src/share/classes/com/sun/tools/javadoc/ProgramElementDocImpl.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javadoc/ProgramElementDocImpl.java	Wed Jul 05 18:34:52 2017 +0200
@@ -164,9 +164,9 @@
      * Return an empty array if there are none.
      */
     public AnnotationDesc[] annotations() {
-        AnnotationDesc res[] = new AnnotationDesc[sym.getAnnotationMirrors().length()];
+        AnnotationDesc res[] = new AnnotationDesc[sym.getRawAttributes().length()];
         int i = 0;
-        for (Attribute.Compound a : sym.getAnnotationMirrors()) {
+        for (Attribute.Compound a : sym.getRawAttributes()) {
             res[i++] = new AnnotationDescImpl(env, a);
         }
         return res;
--- a/langtools/src/share/classes/javax/lang/model/element/ExecutableElement.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/src/share/classes/javax/lang/model/element/ExecutableElement.java	Wed Jul 05 18:34:52 2017 +0200
@@ -78,6 +78,16 @@
     boolean isVarArgs();
 
     /**
+     * Returns {@code true} if this method is a default method and
+     * returns {@code false} otherwise.
+     *
+     * @return {@code true} if this method is a default method and
+     * {@code false} otherwise
+     * @since 1.8
+     */
+    boolean isDefault();
+
+    /**
      * Returns the exceptions and other throwables listed in this
      * method or constructor's {@code throws} clause in declaration
      * order.
--- a/langtools/test/com/sun/javadoc/testHtmlTableTags/TestHtmlTableTags.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/com/sun/javadoc/testHtmlTableTags/TestHtmlTableTags.java	Wed Jul 05 18:34:52 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -207,7 +207,7 @@
             "Instance Methods</a></span><span class=\"tabEnd\">&nbsp;</span></span>" +
             "<span id=\"t4\" class=\"tableTab\"><span><a href=\"javascript:show(8);\">" +
             "Concrete Methods</a></span><span class=\"tabEnd\">&nbsp;</span></span>" +
-            "<span id=\"t5\" class=\"tableTab\"><span><a href=\"javascript:show(16);\">" +
+            "<span id=\"t6\" class=\"tableTab\"><span><a href=\"javascript:show(32);\">" +
             "Deprecated Methods</a></span><span class=\"tabEnd\">&nbsp;</span></span>" +
             "</caption>"
         },
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/com/sun/javadoc/testLambdaFeature/TestLambdaFeature.java	Wed Jul 05 18:34:52 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      8004893
+ * @summary  Make sure that the lambda feature changes work fine in
+ *           javadoc.
+ * @author   bpatel
+ * @library  ../lib/
+ * @build    JavadocTester TestLambdaFeature
+ * @run main TestLambdaFeature
+ */
+
+public class TestLambdaFeature extends JavadocTester {
+
+    //Test information.
+    private static final String BUG_ID = "8004893";
+
+    //Javadoc arguments.
+    private static final String[] ARGS = new String[] {
+        "-d", BUG_ID, "-sourcepath", SRC_DIR, "pkg"
+    };
+
+    //Input for string search tests.
+    private static final String[][] TEST = {
+        {BUG_ID + FS + "pkg" + FS + "A.html",
+            "<td class=\"colFirst\"><code>default void</code></td>"},
+        {BUG_ID + FS + "pkg" + FS + "A.html",
+            "<pre>default&nbsp;void&nbsp;defaultMethod()</pre>"},
+        {BUG_ID + FS + "pkg" + FS + "A.html",
+            "<caption><span id=\"t0\" class=\"activeTableTab\"><span>" +
+            "All Methods</span><span class=\"tabEnd\">&nbsp;</span></span>" +
+            "<span id=\"t2\" class=\"tableTab\"><span>" +
+            "<a href=\"javascript:show(2);\">Instance Methods</a></span>" +
+            "<span class=\"tabEnd\">&nbsp;</span></span><span id=\"t3\" " +
+            "class=\"tableTab\"><span><a href=\"javascript:show(4);\">" +
+            "Abstract Methods</a></span><span class=\"tabEnd\">&nbsp;</span>" +
+            "</span><span id=\"t5\" class=\"tableTab\"><span>" +
+            "<a href=\"javascript:show(16);\">Default Methods</a></span>" +
+            "<span class=\"tabEnd\">&nbsp;</span></span></caption>"},
+        {BUG_ID + FS + "pkg" + FS + "A.html",
+            "<dl>" + NL + "<dt>Functional Interface:</dt>" + NL +
+            "<dd>This is a functional interface and can therefore be used as " +
+            "the assignment target for a lambda expression or method " +
+            "reference. </dd>" + NL + "</dl>"}
+    };
+    private static final String[][] NEGATED_TEST = {
+        {BUG_ID + FS + "pkg" + FS + "A.html",
+            "<td class=\"colFirst\"><code>default default void</code></td>"},
+        {BUG_ID + FS + "pkg" + FS + "A.html",
+            "<pre>default&nbsp;default&nbsp;void&nbsp;defaultMethod()</pre>"},
+        {BUG_ID + FS + "pkg" + FS + "B.html",
+            "<td class=\"colFirst\"><code>default void</code></td>"},
+        {BUG_ID + FS + "pkg" + FS + "B.html",
+            "<dl>" + NL + "<dt>Functional Interface:</dt>"}
+    };
+
+    /**
+     * The entry point of the test.
+     * @param args the array of command line arguments.
+     */
+    public static void main(String[] args) {
+        TestLambdaFeature tester = new TestLambdaFeature();
+        run(tester, ARGS, TEST, NEGATED_TEST);
+        tester.printSummary();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getBugId() {
+        return BUG_ID;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getBugName() {
+        return getClass().getName();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/com/sun/javadoc/testLambdaFeature/pkg/A.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+package pkg;
+
+public interface A {
+
+    public void method1();
+
+    public default void defaultMethod() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/com/sun/javadoc/testLambdaFeature/pkg/B.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+package pkg;
+
+public abstract class B {
+
+    public abstract void method1();
+
+    public void method2() { }
+}
--- a/langtools/test/com/sun/javadoc/testMethodTypes/TestMethodTypes.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/com/sun/javadoc/testMethodTypes/TestMethodTypes.java	Wed Jul 05 18:34:52 2017 +0200
@@ -55,7 +55,7 @@
             "Instance Methods</a></span><span class=\"tabEnd\">&nbsp;</span></span>" +
             "<span id=\"t4\" class=\"tableTab\"><span><a href=\"javascript:show(8);\">" +
             "Concrete Methods</a></span><span class=\"tabEnd\">&nbsp;</span></span>" +
-            "<span id=\"t5\" class=\"tableTab\"><span><a href=\"javascript:show(16);\">" +
+            "<span id=\"t6\" class=\"tableTab\"><span><a href=\"javascript:show(32);\">" +
             "Deprecated Methods</a></span><span class=\"tabEnd\">&nbsp;</span></span>" +
             "</caption>"
         },
@@ -87,7 +87,7 @@
             "Abstract Methods</a></span><span class=\"tabEnd\">&nbsp;</span></span>" +
             "<span id=\"t4\" class=\"tableTab\"><span><a href=\"javascript:show(8);\">" +
             "Concrete Methods</a></span><span class=\"tabEnd\">&nbsp;</span></span>" +
-            "<span id=\"t5\" class=\"tableTab\"><span><a href=\"javascript:show(16);\">" +
+            "<span id=\"t6\" class=\"tableTab\"><span><a href=\"javascript:show(32);\">" +
             "Deprecated Methods</a></span><span class=\"tabEnd\">&nbsp;</span></span>" +
             "</caption>"
         },
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/AccessTest.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,65 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @build DocLintTester
+ * @run main DocLintTester -ref AccessTest.protected.out AccessTest.java
+ * @run main DocLintTester -Xmsgs -ref AccessTest.private.out AccessTest.java
+ * @run main DocLintTester -Xmsgs:syntax -ref AccessTest.private.out AccessTest.java
+ * @run main DocLintTester -Xmsgs:syntax/public -ref AccessTest.public.out AccessTest.java
+ * @run main DocLintTester -Xmsgs:syntax/protected -ref AccessTest.protected.out AccessTest.java
+ * @run main DocLintTester -Xmsgs:syntax/package -ref AccessTest.package.out AccessTest.java
+ * @run main DocLintTester -Xmsgs:syntax/private -ref AccessTest.private.out AccessTest.java
+ * @run main DocLintTester -Xmsgs:all,-syntax AccessTest.java
+ * @run main DocLintTester -Xmsgs:all,-syntax/public AccessTest.java
+ * @run main DocLintTester -Xmsgs:all,-syntax/protected -ref AccessTest.public.out AccessTest.java
+ * @run main DocLintTester -Xmsgs:all,-syntax/package -ref AccessTest.protected.out AccessTest.java
+ * @run main DocLintTester -Xmsgs:all,-syntax/private -ref AccessTest.package.out AccessTest.java
+ */
+
+/** */
+public class AccessTest {
+    /**
+     * public a < b
+     */
+    public void public_syntax_error() { }
+
+    /**
+     * protected a < b
+     */
+    protected void protected_syntax_error() { }
+
+    /**
+     * package-private a < b
+     */
+    void syntax_error() { }
+
+    /**
+     * private a < b
+     */
+    private void private_syntax_error() { }
+}
+
+/** */
+class AccessTest2 {
+    /**
+     * public a < b
+     */
+    public void public_syntax_error() { }
+
+    /**
+     * protected a < b
+     */
+    protected void protected_syntax_error() { }
+
+    /**
+     * package-private a < b
+     */
+    void syntax_error() { }
+
+    /**
+     * private a < b
+     */
+    private void private_syntax_error() { }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/AccessTest.package.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,20 @@
+AccessTest.java:23: error: malformed HTML
+     * public a < b
+                ^
+AccessTest.java:28: error: malformed HTML
+     * protected a < b
+                   ^
+AccessTest.java:33: error: malformed HTML
+     * package-private a < b
+                         ^
+AccessTest.java:46: error: malformed HTML
+     * public a < b
+                ^
+AccessTest.java:51: error: malformed HTML
+     * protected a < b
+                   ^
+AccessTest.java:56: error: malformed HTML
+     * package-private a < b
+                         ^
+6 errors
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/AccessTest.private.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,27 @@
+AccessTest.java:23: error: malformed HTML
+     * public a < b
+                ^
+AccessTest.java:28: error: malformed HTML
+     * protected a < b
+                   ^
+AccessTest.java:33: error: malformed HTML
+     * package-private a < b
+                         ^
+AccessTest.java:38: error: malformed HTML
+     * private a < b
+                 ^
+AccessTest.java:46: error: malformed HTML
+     * public a < b
+                ^
+AccessTest.java:51: error: malformed HTML
+     * protected a < b
+                   ^
+AccessTest.java:56: error: malformed HTML
+     * package-private a < b
+                         ^
+AccessTest.java:61: error: malformed HTML
+     * private a < b
+                 ^
+8 errors
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/AccessTest.protected.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,8 @@
+AccessTest.java:23: error: malformed HTML
+     * public a < b
+                ^
+AccessTest.java:28: error: malformed HTML
+     * protected a < b
+                   ^
+2 errors
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/AccessTest.public.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,5 @@
+AccessTest.java:23: error: malformed HTML
+     * public a < b
+                ^
+1 error
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/AccessibilityTest.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,44 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @build DocLintTester
+ * @run main DocLintTester -Xmsgs:-accessibility AccessibilityTest.java
+ * @run main DocLintTester -ref AccessibilityTest.out AccessibilityTest.java
+ */
+
+/** */
+public class AccessibilityTest {
+
+    /**
+     * <h2> ... </h2>
+     */
+    public void missing_h1() { }
+
+    /**
+     * <h1> ... </h1>
+     * <h3> ... </h3>
+     */
+    public void missing_h2() { }
+
+    /**
+     * <img src="x.jpg">
+     */
+    public void missing_alt() { }
+
+    /**
+     * <table summary="ok"><tr><th>head<tr><td>data</table>
+     */
+    public void table_with_summary() { }
+
+    /**
+     * <table><caption>ok</caption><tr><th>head<tr><td>data</table>
+     */
+    public void table_with_caption() { }
+
+    /**
+     * <table><tr><th>head<tr><td>data</table>
+     */
+    public void table_without_summary_and_caption() { }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/AccessibilityTest.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,13 @@
+AccessibilityTest.java:14: error: header used out of sequence: <H2>
+     * <h2> ... </h2>
+       ^
+AccessibilityTest.java:20: error: header used out of sequence: <H3>
+     * <h3> ... </h3>
+       ^
+AccessibilityTest.java:25: error: no "alt" attribute for image
+     * <img src="x.jpg">
+       ^
+AccessibilityTest.java:40: error: no summary or caption for table
+     * <table><tr><th>head<tr><td>data</table>
+                                      ^
+4 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/DocLintTester.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.sun.tools.doclint.DocLint;
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+public class DocLintTester {
+
+    public static void main(String... args) throws Exception {
+        new DocLintTester().run(args);
+    }
+
+    public void run(String... args) throws Exception {
+        String testSrc = System.getProperty("test.src");
+
+        File refFile = null;
+        List<String> opts = new ArrayList<String>();
+        List<File> files = new ArrayList<File>();
+        for (int i = 0; i < args.length; i++) {
+            String arg = args[i];
+            if (arg.equals("-ref")) {
+                refFile = new File(testSrc, args[++i]);
+            } else if (arg.startsWith("-Xmsgs")) {
+                opts.add(arg);
+            } else
+                files.add(new File(testSrc, arg));
+        }
+
+        check(opts, files, refFile);
+
+        if (errors > 0)
+            throw new Exception(errors + " errors occurred");
+    }
+
+    void check(List<String> opts, List<File> files, File refFile) throws Exception {
+        List<String> args = new ArrayList<String>();
+        args.addAll(opts);
+        for (File file: files)
+            args.add(file.getPath());
+
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        new DocLint().run(pw, args.toArray(new String[args.size()]));
+        pw.flush();
+        String out = normalizeNewlines(removeFileNames(sw.toString())).trim();
+        if (out != null)
+            System.err.println("Output:\n" + out);
+
+        if (refFile == null) {
+            if (!out.isEmpty())
+                error("unexpected output");
+        } else {
+            String expect = readFile(refFile);
+            if (!expect.equals(out)) {
+                error("expected output not found");
+                System.err.println("EXPECT>>" + expect + "<<");
+                System.err.println(" FOUND>>" + out    + "<<");
+            }
+        }
+    }
+
+    String readFile(File file) throws IOException {
+        StringBuilder sb = new StringBuilder();
+        Reader in = new BufferedReader(new FileReader(file));
+        try {
+            char[] buf = new char[1024];
+            int n;
+            while ((n = in.read(buf)) != -1)
+                sb.append(buf, 0, n);
+        } finally {
+            in.close();
+        }
+        return sb.toString().trim();
+    }
+
+    private static final Pattern dirFileLine = Pattern.compile(
+            "(?m)"                          // multi-line mode
+            + "^([^: ]+?)"                  // directory part of file name
+            + "([A-Za-z0-9.]+:[0-9]+:)");   // file name and line number
+
+    String removeFileNames(String s) {
+        Matcher m = dirFileLine.matcher(s);
+        StringBuffer sb = new StringBuffer();
+        while (m.find()) {
+            m.appendReplacement(sb, "$2");
+        }
+        m.appendTail(sb);
+        return sb.toString();
+    }
+
+    private static final String nl = System.getProperty("line.separator");
+    String normalizeNewlines(String s) {
+        return (nl.equals("\n") ? s : s.replace(nl, "\n"));
+    }
+
+
+    void error(String msg) {
+        System.err.println("Error: " + msg);
+        errors++;
+    }
+
+    int errors;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/EmptyAuthorTest.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,12 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @build DocLintTester
+ * @run main DocLintTester -Xmsgs:-syntax EmptyAuthorTest.java
+ * @run main DocLintTester -Xmsgs:syntax -ref EmptyAuthorTest.out EmptyAuthorTest.java
+ */
+
+/** @author */
+public class EmptyAuthorTest {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/EmptyAuthorTest.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,5 @@
+EmptyAuthorTest.java:10: warning: no description for @author
+/** @author */
+    ^
+1 warning
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/EmptyExceptionTest.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,14 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @build DocLintTester
+ * @run main DocLintTester -Xmsgs:-syntax EmptyExceptionTest.java
+ * @run main DocLintTester -Xmsgs:syntax -ref EmptyExceptionTest.out EmptyExceptionTest.java
+ */
+
+/** . */
+public class EmptyExceptionTest {
+    /** @exception NullPointerException */
+    int emptyException() throws NullPointerException { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/EmptyExceptionTest.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,4 @@
+EmptyExceptionTest.java:12: warning: no description for @exception
+    /** @exception NullPointerException */
+        ^
+1 warning
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/EmptyParamTest.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,14 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @build DocLintTester
+ * @run main DocLintTester -Xmsgs:-syntax EmptyParamTest.java
+ * @run main DocLintTester -Xmsgs:syntax -ref EmptyParamTest.out EmptyParamTest.java
+ */
+
+/** . */
+public class EmptyParamTest {
+    /** @param i */
+    int emptyParam(int i) { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/EmptyParamTest.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,5 @@
+EmptyParamTest.java:12: warning: no description for @param
+    /** @param i */
+        ^
+1 warning
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/EmptyReturnTest.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,14 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @build DocLintTester
+ * @run main DocLintTester -Xmsgs:-syntax EmptyReturnTest.java
+ * @run main DocLintTester -Xmsgs:syntax -ref EmptyReturnTest.out EmptyReturnTest.java
+ */
+
+/** . */
+public class EmptyReturnTest {
+    /** @return */
+    int emptyReturn() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/EmptyReturnTest.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,5 @@
+EmptyReturnTest.java:12: warning: no description for @return
+    /** @return */
+        ^
+1 warning
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/EmptySerialDataTest.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,17 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @build DocLintTester
+ * @run main DocLintTester -Xmsgs:-syntax EmptySerialDataTest.java
+ * @run main DocLintTester -Xmsgs:syntax -ref EmptySerialDataTest.out EmptySerialDataTest.java
+ */
+
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+
+/** . */
+public class EmptySerialDataTest implements Serializable {
+    /** @serialData */
+    private void writeObject(ObjectOutputStream s) { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/EmptySerialDataTest.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,5 @@
+EmptySerialDataTest.java:15: warning: no description for @serialData
+    /** @serialData */
+        ^
+1 warning
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/EmptySerialFieldTest.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,22 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @build DocLintTester
+ * @run main DocLintTester -Xmsgs:-syntax EmptySerialFieldTest.java
+ * @run main DocLintTester -Xmsgs:syntax -ref EmptySerialFieldTest.out EmptySerialFieldTest.java
+ */
+
+import java.io.ObjectStreamField;
+import java.io.Serializable;
+
+/** . */
+public class EmptySerialFieldTest implements Serializable {
+
+    /**
+     * @serialField empty    String
+     */
+    private static final ObjectStreamField[] serialPersistentFields = {
+        new ObjectStreamField("empty", String.class),
+    };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/EmptySerialFieldTest.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,5 @@
+EmptySerialFieldTest.java:17: warning: no description for @serialField
+     * @serialField empty    String
+       ^
+1 warning
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/EmptySinceTest.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,14 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @build DocLintTester
+ * @run main DocLintTester -Xmsgs:-syntax EmptySinceTest.java
+ * @run main DocLintTester -Xmsgs:syntax -ref EmptySinceTest.out EmptySinceTest.java
+ */
+
+/** . */
+public class EmptySinceTest {
+    /** @since */
+    int emptySince() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/EmptySinceTest.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,5 @@
+EmptySinceTest.java:12: warning: no description for @since
+    /** @since */
+        ^
+1 warning
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/EmptyVersionTest.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,14 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @build DocLintTester
+ * @run main DocLintTester -Xmsgs:-syntax EmptyVersionTest.java
+ * @run main DocLintTester -Xmsgs:syntax -ref EmptyVersionTest.out EmptyVersionTest.java
+ */
+
+/** . */
+public class EmptyVersionTest {
+    /** @version */
+    int missingVersion() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/EmptyVersionTest.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,4 @@
+EmptyVersionTest.java:12: warning: no description for @version
+    /** @version */
+        ^
+1 warning
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/HtmlAttrsTest.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,27 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @build DocLintTester
+ * @run main DocLintTester -Xmsgs:-html HtmlAttrsTest.java
+ * @run main DocLintTester -ref HtmlAttrsTest.out HtmlAttrsTest.java
+ */
+
+/** */
+public class HtmlAttrsTest {
+    /**
+     * <p xyz>
+     */
+    public void unknown() { }
+
+    /**
+     * <img name="x" alt="alt">
+     */
+    public void obsolete() { }
+
+    /**
+     * <font size="3"> text </font>
+     */
+    public void obsolete_use_css() { }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/HtmlAttrsTest.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,12 @@
+HtmlAttrsTest.java:13: error: unknown attribute: xyz
+     * <p xyz>
+          ^
+HtmlAttrsTest.java:18: warning: attribute obsolete: name
+     * <img name="x" alt="alt">
+            ^
+HtmlAttrsTest.java:23: warning: attribute obsolete, use CSS instead: size
+     * <font size="3"> text </font>
+             ^
+1 error
+2 warnings
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/HtmlTagsTest.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,58 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @build DocLintTester
+ * @run main DocLintTester -Xmsgs:-html HtmlTagsTest.java
+ * @run main DocLintTester -ref HtmlTagsTest.out HtmlTagsTest.java
+ */
+
+/** */
+public class HtmlTagsTest {
+    /**
+     * <xyz> ... </xyz>
+     */
+    public void unknownTag1() { }
+
+    /**
+     * <div> <xyz> </div>
+     */
+    public void unknownTag2() { }
+
+    /**
+     * <br/>
+     */
+    public void selfClosingTag() { }
+
+    /**
+     * <html>
+     */
+    public void not_allowed() { }
+
+    /**
+     * <span> <p> </span>
+     */
+    public void not_allowed_inline() { }
+
+    /**
+     * {@link java.lang.String <p> }
+     * {@link java.lang.String <p> }
+     */
+    public void not_allowed_inline_2() { }
+
+    /**
+     * <img src="any.jpg" alt="alt"> </img>
+     */
+    public void end_not_allowed() { }
+
+    /**
+     * <i> <b> </i>
+     */
+    public void start_not_matched() { }
+
+    /**
+     * <i> </b> </i>
+     */
+    public void end_unexpected() { }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/HtmlTagsTest.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,38 @@
+HtmlTagsTest.java:13: error: unknown tag: xyz
+     * <xyz> ... </xyz>
+       ^
+HtmlTagsTest.java:13: error: unknown tag: xyz
+     * <xyz> ... </xyz>
+                 ^
+HtmlTagsTest.java:18: error: unknown tag: xyz
+     * <div> <xyz> </div>
+             ^
+HtmlTagsTest.java:23: error: self-closing element not allowed
+     * <br/>
+       ^
+HtmlTagsTest.java:28: error: element not allowed in documentation comments: <html>
+     * <html>
+       ^
+HtmlTagsTest.java:33: error: block element not allowed within inline element <span>: p
+     * <span> <p> </span>
+              ^
+HtmlTagsTest.java:38: error: block element not allowed within @link: p
+     * {@link java.lang.String <p> }
+                               ^
+HtmlTagsTest.java:39: error: block element not allowed within @link: p
+     * {@link java.lang.String <p> }
+                               ^
+HtmlTagsTest.java:44: error: invalid end tag: </img>
+     * <img src="any.jpg" alt="alt"> </img>
+                                     ^
+HtmlTagsTest.java:49: error: end tag missing: </b>
+     * <i> <b> </i>
+           ^
+HtmlTagsTest.java:54: error: unexpected end tag: </b>
+     * <i> </b> </i>
+           ^
+HtmlTagsTest.java:54: warning: empty <i> tag
+     * <i> </b> </i>
+                ^
+11 errors
+1 warning
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/MissingCommentTest.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,14 @@
+/*
+ * @test /nodynamiccopyright/
+ * @build DocLintTester
+ * @run main DocLintTester -Xmsgs:-missing MissingCommentTest.java
+ * @run main DocLintTester -Xmsgs:missing -ref MissingCommentTest.out MissingCommentTest.java
+ */
+
+public class MissingCommentTest {
+    MissingCommentTest() { }
+
+    int missingComment;
+
+    void missingComment() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/MissingCommentTest.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,14 @@
+MissingCommentTest.java:8: warning: no comment
+public class MissingCommentTest {
+       ^
+MissingCommentTest.java:9: warning: no comment
+    MissingCommentTest() { }
+    ^
+MissingCommentTest.java:11: warning: no comment
+    int missingComment;
+        ^
+MissingCommentTest.java:13: warning: no comment
+    void missingComment() { }
+         ^
+4 warnings
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/MissingParamsTest.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,23 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @build DocLintTester
+ * @run main DocLintTester -Xmsgs:-missing MissingParamsTest.java
+ * @run main DocLintTester -Xmsgs:missing -ref MissingParamsTest.out MissingParamsTest.java
+ */
+
+/** . */
+public class MissingParamsTest {
+    /** */
+    MissingParamsTest(int param) { }
+
+    /** */
+    <T> MissingParamsTest() { }
+
+    /** */
+    void missingParam(int param) { }
+
+    /** */
+    <T> void missingTyparam() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/MissingParamsTest.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,14 @@
+MissingParamsTest.java:13: warning: no @param for param
+    MissingParamsTest(int param) { }
+    ^
+MissingParamsTest.java:16: warning: no @param for <T>
+    <T> MissingParamsTest() { }
+        ^
+MissingParamsTest.java:19: warning: no @param for param
+    void missingParam(int param) { }
+         ^
+MissingParamsTest.java:22: warning: no @param for <T>
+    <T> void missingTyparam() { }
+             ^
+4 warnings
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/MissingReturnTest.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,23 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @build DocLintTester
+ * @run main DocLintTester -Xmsgs:-missing MissingReturnTest.java
+ * @run main DocLintTester -Xmsgs:missing -ref MissingReturnTest.out MissingReturnTest.java
+ */
+
+/** . */
+public class MissingReturnTest {
+    /** no return allowed */
+    MissingReturnTest() { }
+
+    /** no return allowed */
+    void return_void() { }
+
+    /** no return required */
+    Void return_Void() { }
+
+    /** */
+    int missingReturn() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/MissingReturnTest.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,5 @@
+MissingReturnTest.java:22: warning: no @return
+    int missingReturn() { }
+        ^
+1 warning
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/MissingThrowsTest.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,14 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @build DocLintTester
+ * @run main DocLintTester -Xmsgs:-missing MissingThrowsTest.java
+ * @run main DocLintTester -Xmsgs:missing -ref MissingThrowsTest.out MissingThrowsTest.java
+ */
+
+/** */
+public class MissingThrowsTest {
+    /** */
+    void missingThrows() throws Exception { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/MissingThrowsTest.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,4 @@
+MissingThrowsTest.java:13: warning: no @throws for java.lang.Exception
+    void missingThrows() throws Exception { }
+         ^
+1 warning
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/OptionTest.java	Wed Jul 05 18:34:52 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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 8004832
+ * @summary Add new doclint package
+ */
+
+import com.sun.tools.doclint.DocLint;
+
+public class OptionTest {
+    public static void main(String... args) throws Exception {
+        new OptionTest().run();
+    }
+
+    String[] positiveTests = {
+        "-Xmsgs",
+        "-Xmsgs:all",
+        "-Xmsgs:none",
+        "-Xmsgs:accessibility",
+        "-Xmsgs:html",
+        "-Xmsgs:missing",
+        "-Xmsgs:reference",
+        "-Xmsgs:syntax",
+        "-Xmsgs:html/public",
+        "-Xmsgs:html/protected",
+        "-Xmsgs:html/package",
+        "-Xmsgs:html/private",
+        "-Xmsgs:-html/public",
+        "-Xmsgs:-html/protected",
+        "-Xmsgs:-html/package",
+        "-Xmsgs:-html/private",
+        "-Xmsgs:html,syntax",
+        "-Xmsgs:html,-syntax",
+        "-Xmsgs:-html,syntax",
+        "-Xmsgs:-html,-syntax",
+        "-Xmsgs:html/public,syntax",
+        "-Xmsgs:html,syntax/public",
+        "-Xmsgs:-html/public,syntax/public"
+    };
+
+    String[] negativeTests = {
+        "-typo",
+        "-Xmsgs:-all",
+        "-Xmsgs:-none",
+        "-Xmsgs:typo",
+        "-Xmsgs:html/typo",
+        "-Xmsgs:html/public,typo",
+        "-Xmsgs:html/public,syntax/typo",
+    };
+
+    void run() throws Exception {
+        test(positiveTests, true);
+        test(negativeTests, false);
+
+        if (errors > 0)
+            throw new Exception(errors + " errors occurred");
+    }
+
+    void test(String[] tests, boolean expect) {
+        for (String test: tests) {
+            System.err.println("test: " + test);
+            boolean found = DocLint.isValidOption(test);
+            if (found != expect)
+                error("Unexpected result: " + found + ",expected: " + expect);
+        }
+    }
+
+    void error(String msg) {
+        System.err.println("Error: " + msg);
+        errors++;
+    }
+
+    int errors;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/OverridesTest.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,93 @@
+/*
+ * 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 8004832
+ * @summary Add new doclint package
+ * @build DocLintTester
+ * @run main DocLintTester -Xmsgs:all OverridesTest.java
+ */
+
+/*
+ * This is a test that missing comments on methods may be inherited
+ * from overridden methods. As such, there should be no errors due
+ * to missing comments (or any other types of error) in this test.
+ */
+
+/** An interface. */
+interface I1 {
+    /**
+     * A method
+     * @param p a param
+     * @throws Exception an exception
+     * @return an int
+     */
+    int m(int p) throws Exception;
+}
+
+/** An extending interface. */
+interface I2 extends I1 { }
+
+/** An abstract class. */
+abstract class C1 {
+    /**
+     * A method
+     * @param p a param
+     * @throws Exception an exception
+     * @return an int
+     */
+    int m(int p) throws Exception;
+}
+
+/** An implementing class. */
+class C2 implements I1 {
+    int m(int  p) throws Exception { return p; }
+}
+
+/** An extending class. */
+class C3 extends C1 {
+    int m(int  p) throws Exception { return p; }
+}
+
+/** An extending and implementing class. */
+class C4 extends C1 implements I1 {
+    int m(int  p) throws Exception { return p; }
+}
+
+/** An implementing class using inheritdoc. */
+class C5 implements I1 {
+    /** {@inheritDoc} */
+    int m(int  p) throws Exception { return p; }
+}
+
+/** An implementing class with incomplete documentation. */
+class C6 implements I1 {
+    /** Overriding method */
+    int m(int  p) throws Exception { return p; }
+}
+
+/** A class implementing an inherited interface. */
+class C7 implements I2 {
+    int m(int  p) throws Exception { return p; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/ReferenceTest.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,52 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @build DocLintTester
+ * @run main DocLintTester -Xmsgs:-reference ReferenceTest.java
+ * @run main DocLintTester -ref ReferenceTest.out ReferenceTest.java
+ */
+
+/** */
+public class ReferenceTest {
+    /**
+     * @param x description
+     */
+    public int invalid_param;
+
+    /**
+     * @param x description
+     */
+    public class InvalidParam { }
+
+    /**
+     * @param x description
+     */
+    public void param_name_not_found(int a) { }
+
+    /**
+     * @param <X> description
+     */
+    public class typaram_name_not_found { }
+
+    /**
+     * @see Object#tooStrong()
+     */
+    public void ref_not_found() { }
+
+    /**
+     * @return x description
+     */
+    public int invalid_return;
+
+    /**
+     * @return x description
+     */
+    public void invalid_return();
+
+    /**
+     * @throws Exception description
+     */
+    public void exception_not_thrown() { }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/ReferenceTest.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,30 @@
+ReferenceTest.java:13: error: invalid use of @param
+     * @param x description
+       ^
+ReferenceTest.java:18: error: invalid use of @param
+     * @param x description
+       ^
+ReferenceTest.java:23: error: @param name not found
+     * @param x description
+              ^
+ReferenceTest.java:25: warning: no @param for a
+    public void param_name_not_found(int a) { }
+                ^
+ReferenceTest.java:28: error: @param name not found
+     * @param <X> description
+               ^
+ReferenceTest.java:33: error: reference not found
+     * @see Object#tooStrong()
+            ^
+ReferenceTest.java:38: error: invalid use of @return
+     * @return x description
+       ^
+ReferenceTest.java:43: error: invalid use of @return
+     * @return x description
+       ^
+ReferenceTest.java:48: error: exception not thrown: java.lang.Exception
+     * @throws Exception description
+               ^
+8 errors
+1 warning
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/RunTest.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,105 @@
+/*
+ * 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 8004832
+ * @summary Add new doclint package
+ * @bug 8000103
+ * @summary Create doclint utility
+ */
+
+import com.sun.tools.doclint.DocLint;
+import com.sun.tools.doclint.DocLint.BadArgs;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.annotation.Annotation;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/** javadoc error on toplevel:  a & b. */
+public class RunTest {
+    /** javadoc error on member: a < b */
+    public static void main(String... args) throws Exception {
+        new RunTest().run();
+    }
+
+
+    File testSrc = new File(System.getProperty("test.src"));
+    File thisFile = new File(testSrc, RunTest.class.getSimpleName() + ".java");
+
+    void run() throws Exception {
+        for (Method m: getClass().getDeclaredMethods()) {
+            Annotation a = m.getAnnotation(Test.class);
+            if (a != null) {
+                System.err.println("test: " + m.getName());
+                try {
+                    StringWriter sw = new StringWriter();
+                    PrintWriter pw = new PrintWriter(sw);;
+                    m.invoke(this, new Object[] { pw });
+                    String out = sw.toString();
+                    System.err.println(">>> " + out.replace("\n", "\n>>> "));
+                    if (!out.contains("a < b"))
+                        error("\"a < b\" not found");
+                    if (!out.contains("a & b"))
+                        error("\"a & b\" not found");
+                } catch (InvocationTargetException e) {
+                    Throwable cause = e.getCause();
+                    throw (cause instanceof Exception) ? ((Exception) cause) : e;
+                }
+                System.err.println();
+            }
+        }
+
+        if (errors > 0)
+            throw new Exception(errors + " errors occurred");
+    }
+
+
+    void error(String msg) {
+        System.err.println("Error: " + msg);
+        errors++;
+    }
+
+    int errors;
+
+    /** Marker annotation for test cases. */
+    @Retention(RetentionPolicy.RUNTIME)
+    @interface Test { }
+
+    @Test
+    void testMain(PrintWriter pw) throws BadArgs, IOException {
+        String[] args = { "-Xmsgs", thisFile.getPath() };
+        DocLint d = new DocLint();
+        d.run(pw, args);
+    }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/SyntaxTest.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,17 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @build DocLintTester
+ * @run main DocLintTester -Xmsgs:-syntax SyntaxTest.java
+ * @run main DocLintTester -ref SyntaxTest.out SyntaxTest.java
+ */
+
+/** */
+public class SyntaxTest {
+    /**
+     * a < b
+     */
+    public void syntax_error() { }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/SyntaxTest.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,5 @@
+SyntaxTest.java:13: error: malformed HTML
+     * a < b
+         ^
+1 error
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/SyntheticTest.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,50 @@
+/*
+ * 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 8004832
+ * @summary Add new doclint package
+ * @build DocLintTester
+ * @run main DocLintTester -Xmsgs:all SyntheticTest.java
+ */
+
+/**
+ * This is a test that messages are not generated for synthesized elements
+ * such as default constructors and enum methods.
+ */
+public class SyntheticTest {
+    // No explicit constructor implies a default constructor
+
+    /** enum E */
+    enum E {
+        /** enum member E1 */
+        E1,
+        /** enum member E2 */
+        E2,
+        /** enum member E3 */
+        E3
+    }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/ValidTest.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,112 @@
+/*
+ * 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 8004832
+ * @summary Add new doclint package
+ * @build DocLintTester
+ * @run main DocLintTester ValidTest.java
+ */
+
+class ValidTest {
+    /**
+     * &lt; &gt; &amp; &#40;
+     */
+    void entities() { }
+
+    /**
+     * <h1> ... </h1>
+     * <h2> ... </h2>
+     * <h3> ... </h3>
+     * <h4> ... </h4>
+     * <h5> ... </h5>
+     * <h6> ... </h6>
+     */
+    void all_headers() { }
+
+    /**
+     * <h1> ... </h1>
+     * <h2> ... </h2>
+     * <h3> ... </h3>
+     * <h1> ... </h1>
+     * <h2> ... </h2>
+     * <h3> ... </h3>
+     * <h2> ... </h2>
+     */
+    void header_series() { }
+
+    /**
+     * <div> <p>   </div>
+     */
+    void autoclose_tags() { }
+
+    /**
+     * @param x
+     */
+    void method_param(int x) { }
+
+    /**
+     * @param <T>
+     */
+    <T> T method_typaram(T t) { return t; }
+
+    /**
+     * @param <T>
+     */
+    class ClassTyparam<T> { }
+
+    /**
+     * @param <T>
+     */
+    interface InterfaceTyparam<T> { }
+
+    /**
+     * @return x
+     */
+    int return_int() { return 0; }
+
+    /**
+     * @exception Exception
+     */
+    void throws_Exception1() throws Exception { }
+
+    /**
+     * @throws Exception
+     */
+    void throws_Exception2() throws Exception { }
+
+    class X {
+        /**
+         * @param x
+         */
+        X(int x) { } // constructor parameter
+
+        /**
+         * @param <T>
+         */
+        <T> X(T t) { } // constructor type parameter
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/tidy/AnchorAlreadyDefined.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,17 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @library ..
+ * @build DocLintTester
+ * @run main DocLintTester -ref AnchorAlreadyDefined.out AnchorAlreadyDefined.java
+ */
+
+// tidy: Warning: <.*> anchor ".*" already defined
+
+/**
+ * <a name="here">valid</a>
+ * <a name="here">duplicate</a>
+ * <h1 id="here">duplicate</h1>
+ */
+public class AnchorAlreadyDefined { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/tidy/AnchorAlreadyDefined.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,7 @@
+AnchorAlreadyDefined.java:14: error: anchor already defined: here
+ * <a name="here">duplicate</a>
+      ^
+AnchorAlreadyDefined.java:15: error: anchor already defined: here
+ * <h1 id="here">duplicate</h1>
+       ^
+2 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/tidy/BadEnd.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,16 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @library ..
+ * @build DocLintTester
+ * @run main DocLintTester -ref BadEnd.out BadEnd.java
+ */
+
+// tidy: Warning: <.*> is probably intended as </.*>
+
+/**
+ * <a name="here"> text <a>
+ * <code> text <code>
+ */
+public class BadEnd { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/tidy/BadEnd.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,17 @@
+BadEnd.java:14: warning: nested tag not allowed: <code>
+ * <code> text <code>
+               ^
+BadEnd.java:14: error: element not closed: code
+ * <code> text <code>
+               ^
+BadEnd.java:14: error: element not closed: code
+ * <code> text <code>
+   ^
+BadEnd.java:13: error: element not closed: a
+ * <a name="here"> text <a>
+                        ^
+BadEnd.java:13: error: element not closed: a
+ * <a name="here"> text <a>
+   ^
+4 errors
+1 warning
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/tidy/InsertImplicit.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,16 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @library ..
+ * @build DocLintTester
+ * @run main DocLintTester -ref InsertImplicit.out InsertImplicit.java
+ */
+
+// tidy: Warning: inserting implicit <.*>
+
+/**
+ * </p>
+ * <i> <blockquote> abc </blockquote> </i>
+ */
+public class InsertImplicit { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/tidy/InsertImplicit.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,7 @@
+InsertImplicit.java:13: error: unexpected end tag: </p>
+ * </p>
+   ^
+InsertImplicit.java:14: error: block element not allowed within inline element <i>: blockquote
+ * <i> <blockquote> abc </blockquote> </i>
+       ^
+2 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/tidy/InvalidEntity.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,22 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @library ..
+ * @build DocLintTester
+ * @run main DocLintTester -ref InvalidEntity.out InvalidEntity.java
+ */
+
+// tidy: Warning: replacing invalid numeric character reference .*
+
+// See
+// http://www.w3.org/TR/html4/sgml/entities.html
+// http://stackoverflow.com/questions/631406/what-is-the-difference-between-em-dash-151-and-8212
+
+/**
+ * &#01;
+ * &#x01;
+ * &splodge;
+ *
+ */
+public class InvalidEntity { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/tidy/InvalidEntity.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,10 @@
+InvalidEntity.java:17: error: invalid entity &#01;
+ * &#01;
+   ^
+InvalidEntity.java:18: error: invalid entity &#x01;
+ * &#x01;
+   ^
+InvalidEntity.java:19: error: invalid entity &splodge;
+ * &splodge;
+   ^
+3 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/tidy/InvalidName.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,18 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @library ..
+ * @build DocLintTester
+ * @run main DocLintTester -ref InvalidName.out InvalidName.java
+ */
+
+// tidy: Warning: <a> cannot copy name attribute to id
+
+/**
+ * <a name="abc">valid</a>
+ * <a name="abc123">valid</a>
+ * <a name="a.1:2-3_4">valid</a>
+ * <a name="foo()">invalid</a>
+ */
+public class InvalidName { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/tidy/InvalidName.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,4 @@
+InvalidName.java:16: error: invalid name for anchor: "foo()"
+ * <a name="foo()">invalid</a>
+      ^
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/tidy/InvalidTag.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,15 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @library ..
+ * @build DocLintTester
+ * @run main DocLintTester -ref InvalidTag.out InvalidTag.java
+ */
+
+// tidy: Error: <.*> is not recognized!
+
+/**
+ * List<String> list = new ArrayList<>();
+ */
+public class InvalidTag { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/tidy/InvalidTag.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,10 @@
+InvalidTag.java:13: error: unknown tag: String
+ * List<String> list = new ArrayList<>();
+       ^
+InvalidTag.java:13: error: malformed HTML
+ * List<String> list = new ArrayList<>();
+                                    ^
+InvalidTag.java:13: error: bad use of '>'
+ * List<String> list = new ArrayList<>();
+                                     ^
+3 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/tidy/InvalidURI.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,21 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @library ..
+ * @build DocLintTester
+ * @run main DocLintTester -ref InvalidURI.out InvalidURI.java
+ */
+
+// tidy: Warning: <a> escaping malformed URI reference
+// tidy: Warning: <.*> attribute ".*" lacks value
+
+/**
+ * <a href="abc">valid</a>
+ * <a href="abc%20def">valid</a>
+ * <a href="abc def">invalid</a>
+ * <a href>no value</a>
+ * <a href= >no value</a>
+ * <a href="" >no value</a>
+ */
+public class InvalidURI { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/tidy/InvalidURI.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,13 @@
+InvalidURI.java:16: error: invalid uri: "abc def"
+ * <a href="abc def">invalid</a>
+      ^
+InvalidURI.java:17: error: attribute lacks value
+ * <a href>no value</a>
+      ^
+InvalidURI.java:18: error: attribute lacks value
+ * <a href= >no value</a>
+      ^
+InvalidURI.java:19: error: attribute lacks value
+ * <a href="" >no value</a>
+      ^
+4 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/tidy/MissingGT.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,16 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @library ..
+ * @build DocLintTester
+ * @run main DocLintTester -ref MissingGT.out MissingGT.java
+ */
+
+// tidy: Warning: <.*> missing '>' for end of tag
+
+/**
+ * <img src="image.gif"
+ * <i>  text </i>
+ */
+public class MissingGT { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/tidy/MissingGT.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,4 @@
+MissingGT.java:13: error: malformed HTML
+ * <img src="image.gif"
+   ^
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/tidy/MissingTag.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,17 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @library ..
+ * @build DocLintTester
+ * @run main DocLintTester -ref MissingTag.out MissingTag.java
+ */
+
+// tidy: Warning: missing <.*>
+// tidy: Warning: missing </.*> before </.*>
+
+/**
+ * </p>
+ * <h1> <b> text </h1>
+ */
+public class MissingTag { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/tidy/MissingTag.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,7 @@
+MissingTag.java:14: error: unexpected end tag: </p>
+ * </p>
+   ^
+MissingTag.java:15: error: end tag missing: </b>
+ * <h1> <b> text </h1>
+        ^
+2 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/tidy/NestedTag.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,16 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @library ..
+ * @build DocLintTester
+ * @run main DocLintTester -ref NestedTag.out NestedTag.java
+ */
+
+// tidy: Warning: nested emphasis <.*>
+
+/**
+ * <b><b> text </b></b>
+ * {@link java.lang.String <code>String</code>}
+ */
+public class NestedTag { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/tidy/NestedTag.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,7 @@
+NestedTag.java:13: warning: nested tag not allowed: <b>
+ * <b><b> text </b></b>
+      ^
+NestedTag.java:14: warning: nested tag not allowed: <code>
+ * {@link java.lang.String <code>String</code>}
+                           ^
+2 warnings
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/tidy/ParaInPre.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,20 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @library ..
+ * @build DocLintTester
+ * @run main DocLintTester -ref ParaInPre.out ParaInPre.java
+ */
+
+// tidy: Warning: replacing <p> by <br>
+// tidy: Warning: using <br> in place of <p>
+
+/**
+ * <pre>
+ *     text
+ *     <p>
+ *     more text
+ * </pre>
+ */
+public class ParaInPre { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/tidy/ParaInPre.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,4 @@
+ParaInPre.java:16: warning: unexpected use of <p> inside <pre> element
+ *     <p>
+       ^
+1 warning
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/tidy/README.txt	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,21 @@
+The utilities in this directory can be used to determine
+common issues in javadoc comments by running the standard
+"tidy" program on the output of javadoc, and analysing
+the messages that are reported.
+
+tidy.sh is a script that will run the "tidy" program on
+the files in a directory, writing the results to a new
+directroy.
+
+tidystats.Main is a Java program that can analyze the 
+files produced by the tidy.sh script to generate a 
+summary report about the warnings that were found.
+
+
+The tests is this directory are focussed on verifying
+that doclint detects issues in javadoc comments that will
+give rise to issues detected by "tidy" in the output
+generated by javadoc. 
+
+For more information on the "tidy" program, see the HTML Tidy
+Library Project page at http://tidy.sourceforge.net/.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/tidy/RepeatedAttr.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,15 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @library ..
+ * @build DocLintTester
+ * @run main DocLintTester -ref RepeatedAttr.out RepeatedAttr.java
+ */
+
+// tidy: Warning: <.*> dropping value ".*" for repeated attribute ".*"
+
+/**
+ * <img src="image.gif" alt alt="summary">
+ */
+public class RepeatedAttr { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/tidy/RepeatedAttr.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,4 @@
+RepeatedAttr.java:13: error: repeated attribute: alt
+ * <img src="image.gif" alt alt="summary">
+                            ^
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/tidy/TextNotAllowed.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,26 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @library ..
+ * @build DocLintTester
+ * @run main DocLintTester -ref TextNotAllowed.out TextNotAllowed.java
+ */
+
+// tidy: Warning: plain text isn't allowed in <.*> elements
+
+/**
+ * <table summary=description> abc </table>
+ * <table summary=description> <tbody> abc </tbody> </table>
+ * <table summary=description> <tr> abc </tr> </table>
+ *
+ * <dl> abc </dl>
+ * <ol> abc </ol>
+ * <ul> abc </ul>
+ *
+ * <ul>
+ *     <li> item
+ *     <li> item
+ * </ul>
+ */
+public class TextNotAllowed { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/tidy/TextNotAllowed.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,19 @@
+TextNotAllowed.java:13: error: text not allowed in <table> element
+ * <table summary=description> abc </table>
+                                   ^
+TextNotAllowed.java:14: error: text not allowed in <tbody> element
+ * <table summary=description> <tbody> abc </tbody> </table>
+                                           ^
+TextNotAllowed.java:15: error: text not allowed in <tr> element
+ * <table summary=description> <tr> abc </tr> </table>
+                                        ^
+TextNotAllowed.java:17: error: text not allowed in <dl> element
+ * <dl> abc </dl>
+            ^
+TextNotAllowed.java:18: error: text not allowed in <ol> element
+ * <ol> abc </ol>
+            ^
+TextNotAllowed.java:19: error: text not allowed in <ul> element
+ * <ul> abc </ul>
+            ^
+6 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/tidy/TrimmingEmptyTag.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,29 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @library ..
+ * @build DocLintTester
+ * @run main DocLintTester -ref TrimmingEmptyTag.out TrimmingEmptyTag.java
+ */
+
+// tidy: Warning: trimming empty <.*>
+
+/**
+ * <b></b>
+ * <table summary=description></table>
+ * <table><caption></caption></table>
+ * <code></code>
+ * <dl></dl>
+ * <dl><dt></dt><dd></dd></dl>
+ * <font></font>
+ * <i></i>
+ * <ol></ol>
+ * <p></p>
+ * <pre></pre>
+ * <span></span>
+ * <tt></tt>
+ * <ul></ul>
+ * <ul><li></li></ul>
+ */
+public class TrimmingEmptyTag { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/tidy/TrimmingEmptyTag.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,46 @@
+TrimmingEmptyTag.java:13: warning: empty <b> tag
+ * <b></b>
+      ^
+TrimmingEmptyTag.java:14: warning: empty <table> tag
+ * <table summary=description></table>
+                              ^
+TrimmingEmptyTag.java:15: warning: empty <caption> tag
+ * <table><caption></caption></table>
+                   ^
+TrimmingEmptyTag.java:16: warning: empty <code> tag
+ * <code></code>
+         ^
+TrimmingEmptyTag.java:17: warning: empty <dl> tag
+ * <dl></dl>
+       ^
+TrimmingEmptyTag.java:18: warning: empty <dt> tag
+ * <dl><dt></dt><dd></dd></dl>
+           ^
+TrimmingEmptyTag.java:18: warning: empty <dd> tag
+ * <dl><dt></dt><dd></dd></dl>
+                    ^
+TrimmingEmptyTag.java:19: warning: empty <font> tag
+ * <font></font>
+         ^
+TrimmingEmptyTag.java:20: warning: empty <i> tag
+ * <i></i>
+      ^
+TrimmingEmptyTag.java:21: warning: empty <ol> tag
+ * <ol></ol>
+       ^
+TrimmingEmptyTag.java:22: warning: empty <p> tag
+ * <p></p>
+      ^
+TrimmingEmptyTag.java:23: warning: empty <pre> tag
+ * <pre></pre>
+        ^
+TrimmingEmptyTag.java:24: warning: empty <span> tag
+ * <span></span>
+         ^
+TrimmingEmptyTag.java:25: warning: empty <tt> tag
+ * <tt></tt>
+       ^
+TrimmingEmptyTag.java:26: warning: empty <ul> tag
+ * <ul></ul>
+       ^
+15 warnings
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/tidy/UnescapedOrUnknownEntity.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,19 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8004832
+ * @summary Add new doclint package
+ * @library ..
+ * @build DocLintTester
+ * @run main DocLintTester -ref UnescapedOrUnknownEntity.out UnescapedOrUnknownEntity.java
+ */
+
+// tidy: Warning: unescaped & or unknown entity ".*"
+// tidy: Warning: unescaped & which should be written as &amp;
+// tidy: Warning: entity ".*" doesn't end in ';'
+
+/**
+ * L&F
+ * Drag&Drop
+ * if (a & b);
+ */
+public class UnescapedOrUnknownEntity { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/tidy/UnescapedOrUnknownEntity.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,11 @@
+UnescapedOrUnknownEntity.java:15: error: semicolon missing
+ * L&F
+    ^
+UnescapedOrUnknownEntity.java:16: error: semicolon missing
+ * Drag&Drop
+       ^
+UnescapedOrUnknownEntity.java:17: error: bad HTML entity
+ * if (a & b);
+         ^
+3 errors
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/tidy/util/Main.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,182 @@
+package tidystats;
+
+import java.io.IOException;
+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.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class Main {
+    public static void main(String... args) throws IOException {
+        new Main().run(args);
+    }
+
+    void run(String... args) throws IOException {
+        FileSystem fs = FileSystems.getDefault();
+        List<Path> paths = new ArrayList<>();
+
+        int i;
+        for (i = 0; i < args.length; i++) {
+            String arg = args[i];
+            if (arg.startsWith("-"))
+                throw new IllegalArgumentException(arg);
+            else
+                break;
+        }
+
+        for ( ; i < args.length; i++) {
+            Path p = fs.getPath(args[i]);
+            paths.add(p);
+        }
+
+        for (Path p: paths) {
+            scan(p);
+        }
+
+        print("%6d files read", files);
+        print("%6d files had no errors or warnings", ok);
+        print("%6d files reported \"Not all warnings/errors were shown.\"", overflow);
+        print("%6d errors found", errs);
+        print("%6d warnings found", warns);
+        print("%6d recommendations to use CSS", css);
+        print("");
+
+        Map<Integer, Set<String>> sortedCounts = new TreeMap<>(
+                new Comparator<Integer>() {
+                    @Override
+                    public int compare(Integer o1, Integer o2) {
+                        return o2.compareTo(o1);
+                    }
+                });
+
+        for (Map.Entry<Pattern, Integer> e: counts.entrySet()) {
+            Pattern p = e.getKey();
+            Integer n = e.getValue();
+            Set<String> set = sortedCounts.get(n);
+            if (set == null)
+                sortedCounts.put(n, (set = new TreeSet<>()));
+            set.add(p.toString());
+        }
+
+        for (Map.Entry<Integer, Set<String>> e: sortedCounts.entrySet()) {
+            for (String p: e.getValue()) {
+                if (p.startsWith(".*")) p = p.substring(2);
+                print("%6d: %s", e.getKey(), p);
+            }
+        }
+    }
+
+    void scan(Path p) throws IOException {
+        if (Files.isDirectory(p)) {
+            for (Path c: Files.newDirectoryStream(p)) {
+                scan(c);
+            }
+        } else if (isTidyFile(p)) {
+            scan(Files.readAllLines(p, Charset.defaultCharset()));
+        }
+    }
+
+    boolean isTidyFile(Path p) {
+        return Files.isRegularFile(p) && p.getFileName().toString().endsWith(".tidy");
+    }
+
+    void scan(List<String> lines) {
+        Matcher m;
+        files++;
+        for (String line: lines) {
+            if (okPattern.matcher(line).matches()) {
+                ok++;
+            } else if ((m = countPattern.matcher(line)).matches()) {
+                warns += Integer.valueOf(m.group(1));
+                errs += Integer.valueOf(m.group(2));
+                if (m.group(3) != null)
+                    overflow++;
+            } else if ((m = guardPattern.matcher(line)).matches()) {
+                boolean found = false;
+                for (Pattern p: patterns) {
+                    if ((m = p.matcher(line)).matches()) {
+                        found = true;
+                        count(p);
+                        break;
+                    }
+                }
+                if (!found)
+                    System.err.println("Unrecognized line: " + line);
+            } else if (cssPattern.matcher(line).matches()) {
+                css++;
+            }
+        }
+    }
+
+    Map<Pattern, Integer> counts = new HashMap<>();
+    void count(Pattern p) {
+        Integer i = counts.get(p);
+        counts.put(p, (i == null) ? 1 : i + 1);
+    }
+
+    void print(String format, Object... args) {
+        System.out.println(String.format(format, args));
+    }
+
+    Pattern okPattern = Pattern.compile("No warnings or errors were found.");
+    Pattern countPattern = Pattern.compile("([0-9]+) warnings, ([0-9]+) errors were found!.*?(Not all warnings/errors were shown.)?");
+    Pattern cssPattern = Pattern.compile("You are recommended to use CSS.*");
+    Pattern guardPattern = Pattern.compile("line [0-9]+ column [0-9]+ - (Error|Warning):.*");
+
+    Pattern[] patterns = {
+        Pattern.compile(".*Error: <.*> is not recognized!"),
+        Pattern.compile(".*Error: missing quote mark for attribute value"),
+        Pattern.compile(".*Warning: <.*> anchor \".*\" already defined"),
+        Pattern.compile(".*Warning: <.*> attribute \".*\" has invalid value \".*\""),
+        Pattern.compile(".*Warning: <.*> attribute \".*\" lacks value"),
+        Pattern.compile(".*Warning: <.*> attribute \".*\" lacks value"),
+        Pattern.compile(".*Warning: <.*> attribute with missing trailing quote mark"),
+        Pattern.compile(".*Warning: <.*> dropping value \".*\" for repeated attribute \".*\""),
+        Pattern.compile(".*Warning: <.*> inserting \".*\" attribute"),
+        Pattern.compile(".*Warning: <.*> is probably intended as </.*>"),
+        Pattern.compile(".*Warning: <.*> isn't allowed in <.*> elements"),
+        Pattern.compile(".*Warning: <.*> lacks \".*\" attribute"),
+        Pattern.compile(".*Warning: <.*> missing '>' for end of tag"),
+        Pattern.compile(".*Warning: <.*> proprietary attribute \".*\""),
+        Pattern.compile(".*Warning: <.*> unexpected or duplicate quote mark"),
+        Pattern.compile(".*Warning: <a> cannot copy name attribute to id"),
+        Pattern.compile(".*Warning: <a> escaping malformed URI reference"),
+        Pattern.compile(".*Warning: <blockquote> proprietary attribute \"pre\""),
+        Pattern.compile(".*Warning: discarding unexpected <.*>"),
+        Pattern.compile(".*Warning: discarding unexpected </.*>"),
+        Pattern.compile(".*Warning: entity \".*\" doesn't end in ';'"),
+        Pattern.compile(".*Warning: inserting implicit <.*>"),
+        Pattern.compile(".*Warning: inserting missing 'title' element"),
+        Pattern.compile(".*Warning: missing <!DOCTYPE> declaration"),
+        Pattern.compile(".*Warning: missing <.*>"),
+        Pattern.compile(".*Warning: missing </.*> before <.*>"),
+        Pattern.compile(".*Warning: nested emphasis <.*>"),
+        Pattern.compile(".*Warning: plain text isn't allowed in <.*> elements"),
+        Pattern.compile(".*Warning: replacing <p> by <br>"),
+        Pattern.compile(".*Warning: replacing invalid numeric character reference .*"),
+        Pattern.compile(".*Warning: replacing unexpected .* by </.*>"),
+        Pattern.compile(".*Warning: trimming empty <.*>"),
+        Pattern.compile(".*Warning: unescaped & or unknown entity \".*\""),
+        Pattern.compile(".*Warning: unescaped & which should be written as &amp;"),
+        Pattern.compile(".*Warning: using <br> in place of <p>")
+    };
+
+    int files;
+    int ok;
+    int warns;
+    int errs;
+    int css;
+    int overflow;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/doclint/tidy/util/tidy.sh	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,52 @@
+#!/bin/sh
+#
+# 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.
+#
+
+# Run the "tidy" program over the files in a directory.
+#
+# Usage:
+#   sh tidy.sh <dir>
+#
+# The "tidy" program will be run on each HTML file in <dir>,
+# and the output placed in the corresponding location in a new
+# directory <dir>.tidy.  The console output from running "tidy" will
+# be saved in a corresponding file with an additional .tidy extension.
+#
+# Non-HTML files will be copied without modification from <dir> to
+# <dir>.tidy, so that relative links within the directory tree are
+# unaffected.
+
+dir=$1
+odir=$dir.tidy
+
+( cd $dir ; find . -type f ) | \
+    while read file ; do
+        mkdir -p $odir/$(dirname $file)
+        case $file in
+            *.html )
+                cat $dir/$file | tidy 1>$odir/$file 2>$odir/$file.tidy
+                ;;
+            * ) cp $dir/$file $odir/$file
+                ;;
+        esac
+    done
--- a/langtools/test/tools/javac/7129225/TestImportStar.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/7129225/TestImportStar.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
 /* @test
  * @bug 7129225
  * @summary import xxx.* isn't handled correctly by annotation processing
- * @library ../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor
  * @compile/fail/ref=NegTest.ref -XDrawDiagnostics TestImportStar.java
  * @compile Anno.java AnnoProcessor.java
--- a/langtools/test/tools/javac/7153958/CPoolRefClassContainingInlinedCts.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/7153958/CPoolRefClassContainingInlinedCts.java	Wed Jul 05 18:34:52 2017 +0200
@@ -27,7 +27,7 @@
  * @test
  * @bug 7153958
  * @summary add constant pool reference to class containing inlined constants
- * @compile pkg/ClassToBeStaticallyImported.java
+ * @compile pkg/ClassToBeStaticallyImported.java CPoolRefClassContainingInlinedCts.java
  * @run main CPoolRefClassContainingInlinedCts
  */
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/8000518/DuplicateConstantPoolEntry.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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 8000518
+ * @summary Javac generates duplicate name_and_type constant pool entry for
+ * class BinaryOpValueExp.java
+ * @run main DuplicateConstantPoolEntry
+ */
+
+import com.sun.source.util.JavacTask;
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.ConstantPoolException;
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.List;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.ToolProvider;
+
+/*
+ * This bug was reproduced having two classes B and C referenced from a class A
+ * class C should be compiled and generated in advance. Later class A and B should
+ * be compiled like this: javac A.java B.java
+ */
+
+public class DuplicateConstantPoolEntry {
+
+    public static void main(String args[]) throws Exception {
+        new DuplicateConstantPoolEntry().run();
+    }
+
+    void run() throws Exception {
+        generateFilesNeeded();
+        checkReference();
+    }
+
+    void generateFilesNeeded() throws Exception {
+
+        StringJavaFileObject[] CSource = new StringJavaFileObject[] {
+            new StringJavaFileObject("C.java",
+                "class C {C(String s) {}}"),
+        };
+
+        List<StringJavaFileObject> AandBSource = Arrays.asList(
+                new StringJavaFileObject("A.java",
+                    "class A {void test() {new B(null);new C(null);}}"),
+                new StringJavaFileObject("B.java",
+                    "class B {B(String s) {}}")
+        );
+
+        final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
+        JavacTask compileC = (JavacTask)tool.getTask(null, null, null, null, null,
+                Arrays.asList(CSource));
+        if (!compileC.call()) {
+            throw new AssertionError("Compilation error while compiling C.java sources");
+        }
+        JavacTask compileAB = (JavacTask)tool.getTask(null, null, null,
+                Arrays.asList("-cp", "."), null, AandBSource);
+        if (!compileAB.call()) {
+            throw new AssertionError("Compilation error while compiling A and B sources");
+        }
+    }
+
+    void checkReference() throws IOException, ConstantPoolException {
+        File file = new File("A.class");
+        ClassFile classFile = ClassFile.read(file);
+        for (int i = 1;
+                i < classFile.constant_pool.size() - 1;
+                i += classFile.constant_pool.get(i).size()) {
+            for (int j = i + classFile.constant_pool.get(i).size();
+                    j < classFile.constant_pool.size();
+                    j += classFile.constant_pool.get(j).size()) {
+                if (classFile.constant_pool.get(i).toString().
+                        equals(classFile.constant_pool.get(j).toString())) {
+                    throw new AssertionError(
+                            "Duplicate entries in the constant pool at positions " +
+                            i + " and " + j);
+                }
+            }
+        }
+    }
+
+    private static class StringJavaFileObject extends SimpleJavaFileObject {
+        StringJavaFileObject(String name, String text) {
+            super(URI.create(name), JavaFileObject.Kind.SOURCE);
+            this.text = text;
+        }
+        @Override
+        public CharSequence getCharContent(boolean b) {
+            return text;
+        }
+        private String text;
+    }
+}
--- a/langtools/test/tools/javac/cast/intersection/model/Model01.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/cast/intersection/model/Model01.java	Wed Jul 05 18:34:52 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 8002099
  * @summary Add support for intersection types in cast expression
- * @library ../../../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor ModelChecker
  * @compile -XDallowIntersectionTypes -processor ModelChecker Model01.java
  */
--- a/langtools/test/tools/javac/classreader/T7031108.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/classreader/T7031108.java	Wed Jul 05 18:34:52 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 7031108
  * @summary NPE in javac.jvm.ClassReader.findMethod in PackageElement.enclosedElements from AP in incr build
- * @library ../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor T7031108
  * @run main T7031108
  */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/NoContent.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+// key: compiler.err.dc.no.content
+// key: compiler.note.note
+// key: compiler.note.proc.messager
+// run: backdoor
+// options: -processor DocCommentProcessor -proc:only
+
+/** @see */
+class NoContent {
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/doclint/DocLintTest.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,225 @@
+/*
+ * 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 8004833
+ * @summary Integrate doclint support into javac
+ */
+
+import java.io.File;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import javax.tools.Diagnostic;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.StandardLocation;
+import javax.tools.ToolProvider;
+import static javax.tools.Diagnostic.Kind.*;
+
+import com.sun.source.util.JavacTask;
+import com.sun.tools.javac.main.Main;
+import java.util.EnumSet;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class DocLintTest {
+    public static void main(String... args) throws Exception {
+        new DocLintTest().run();
+    }
+
+    JavaCompiler javac;
+    StandardJavaFileManager fm;
+    JavaFileObject file;
+
+    final String code =
+        /* 01 */    "/** Class comment. */\n" +
+        /* 02 */    "public class Test {\n" +
+        /* 03 */    "    /** Method comment. */\n" +
+        /* 04 */    "    public void method() { }\n" +
+        /* 05 */    "\n" +
+        /* 06 */    "    /** Syntax < error. */\n" +
+        /* 07 */    "    private void syntaxError() { }\n" +
+        /* 08 */    "\n" +
+        /* 09 */    "    /** @see DoesNotExist */\n" +
+        /* 10 */    "    protected void referenceError() { }\n" +
+        /* 08 */    "\n" +
+        /* 09 */    "    /** @return */\n" +
+        /* 10 */    "    public int emptyReturn() { return 0; }\n" +
+        /* 11 */    "}\n";
+
+    final String rawDiags = "-XDrawDiagnostics";
+    private enum Message {
+        // doclint messages
+        DL_ERR6(ERROR, "Test.java:6:16: compiler.err.proc.messager: malformed HTML"),
+        DL_ERR9(ERROR, "Test.java:9:14: compiler.err.proc.messager: reference not found"),
+        DL_WRN12(WARNING, "Test.java:12:9: compiler.warn.proc.messager: no description for @return"),
+
+        OPT_BADARG(ERROR, "invalid flag: -Xdoclint:badarg");
+
+        final Diagnostic.Kind kind;
+        final String text;
+
+        static Message get(String text) {
+            for (Message m: values()) {
+                if (m.text.equals(text))
+                    return m;
+            }
+            return null;
+        }
+
+        Message(Diagnostic.Kind kind, String text) {
+            this.kind = kind;
+            this.text = text;
+        }
+
+        @Override
+        public String toString() {
+            return "[" + kind + ",\"" + text + "\"]";
+        }
+    }
+    void run() throws Exception {
+        javac = ToolProvider.getSystemJavaCompiler();
+        fm = javac.getStandardFileManager(null, null, null);
+        fm.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(new File(".")));
+        file = new SimpleJavaFileObject(URI.create("Test.java"), JavaFileObject.Kind.SOURCE) {
+            @Override
+            public CharSequence getCharContent(boolean ignoreEncoding) {
+                return code;
+            }
+        };
+
+        test(Collections.<String>emptyList(),
+                Main.Result.OK,
+                EnumSet.noneOf(Message.class));
+
+        test(Arrays.asList("-Xdoclint:none"),
+                Main.Result.OK,
+                EnumSet.noneOf(Message.class));
+
+        test(Arrays.asList(rawDiags, "-Xdoclint"),
+                Main.Result.ERROR,
+                EnumSet.of(Message.DL_ERR6, Message.DL_ERR9, Message.DL_WRN12));
+
+        test(Arrays.asList(rawDiags, "-Xdoclint:all/public"),
+                Main.Result.OK,
+                EnumSet.of(Message.DL_WRN12));
+
+        test(Arrays.asList(rawDiags, "-Xdoclint:syntax"),
+                Main.Result.ERROR,
+                EnumSet.of(Message.DL_ERR6, Message.DL_WRN12));
+
+        test(Arrays.asList(rawDiags, "-Xdoclint:reference"),
+                Main.Result.ERROR,
+                EnumSet.of(Message.DL_ERR9));
+
+        test(Arrays.asList(rawDiags, "-Xdoclint:badarg"),
+                Main.Result.CMDERR,
+                EnumSet.of(Message.OPT_BADARG));
+
+        if (errors > 0)
+            throw new Exception(errors + " errors occurred");
+    }
+
+    void test(List<String> opts, Main.Result expectResult, Set<Message> expectMessages) {
+        System.err.println("test: " + opts);
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        List<JavaFileObject> files = Arrays.asList(file);
+        try {
+            JavacTask t = (JavacTask) javac.getTask(pw, fm, null, opts, null, files);
+            boolean ok = t.call();
+            pw.close();
+            String out = sw.toString().replaceAll("[\r\n]+", "\n");
+            if (!out.isEmpty())
+                System.err.println(out);
+            if (ok && expectResult != Main.Result.OK) {
+                error("Compilation succeeded unexpectedly");
+            } else if (!ok && expectResult != Main.Result.ERROR) {
+                error("Compilation failed unexpectedly");
+            } else
+                check(out, expectMessages);
+        } catch (IllegalArgumentException e) {
+            System.err.println(e);
+            String expectOut = expectMessages.iterator().next().text;
+            if (expectResult != Main.Result.CMDERR)
+                error("unexpected exception caught");
+            else if (!e.getMessage().equals(expectOut)) {
+                error("unexpected exception message: "
+                        + e.getMessage()
+                        + " expected: " + expectOut);
+            }
+        }
+
+//        if (errors > 0)
+//            throw new Error("stop");
+    }
+
+    private void check(String out, Set<Message> expect) {
+        Pattern stats = Pattern.compile("^([1-9]+) (error|warning)(s?)");
+        Set<Message> found = EnumSet.noneOf(Message.class);
+        int e = 0, w = 0;
+        if (!out.isEmpty()) {
+            for (String line: out.split("[\r\n]+")) {
+                Matcher s = stats.matcher(line);
+                if (s.matches()) {
+                    int i = Integer.valueOf(s.group(1));
+                    if (s.group(2).equals("error"))
+                        e++;
+                    else
+                        w++;
+                    continue;
+                }
+
+                Message m = Message.get(line);
+                if (m == null)
+                    error("Unexpected line: " + line);
+                else
+                    found.add(m);
+            }
+        }
+        for (Message m: expect) {
+            if (!found.contains(m))
+                error("expected message not found: " + m.text);
+        }
+        for (Message m: found) {
+            if (!expect.contains(m))
+                error("unexpected message found: " + m.text);
+        }
+    }
+
+    void error(String msg) {
+        System.err.println("Error: " + msg);
+        errors++;
+    }
+
+    int errors;
+}
--- a/langtools/test/tools/javac/enum/6350057/T6350057.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/enum/6350057/T6350057.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 6350057 7025809
  * @summary Test that parameters on implicit enum methods have the right kind
  * @author  Joseph D. Darcy
- * @library ../../lib
+ * @library /tools/javac/lib
  * @build   JavacTestingAbstractProcessor T6350057
  * @compile -processor T6350057 -proc:only TestEnum.java
  */
--- a/langtools/test/tools/javac/enum/6424358/T6424358.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/enum/6424358/T6424358.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug     6424358 7025809
  * @summary Synthesized static enum method values() is final
  * @author  Peter von der Ah\u00e9
- * @library ../../lib
+ * @library /tools/javac/lib
  * @build   JavacTestingAbstractProcessor T6424358
  * @compile -processor T6424358 -proc:only T6424358.java
  */
--- a/langtools/test/tools/javac/file/T7018098.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/file/T7018098.java	Wed Jul 05 18:34:52 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 7018098
  * @summary CacheFSInfo persists too long
- * @library ../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor T7018098
  * @run main T7018098
  */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/file/zip/8003512/LoadClassFromJava6CreatedJarTest.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,183 @@
+
+/*
+ * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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 8003512
+ * @summary javac doesn't work with jar files with >64k entries
+ * @compile -target 6 -source 6 -XDignore.symbol.file LoadClassFromJava6CreatedJarTest.java ../Utils.java
+ * @run main/timeout=360 LoadClassFromJava6CreatedJarTest
+ */
+
+/*
+ * The test creates a jar file with more than 64K entries. The jar file is
+ * created executing the LoadClassFromJava6CreatedJarTest$MakeJar
+ * class with a JVM version 6. The test must include Java 6 features only.
+ *
+ * The aim is to verify classes included in jar files with more than 64K entries
+ * created with Java 6 can be loaded by more recent versions of Java.
+ *
+ * A path to JDK or JRE version 6 is needed. This can be provided
+ * by passing this option to jtreg:
+ * -javaoption:-Djava6.home="/path/to/jdk_or_jre6"
+ */
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.Arrays;
+import java.util.List;
+import java.util.zip.CRC32;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+public class LoadClassFromJava6CreatedJarTest {
+
+    static final String javaHome6 = System.getProperty("java6.home");
+    static final String testClasses = System.getProperty("test.classes");
+
+    public static void main(String... args)
+            throws IOException, InterruptedException {
+        if (javaHome6 != null) {
+            new LoadClassFromJava6CreatedJarTest().run();
+        } else {
+            System.out.println(
+                "The test LoadClassFromJava6CreatedJarTest cannot be executed. " +
+                "In order to run it you should pass an option with " +
+                "this form -javaoption:-Djava6.home=\"/path/to/jdk_or_jre6\" " +
+                "to jtreg.");
+        }
+    }
+
+    void run() throws IOException, InterruptedException {
+        File classA = new File("A.java");
+        Utils.createJavaFile(classA, null);
+        if (!Utils.compile("-target", "6", "-source", "6",
+            classA.getAbsolutePath())) {
+            throw new AssertionError("Test failed while compiling class A");
+        }
+
+        executeCommand(Arrays.asList(javaHome6 + "/bin/java", "-classpath",
+            testClasses, "LoadClassFromJava6CreatedJarTest$MakeJar"));
+
+        File classB = new File("B.java");
+        Utils.createJavaFile(classB, classA);
+        if (!Utils.compile("-cp", "a.jar", classB.getAbsolutePath())) {
+            throw new AssertionError("Test failed while compiling class Main");
+        }
+    }
+
+    void executeCommand(List<String> command)
+            throws IOException, InterruptedException {
+        ProcessBuilder pb = new ProcessBuilder(command).
+            redirectErrorStream(true);
+        Process p = pb.start();
+        BufferedReader r =
+            new BufferedReader(new InputStreamReader(p.getInputStream()));
+        String line;
+        while ((line = r.readLine()) != null) {
+            System.err.println(line);
+        }
+        int rc = p.waitFor();
+        if (rc != 0) {
+            throw new AssertionError("Unexpected exit code: " + rc);
+        }
+    }
+
+    static class MakeJar {
+        public static void main(String[] args) throws Throwable {
+            File classFile = new File("A.class");
+            ZipOutputStream zos = null;
+            FileInputStream fis = null;
+            final int MAX = Short.MAX_VALUE * 2 + 10;
+            ZipEntry ze = null;
+            try {
+                zos = new ZipOutputStream(new FileOutputStream("a.jar"));
+                zos.setLevel(ZipOutputStream.STORED);
+                zos.setMethod(ZipOutputStream.STORED);
+                for (int i = 0; i < MAX ; i++) {
+                    ze = new ZipEntry("X" + i + ".txt");
+                    ze.setSize(0);
+                    ze.setCompressedSize(0);
+                    ze.setCrc(0);
+                    zos.putNextEntry(ze);
+                }
+
+                // add a class file
+                ze = new ZipEntry("A.class");
+                ze.setCompressedSize(classFile.length());
+                ze.setSize(classFile.length());
+                ze.setCrc(computeCRC(classFile));
+                zos.putNextEntry(ze);
+                fis = new FileInputStream(classFile);
+                for (int c; (c = fis.read()) >= 0;) {
+                    zos.write(c);
+                }
+            } finally {
+                zos.close();
+                fis.close();
+            }
+        }
+
+        private static final int BUFFER_LEN = Short.MAX_VALUE * 2;
+
+        static long getCount(long minlength) {
+            return (minlength / BUFFER_LEN) + 1;
+        }
+
+        static long computeCRC(long minlength) {
+            CRC32 crc = new CRC32();
+            byte[] buffer = new byte[BUFFER_LEN];
+            long count = getCount(minlength);
+            for (long i = 0; i < count; i++) {
+                crc.update(buffer);
+            }
+            return crc.getValue();
+        }
+
+        static long computeCRC(File inFile) throws IOException {
+            byte[] buffer = new byte[8192];
+            CRC32 crc = new CRC32();
+            FileInputStream fis = null;
+            BufferedInputStream bis = null;
+            try {
+                fis = new FileInputStream(inFile);
+                bis = new BufferedInputStream(fis);
+                int n = bis.read(buffer);
+                while (n > 0) {
+                    crc.update(buffer, 0, n);
+                    n = bis.read(buffer);
+                }
+            } finally {
+                bis.close();
+                fis.close();
+            }
+            return crc.getValue();
+        }
+    }
+}
--- a/langtools/test/tools/javac/file/zip/Utils.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/file/zip/Utils.java	Wed Jul 05 18:34:52 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 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
@@ -21,6 +21,12 @@
  * questions.
  */
 
+/*
+ * This utils class is been used by test T8003512 which is compiled with Java 6
+ * only features. So if this class is modified, it should be so using Java 6
+ * features only.
+ */
+
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
 import java.io.Closeable;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/BadMethodCall2.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,13 @@
+/**
+ * @test /nodynamiccopyright/
+ * @bug 8004099
+ * @summary Bad compiler diagnostic generated when poly expression is passed to non-existent method
+ * @compile/fail/ref=BadMethodCall2.out -XDrawDiagnostics BadMethodCall2.java
+ */
+class BadMethodCall2 {
+     void test(Object rec) {
+         rec.nonExistent(System.out::println);
+         rec.nonExistent(()->{});
+         rec.nonExistent(true ? "1" : "2");
+     }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/BadMethodCall2.out	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,4 @@
+BadMethodCall2.java:9:13: compiler.err.cant.resolve.location.args: kindname.method, nonExistent, , @309, (compiler.misc.location.1: kindname.variable, rec, java.lang.Object)
+BadMethodCall2.java:10:13: compiler.err.cant.resolve.location.args: kindname.method, nonExistent, , @356, (compiler.misc.location.1: kindname.variable, rec, java.lang.Object)
+BadMethodCall2.java:11:13: compiler.err.cant.resolve.location.args: kindname.method, nonExistent, , @390, (compiler.misc.location.1: kindname.variable, rec, java.lang.Object)
+3 errors
--- a/langtools/test/tools/javac/lambda/TestInvokeDynamic.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/lambda/TestInvokeDynamic.java	Wed Jul 05 18:34:52 2017 +0200
@@ -50,6 +50,7 @@
 import com.sun.tools.javac.code.Symbol;
 import com.sun.tools.javac.code.Symbol.MethodSymbol;
 import com.sun.tools.javac.code.Symtab;
+import com.sun.tools.javac.code.Types;
 import com.sun.tools.javac.jvm.Pool;
 import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
 import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
@@ -151,7 +152,7 @@
 
         abstract boolean check(CPInfo cpInfo) throws Exception;
 
-        Object getValue(Symtab syms, Names names) {
+        Object getValue(Symtab syms, Names names, Types types) {
             switch (this) {
                 case STRING:
                 case INTEGER:
@@ -162,7 +163,7 @@
                 case CLASS:
                     return syms.stringType.tsym;
                 case METHOD_HANDLE:
-                    return new Pool.MethodHandle(REF_invokeVirtual, syms.arrayCloneMethod);
+                    return new Pool.MethodHandle(REF_invokeVirtual, syms.arrayCloneMethod, types);
                 case METHOD_TYPE:
                     return syms.arrayCloneMethod.type;
                 default:
@@ -231,7 +232,8 @@
         Context context = ct.getContext();
         Symtab syms = Symtab.instance(context);
         Names names = Names.instance(context);
-        ct.addTaskListener(new Indifier(syms, names));
+        Types types = Types.instance(context);
+        ct.addTaskListener(new Indifier(syms, names, types));
         try {
             ct.generate();
         } catch (Throwable t) {
@@ -378,10 +380,12 @@
         MethodSymbol bsm;
         Symtab syms;
         Names names;
+        Types types;
 
-        Indifier(Symtab syms, Names names) {
+        Indifier(Symtab syms, Names names, Types types) {
             this.syms = syms;
             this.names = names;
+            this.types = types;
         }
 
         @Override
@@ -405,7 +409,7 @@
             if (!oldSym.isConstructor()) {
                 Object[] staticArgs = new Object[arity.arity];
                 for (int i = 0; i < arity.arity ; i++) {
-                    staticArgs[i] = saks[i].getValue(syms, names);
+                    staticArgs[i] = saks[i].getValue(syms, names, types);
                 }
                 ident.sym = new Symbol.DynamicMethodSymbol(oldSym.name, oldSym.owner, REF_invokeStatic, bsm, oldSym.type, staticArgs);
             }
--- a/langtools/test/tools/javac/multicatch/model/ModelChecker.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/multicatch/model/ModelChecker.java	Wed Jul 05 18:34:52 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 6993963 7025809
  * @summary Project Coin: Use precise exception analysis for effectively final catch parameters
- * @library ../../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor ModelChecker
  * @compile -processor ModelChecker Model01.java
  */
--- a/langtools/test/tools/javac/options/T7022337.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/options/T7022337.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @test
  * @bug 7022337
  * @summary repeated warnings about bootclasspath not set
- * @library ../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor T7022337
  * @run main T7022337
  */
--- a/langtools/test/tools/javac/plugin/showtype/ShowTypePlugin.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/plugin/showtype/ShowTypePlugin.java	Wed Jul 05 18:34:52 2017 +0200
@@ -41,7 +41,7 @@
         return "showtype";
     }
 
-    public void call(JavacTask task, String... args) {
+    public void init(JavacTask task, String... args) {
         Pattern pattern = null;
         if (args.length == 1)
             pattern = Pattern.compile(args[0]);
--- a/langtools/test/tools/javac/plugin/showtype/Test.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/plugin/showtype/Test.java	Wed Jul 05 18:34:52 2017 +0200
@@ -1,22 +1,3 @@
-
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.nio.charset.Charset;
-import java.nio.file.Files;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Locale;
-import java.util.Objects;
-import javax.tools.JavaCompiler;
-import javax.tools.JavaFileManager;
-import javax.tools.JavaFileObject;
-import javax.tools.StandardJavaFileManager;
-import javax.tools.StandardLocation;
-import javax.tools.ToolProvider;
-
 /*
  * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -42,10 +23,28 @@
 
 /**
  *  @test
- *  @bug 8001098
+ *  @bug 8001098 8004961
  *  @summary Provide a simple light-weight "plug-in" mechanism for javac
  */
 
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+import java.util.Objects;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.StandardLocation;
+import javax.tools.ToolProvider;
+
 public class Test {
     public static void main(String... args) throws Exception {
         new Test().run();
--- a/langtools/test/tools/javac/processing/6348499/T6348499.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/6348499/T6348499.java	Wed Jul 05 18:34:52 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 6441871
  * @summary javac crashes at com.sun.tools.javac.jvm.ClassReader$BadClassFile
- * @library ../../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor A
  * @run main T6348499
  */
--- a/langtools/test/tools/javac/processing/6359313/T6359313.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/6359313/T6359313.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug     6359313
  * @summary error compiling annotated package
  * @author  Peter von der Ah\u00e9
- * @library ../../lib
+ * @library /tools/javac/lib
  * @build   JavacTestingAbstractProcessor
  * @compile T6359313.java
  * @compile -processor T6359313 package-info.java Foo.java
--- a/langtools/test/tools/javac/processing/6365040/T6365040.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/6365040/T6365040.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 6365040 6358129
  * @summary Test -processor foo,bar,baz
  * @author  Joseph D. Darcy
- * @library ../../lib
+ * @library /tools/javac/lib
  * @build   JavacTestingAbstractProcessor
  * @compile ProcFoo.java
  * @compile ProcBar.java
--- a/langtools/test/tools/javac/processing/6413690/T6413690.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/6413690/T6413690.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug     6413690 6380018
  * @summary JavacProcessingEnvironment does not enter trees from preceding rounds
  * @author  Peter von der Ah\u00e9
- * @library ../../lib
+ * @library /tools/javac/lib
  * @build   JavacTestingAbstractProcessor
  * @compile T6413690.java
  * @compile -XDfatalEnterError -verbose -processor T6413690 src/Super.java TestMe.java
--- a/langtools/test/tools/javac/processing/6414633/T6414633.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/6414633/T6414633.java	Wed Jul 05 18:34:52 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 6414633 6440109
  * @summary Only the first processor message at a source location is reported
- * @library ../../lib
+ * @library /tools/javac/lib
  * @build    JavacTestingAbstractProcessor A T6414633
  * @run main T6414633
  */
--- a/langtools/test/tools/javac/processing/6430209/T6430209.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/6430209/T6430209.java	Wed Jul 05 18:34:52 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 6441871
  * @summary spurious compiler error elicited by packageElement.getEnclosedElements()
- * @library ../../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor b6341534
  * @run main T6430209
  */
--- a/langtools/test/tools/javac/processing/6499119/ClassProcessor.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/6499119/ClassProcessor.java	Wed Jul 05 18:34:52 2017 +0200
@@ -32,7 +32,7 @@
  * @test
  * @bug 6499119
  * @summary Created package-info class file modeled improperly
- * @library ../../lib
+ * @library /tools/javac/lib
  * @build   JavacTestingAbstractProcessor
  * @compile ClassProcessor.java package-info.java
  * @compile/process -cp . -processor ClassProcessor -Akind=java  java.lang.Object
--- a/langtools/test/tools/javac/processing/6511613/clss41701.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/6511613/clss41701.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 6511613
  * @summary javac unexpectedly doesn't fail in some cases if an annotation processor specified
  *
- * @library ../../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor DummyProcessor
  * @compile/fail clss41701.java
  * @compile/fail -processor DummyProcessor clss41701.java
--- a/langtools/test/tools/javac/processing/6512707/T6512707.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/6512707/T6512707.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 6512707
  * @summary "incompatible types" after (unrelated) annotation processing
  * @author  Peter Runge
- * @library ../../lib
+ * @library /tools/javac/lib
  * @build   JavacTestingAbstractProcessor
  * @compile T6512707.java
  * @compile -processor T6512707 TestAnnotation.java
--- a/langtools/test/tools/javac/processing/6634138/T6634138.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/6634138/T6634138.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 6634138
  * @author  Joseph D. Darcy
  * @summary Verify source files output after processing is over are compiled
- * @library ../../lib
+ * @library /tools/javac/lib
  * @build   JavacTestingAbstractProcessor
  * @compile T6634138.java
  * @compile -processor T6634138 Dummy.java
--- a/langtools/test/tools/javac/processing/6994946/SemanticErrorTest.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/6994946/SemanticErrorTest.java	Wed Jul 05 18:34:52 2017 +0200
@@ -2,7 +2,7 @@
  * @test /nodynamiccopyright/
  * @bug 6994946
  * @summary option to specify only syntax errors as unrecoverable
- * @library ../../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor TestProcessor
  * @compile/fail/ref=SemanticErrorTest.1.out -XDrawDiagnostics                                  -processor TestProcessor SemanticErrorTest.java
  * @compile/fail/ref=SemanticErrorTest.2.out -XDrawDiagnostics -XDonlySyntaxErrorsUnrecoverable -processor TestProcessor SemanticErrorTest.java
--- a/langtools/test/tools/javac/processing/6994946/SyntaxErrorTest.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/6994946/SyntaxErrorTest.java	Wed Jul 05 18:34:52 2017 +0200
@@ -2,7 +2,7 @@
  * @test /nodynamiccopyright/
  * @bug 6994946
  * @summary option to specify only syntax errors as unrecoverable
- * @library ../../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor TestProcessor
  * @compile/fail/ref=SyntaxErrorTest.out -XDrawDiagnostics                                  -processor TestProcessor SyntaxErrorTest.java
  * @compile/fail/ref=SyntaxErrorTest.out -XDrawDiagnostics -XDonlySyntaxErrorsUnrecoverable -processor TestProcessor SyntaxErrorTest.java
--- a/langtools/test/tools/javac/processing/T6920317.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/T6920317.java	Wed Jul 05 18:34:52 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 6920317
  * @summary package-info.java file has to be specified on the javac cmdline, else it will not be avail
- * @library ../lib
+ * @library /tools/javac/lib
  */
 
 import java.io.*;
--- a/langtools/test/tools/javac/processing/T7196462.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/T7196462.java	Wed Jul 05 18:34:52 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 7196462
  * @summary JavacProcessingEnvironment should tolerate BasicJavacTask
- * @library ../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor T7196462
  * @compile/process -processor T7196462 T7196462.java
  */
--- a/langtools/test/tools/javac/processing/TestWarnErrorCount.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/TestWarnErrorCount.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @test
  * @bug 7022337
  * @summary repeated warnings about bootclasspath not set
- * @library ../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor TestWarnErrorCount
  * @run main TestWarnErrorCount
  */
--- a/langtools/test/tools/javac/processing/environment/TestSourceVersion.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/environment/TestSourceVersion.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 6402506
  * @summary Test that getSourceVersion works properly
  * @author  Joseph D. Darcy
- * @library ../../lib
+ * @library /tools/javac/lib
  * @build   JavacTestingAbstractProcessor
  * @compile TestSourceVersion.java
  * @compile -processor TestSourceVersion -proc:only -source 1.2 -AExpectedVersion=RELEASE_2 HelloWorld.java
--- a/langtools/test/tools/javac/processing/environment/round/TestContext.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/environment/round/TestContext.java	Wed Jul 05 18:34:52 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 6988836
  * @summary A new JavacElements is created for each round of annotation processing
- * @library ../../../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor TestContext
  * @compile/process -processor TestContext -XprintRounds TestContext
  */
--- a/langtools/test/tools/javac/processing/environment/round/TestElementsAnnotatedWith.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/environment/round/TestElementsAnnotatedWith.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 6397298 6400986 6425592 6449798 6453386 6508401 6498938 6911854
  * @summary Tests that getElementsAnnotatedWith works properly.
  * @author  Joseph D. Darcy
- * @library ../../../lib
+ * @library /tools/javac/lib
  * @build   JavacTestingAbstractProcessor
  * @compile TestElementsAnnotatedWith.java
  * @compile InheritedAnnotation.java
--- a/langtools/test/tools/javac/processing/errors/TestErrorCount.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/errors/TestErrorCount.java	Wed Jul 05 18:34:52 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 6988079
  * @summary Errors reported via Messager.printMessage(ERROR,"error message") are not tallied correctly
- * @library ../../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor TestErrorCount
  * @compile/fail/ref=TestErrorCount.out -XDrawDiagnostics -processor TestErrorCount TestErrorCount.java
  */
--- a/langtools/test/tools/javac/processing/errors/TestFatalityOfParseErrors.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/errors/TestFatalityOfParseErrors.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 6403459
  * @summary Test that generating programs with syntax errors is a fatal condition
  * @author  Joseph D. Darcy
- * @library ../../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor
  * @compile TestReturnCode.java
  * @compile TestFatalityOfParseErrors.java
--- a/langtools/test/tools/javac/processing/errors/TestOptionSyntaxErrors.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/errors/TestOptionSyntaxErrors.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 6406212
  * @summary Test that annotation processor options with illegal syntax are rejected
  * @author  Joseph D. Darcy
- * @library ../../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor CompileFail
  * @compile TestOptionSyntaxErrors.java
  * @run main CompileFail CMDERR -A TestOptionSyntaxErrors.java
--- a/langtools/test/tools/javac/processing/errors/TestParseErrors/TestParseErrors.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/errors/TestParseErrors/TestParseErrors.java	Wed Jul 05 18:34:52 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 6988407
  * @summary javac crashes running processor on errant code; it used to print error message
- * @library ../../../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor TestParseErrors
  * @compile/fail/ref=TestParseErrors.out -XDrawDiagnostics -proc:only -processor TestParseErrors ParseErrors.java
  */
--- a/langtools/test/tools/javac/processing/errors/TestReturnCode.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/errors/TestReturnCode.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 6403468
  * @summary Test that an erroneous return code results from raising an error.
  * @author  Joseph D. Darcy
- * @library ../../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor CompileFail
  * @compile TestReturnCode.java
  *
--- a/langtools/test/tools/javac/processing/filer/TestFilerConstraints.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/filer/TestFilerConstraints.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 6380018 6453386 6457283
  * @summary Test that the constraints guaranteed by the Filer and maintained
  * @author  Joseph D. Darcy
- * @library ../../lib
+ * @library /tools/javac/lib
  * @build TestFilerConstraints
  * @compile -encoding iso-8859-1 -processor TestFilerConstraints -proc:only TestFilerConstraints.java
  */
--- a/langtools/test/tools/javac/processing/filer/TestGetResource.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/filer/TestGetResource.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 6380018 6449798
  * @summary Test Filer.getResource
  * @author  Joseph D. Darcy
- * @library ../../lib
+ * @library /tools/javac/lib
  * @build  JavacTestingAbstractProcessor TestGetResource
  * @compile -processor TestGetResource -proc:only -Aphase=write TestGetResource.java
  * @compile -processor TestGetResource -proc:only -Aphase=read  TestGetResource.java
--- a/langtools/test/tools/javac/processing/filer/TestGetResource2.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/filer/TestGetResource2.java	Wed Jul 05 18:34:52 2017 +0200
@@ -24,7 +24,7 @@
 /* @test
  * @bug 6929404
  * @summary Filer.getResource(SOURCE_PATH, ...) does not work when -sourcepath contains >1 entry
- * @library ../../lib
+ * @library /tools/javac/lib
  */
 
 import java.io.*;
--- a/langtools/test/tools/javac/processing/filer/TestInvalidRelativeNames.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/filer/TestInvalidRelativeNames.java	Wed Jul 05 18:34:52 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 6502392
  * @summary Invalid relative names for Filer.createResource and Filer.getResource
- * @library ../../lib
+ * @library /tools/javac/lib
  * @build   JavacTestingAbstractProcessor
  * @compile TestInvalidRelativeNames.java
  * @compile/process -processor TestInvalidRelativeNames java.lang.Object
--- a/langtools/test/tools/javac/processing/filer/TestLastRound.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/filer/TestLastRound.java	Wed Jul 05 18:34:52 2017 +0200
@@ -24,7 +24,7 @@
 /*
  * @test 6966604
  * @summary JavacFiler not correctly notified of lastRound
- * @library ../../lib
+ * @library /tools/javac/lib
  * @build   JavacTestingAbstractProcessor
  * @compile TestLastRound.java
  * @compile/fail/ref=TestLastRound.out -XDrawDiagnostics -Werror -proc:only -processor TestLastRound TestLastRound.java
--- a/langtools/test/tools/javac/processing/filer/TestPackageInfo.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/filer/TestPackageInfo.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 6380018 6392177 6993311
  * @summary Test the ability to create and process package-info.java files
  * @author  Joseph D. Darcy
- * @library ../../lib
+ * @library /tools/javac/lib
  * @build   JavacTestingAbstractProcessor
  * @compile TestPackageInfo.java
  * @compile -processor TestPackageInfo -proc:only foo/bar/package-info.java TestPackageInfo.java
--- a/langtools/test/tools/javac/processing/filer/TestValidRelativeNames.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/filer/TestValidRelativeNames.java	Wed Jul 05 18:34:52 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 6999891
  * @summary Test valid relative names for Filer.createResource and Filer.getResource
- * @library ../../lib
+ * @library /tools/javac/lib
  * @build   JavacTestingAbstractProcessor
  * @compile TestValidRelativeNames.java
  * @compile/process -processor TestValidRelativeNames -Amode=create java.lang.Object
--- a/langtools/test/tools/javac/processing/messager/6362067/T6362067.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/messager/6362067/T6362067.java	Wed Jul 05 18:34:52 2017 +0200
@@ -2,7 +2,7 @@
  * @test  /nodynamiccopyright/
  * @bug     6362067
  * @summary Messager methods do not print out source position information
- * @library ../../../lib
+ * @library /tools/javac/lib
  * @build   JavacTestingAbstractProcessor T6362067
  * @compile -processor T6362067 -proc:only T6362067.java
  * @compile/ref=T6362067.out -XDrawDiagnostics -processor T6362067 -proc:only T6362067.java
--- a/langtools/test/tools/javac/processing/messager/MessagerBasics.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/messager/MessagerBasics.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug     6341173 6341072
  * @summary Test presence of Messager methods
  * @author  Joseph D. Darcy
- * @library ../../lib
+ * @library /tools/javac/lib
  * @build   JavacTestingAbstractProcessor
  * @compile MessagerBasics.java
  * @compile -processor MessagerBasics -proc:only MessagerBasics.java
--- a/langtools/test/tools/javac/processing/model/6194785/T6194785.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/model/6194785/T6194785.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug     6194785
  * @summary ParameterDeclaration.getSimpleName does not return actual name from class files
  * @author  Peter von der Ah\u00e9
- * @library ../../../lib
+ * @library /tools/javac/lib
  * @build   JavacTestingAbstractProcessor
  * @compile -g T6194785.java T6194785a.java
  * @compile -processor T6194785 foo.T6194785a T6194785.java
--- a/langtools/test/tools/javac/processing/model/6341534/T6341534.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/model/6341534/T6341534.java	Wed Jul 05 18:34:52 2017 +0200
@@ -27,7 +27,7 @@
  * @summary PackageElement.getEnclosedElements results in NullPointerException from parse(JavaCompiler.java:429)
  * @author  Steve Sides
  * @author  Peter von der Ahe
- * @library ../../../lib
+ * @library /tools/javac/lib
  * @build   JavacTestingAbstractProcessor
  * @compile T6341534.java
  * @compile -proc:only -processor T6341534 dir/package-info.java
--- a/langtools/test/tools/javac/processing/model/element/TestAnonClassNames.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/model/element/TestAnonClassNames.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 6449781 6930508
  * @summary Test that reported names of anonymous classes are non-null.
  * @author  Joseph D. Darcy
- * @library ../../../lib
+ * @library /tools/javac/lib
  * @build   JavacTestingAbstractProcessor TestAnonSourceNames
  * @compile -processor TestAnonSourceNames TestAnonClassNames.java
  * @run main TestAnonClassNames
--- a/langtools/test/tools/javac/processing/model/element/TestElement.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/model/element/TestElement.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 6453386
  * @summary Test basic properties of javax.lang.element.Element
  * @author  Joseph D. Darcy
- * @library ../../../lib
+ * @library /tools/javac/lib
  * @build   JavacTestingAbstractProcessor TestElement
  * @compile -processor TestElement -proc:only TestElement.java
  */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/processing/model/element/TestExecutableElement.java	Wed Jul 05 18:34:52 2017 +0200
@@ -0,0 +1,113 @@
+/*
+ * 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 8005046
+ * @summary Test basic properties of javax.lang.element.Element
+ * @author  Joseph D. Darcy
+ * @library /tools/javac/lib
+ * @build   JavacTestingAbstractProcessor TestExecutableElement
+ * @compile -processor TestExecutableElement -proc:only TestExecutableElement.java
+ */
+
+import java.lang.annotation.*;
+import java.util.Formatter;
+import java.util.Set;
+import java.util.Objects;
+import javax.annotation.processing.*;
+import javax.lang.model.SourceVersion;
+import static javax.lang.model.SourceVersion.*;
+import javax.lang.model.element.*;
+import javax.lang.model.util.*;
+import static javax.lang.model.util.ElementFilter.*;
+import static javax.tools.Diagnostic.Kind.*;
+import static javax.tools.StandardLocation.*;
+
+/**
+ * Test some basic workings of javax.lang.element.ExecutableElement
+ */
+public class TestExecutableElement extends JavacTestingAbstractProcessor implements ProviderOfDefault {
+    @IsDefault(false)
+    public boolean process(Set<? extends TypeElement> annotations,
+                           RoundEnvironment roundEnv) {
+        int errors = 0;
+        if (!roundEnv.processingOver()) {
+            boolean hasRun = false;
+            for (Element element : roundEnv.getRootElements()) {
+                for (ExecutableElement method : methodsIn(element.getEnclosedElements())) {
+                    hasRun = true;
+                    errors += checkIsDefault(method);
+                }
+            }
+
+            if (!hasRun) {
+                messager.printMessage(ERROR, "No test cases run; test fails.");
+            }
+        }
+        return true;
+    }
+
+    @IsDefault(false)
+    int checkIsDefault(ExecutableElement method) {
+        System.out.println("Testing " + method);
+        IsDefault expectedIsDefault = method.getAnnotation(IsDefault.class);
+
+        boolean expectedDefault = (expectedIsDefault != null) ?
+            expectedIsDefault.value() :
+            false;
+
+        boolean methodIsDefault = method.isDefault();
+
+        if (methodIsDefault != expectedDefault) {
+            messager.printMessage(ERROR,
+                                  new Formatter().format("Unexpected Executable.isDefault result: got %s, expected %s",
+                                                         expectedDefault,
+                                                         methodIsDefault).toString(),
+                                  method);
+            return 1;
+        }
+        return 0;
+    }
+}
+
+/**
+ * Expected value of the ExecutableElement.isDefault method.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+@interface IsDefault {
+    boolean value();
+}
+
+/**
+ * Test interface to provide a default method.
+ */
+interface ProviderOfDefault {
+    @IsDefault(false)
+    boolean process(Set<? extends TypeElement> annotations,
+                    RoundEnvironment roundEnv);
+
+    @IsDefault(true)
+    default void quux() {};
+}
--- a/langtools/test/tools/javac/processing/model/element/TestMissingElement/TestMissingElement.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/model/element/TestMissingElement/TestMissingElement.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @test
  * @bug 6639645 7026414 7025809
  * @summary Modeling type implementing missing interfaces
- * @library ../../../../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor TestMissingElement
  * @compile -proc:only -XprintRounds -processor TestMissingElement InvalidSource.java
  */
--- a/langtools/test/tools/javac/processing/model/element/TestMissingElement2/TestMissingClass.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/model/element/TestMissingElement2/TestMissingClass.java	Wed Jul 05 18:34:52 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 6639645
  * @summary Modeling type implementing missing interfaces
- * @library ../../../../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor Generator
  * @compile -XprintRounds -processor Generator TestMissingClass.java
  * @run main TestMissingClass
--- a/langtools/test/tools/javac/processing/model/element/TestMissingElement2/TestMissingGenericClass1.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/model/element/TestMissingElement2/TestMissingGenericClass1.java	Wed Jul 05 18:34:52 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 6639645
  * @summary Modeling type implementing missing interfaces
- * @library ../../../../lib
+ * @library /tools/javac/lib
  * @clean MissingGenericClass1
  * @build JavacTestingAbstractProcessor Generator
  * @compile -XprintRounds -processor Generator TestMissingGenericClass1.java
--- a/langtools/test/tools/javac/processing/model/element/TestMissingElement2/TestMissingGenericClass2.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/model/element/TestMissingElement2/TestMissingGenericClass2.java	Wed Jul 05 18:34:52 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 6639645
  * @summary Modeling type implementing missing interfaces
- * @library ../../../../lib
+ * @library /tools/javac/lib
  * @clean MissingGenericClass2
  * @build JavacTestingAbstractProcessor Generator
  * @compile -XprintRounds -processor Generator TestMissingGenericClass2.java
--- a/langtools/test/tools/javac/processing/model/element/TestMissingElement2/TestMissingGenericInterface1.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/model/element/TestMissingElement2/TestMissingGenericInterface1.java	Wed Jul 05 18:34:52 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 6639645
  * @summary Modeling type implementing missing interfaces
- * @library ../../../../lib
+ * @library /tools/javac/lib
  * @clean MissingGenericInterface1
  * @build JavacTestingAbstractProcessor Generator
  * @compile -XprintRounds -processor Generator TestMissingGenericInterface1.java
--- a/langtools/test/tools/javac/processing/model/element/TestMissingElement2/TestMissingGenericInterface2.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/model/element/TestMissingElement2/TestMissingGenericInterface2.java	Wed Jul 05 18:34:52 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 6639645
  * @summary Modeling type implementing missing interfaces
- * @library ../../../../lib
+ * @library /tools/javac/lib
  * @clean MissingGenericInterface2
  * @build JavacTestingAbstractProcessor Generator
  * @compile -XprintRounds -processor Generator TestMissingGenericInterface2.java
--- a/langtools/test/tools/javac/processing/model/element/TestMissingElement2/TestMissingInterface.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/model/element/TestMissingElement2/TestMissingInterface.java	Wed Jul 05 18:34:52 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 6639645
  * @summary Modeling type implementing missing interfaces
- * @library ../../../../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor Generator
  * @compile -XprintRounds -processor Generator TestMissingInterface.java
  * @run main TestMissingInterface
--- a/langtools/test/tools/javac/processing/model/element/TestNames.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/model/element/TestNames.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 6380016
  * @summary Test that the constraints guaranteed by the Filer and maintained
  * @author  Joseph D. Darcy
- * @library ../../../lib
+ * @library /tools/javac/lib
  * @build   JavacTestingAbstractProcessor TestNames
  * @compile -processor TestNames -proc:only TestNames.java
  */
--- a/langtools/test/tools/javac/processing/model/element/TestPackageElement.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/model/element/TestPackageElement.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 6449798 6399404
  * @summary Test basic workings of PackageElement
  * @author  Joseph D. Darcy
- * @library ../../../lib
+ * @library /tools/javac/lib
  * @build   JavacTestingAbstractProcessor TestPackageElement
  * @compile -processor TestPackageElement -proc:only TestPackageElement.java
  */
--- a/langtools/test/tools/javac/processing/model/element/TestResourceElement.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/model/element/TestResourceElement.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 6967842
  * @summary Element not returned from tree API for ARM resource variables.
  * @author A. Sundararajan
- * @library ../../../lib
+ * @library /tools/javac/lib
  * @build   JavacTestingAbstractProcessor TestResourceElement
  * @compile -processor TestResourceElement -proc:only TestResourceElement.java
  */
--- a/langtools/test/tools/javac/processing/model/element/TestResourceVariable.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/model/element/TestResourceVariable.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug  6911256 6964740 6967842 6961571 7025809
  * @summary Test that the resource variable kind is appropriately set
  * @author  Joseph D. Darcy
- * @library ../../../lib
+ * @library /tools/javac/lib
  * @build   JavacTestingAbstractProcessor TestResourceVariable
  * @compile -processor TestResourceVariable -proc:only TestResourceVariable.java
  */
--- a/langtools/test/tools/javac/processing/model/element/TestTypeParameter.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/model/element/TestTypeParameter.java	Wed Jul 05 18:34:52 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 6505047
  * @summary javax.lang.model.element.Element.getEnclosingElement() doesn't return null for type parameter
- * @library ../../../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor TestTypeParameter
  * @compile -processor TestTypeParameter -proc:only TestTypeParameter.java
  */
--- a/langtools/test/tools/javac/processing/model/element/TypeParamBounds.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/model/element/TypeParamBounds.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug     6423972
  * @summary Tests TypeParameter.getBounds.
  * @author  Scott Seligman
- * @library ../../../lib
+ * @library /tools/javac/lib
  * @build   JavacTestingAbstractProcessor TypeParamBounds
  * @compile -processor TypeParamBounds -proc:only TypeParamBounds.java
  */
--- a/langtools/test/tools/javac/processing/model/type/MirroredTypeEx/OverEager.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/model/type/MirroredTypeEx/OverEager.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug     6362178
  * @summary MirroredType[s]Exception shouldn't be created too eagerly
  * @author  Scott Seligman
- * @library ../../../../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor
  * @compile -g OverEager.java
  * @compile -processor OverEager -proc:only OverEager.java
--- a/langtools/test/tools/javac/processing/model/type/MirroredTypeEx/Plurality.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/model/type/MirroredTypeEx/Plurality.java	Wed Jul 05 18:34:52 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug     6519115
  * @summary Verify MirroredTypeException vs MirroredTypesException is thrown
- * @library ../../../../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor
  * @compile Plurality.java
  * @compile -processor Plurality -proc:only Plurality.java
--- a/langtools/test/tools/javac/processing/model/type/NoTypes.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/model/type/NoTypes.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug     6418666 6423973 6453386 7025809
  * @summary Test the NoTypes: VOID, PACKAGE, NONE
  * @author  Scott Seligman
- * @library ../../../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor
  * @compile -g NoTypes.java
  * @compile -processor NoTypes -proc:only NoTypes.java
--- a/langtools/test/tools/javac/processing/model/type/TestUnionType.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/model/type/TestUnionType.java	Wed Jul 05 18:34:52 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug     7029150 7025809
  * @summary Test support for union types
- * @library ../../../lib
+ * @library /tools/javac/lib
  */
 
 import java.net.URI;
--- a/langtools/test/tools/javac/processing/model/util/BinaryName.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/model/util/BinaryName.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug     6346251
  * @summary Test Elements.getBinaryName
  * @author  Scott Seligman
- * @library ../../../lib
+ * @library /tools/javac/lib
  * @build   JavacTestingAbstractProcessor BinaryName
  * @compile -processor BinaryName -proc:only BinaryName.java
  */
--- a/langtools/test/tools/javac/processing/model/util/GetTypeElemBadArg.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/model/util/GetTypeElemBadArg.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug     6346506 6408241
  * @summary getTypeElement should tolerate a type that can't be found
  * @author  Scott Seligman
- * @library ../../../lib
+ * @library /tools/javac/lib
  * @build   JavacTestingAbstractProcessor GetTypeElemBadArg
  * @compile -processor GetTypeElemBadArg -proc:only GetTypeElemBadArg.java
  */
--- a/langtools/test/tools/javac/processing/model/util/NoSupers.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/model/util/NoSupers.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug     6346453
  * @summary directSupertypes should return empty list if arg has no supertypes
  * @author  Scott Seligman
- * @library ../../../lib
+ * @library /tools/javac/lib
  * @build   JavacTestingAbstractProcessor NoSupers
  * @compile -processor NoSupers -proc:only NoSupers.java
  */
--- a/langtools/test/tools/javac/processing/model/util/OverridesSpecEx.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/model/util/OverridesSpecEx.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug     6453386
  * @summary Verify that example code in Elements.overrides works as spec'ed.
  * @author  Scott Seligman
- * @library ../../../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor
  * @compile -g OverridesSpecEx.java
  * @compile -processor OverridesSpecEx -proc:only OverridesSpecEx.java
--- a/langtools/test/tools/javac/processing/model/util/TypesBadArg.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/model/util/TypesBadArg.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug     6345812
  * @summary Validate argument kinds in Types utilities
  * @author  Scott Seligman
- * @library ../../../lib
+ * @library /tools/javac/lib
  * @build   JavacTestingAbstractProcessor TypesBadArg
  * @compile -processor TypesBadArg -proc:only TypesBadArg.java
  */
--- a/langtools/test/tools/javac/processing/model/util/deprecation/TestDeprecation.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/model/util/deprecation/TestDeprecation.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 6392818
  * @summary Tests Elements.isDeprecated(Element)
  * @author  Joseph D. Darcy
- * @library ../../../../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor
  * @compile TestDeprecation.java
  * @compile -processor TestDeprecation -proc:only Dep1.java
--- a/langtools/test/tools/javac/processing/model/util/directSupersOfErr/DirectSupersOfErr.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/model/util/directSupersOfErr/DirectSupersOfErr.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug     6346973
  * @summary directSupertypes(t) should not return t
  * @author  Scott Seligman
- * @library ../../../../lib
+ * @library /tools/javac/lib
  * @build   JavacTestingAbstractProcessor DirectSupersOfErr
  * @compile -processor DirectSupersOfErr -proc:only C1.java
  */
--- a/langtools/test/tools/javac/processing/model/util/elements/TestGetConstantExpression.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/model/util/elements/TestGetConstantExpression.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 6471577 6517779
  * @summary Test Elements.getConstantExpression
  * @author  Joseph D. Darcy
- * @library ../../../../lib
+ * @library /tools/javac/lib
  * @build   JavacTestingAbstractProcessor TestGetConstantExpression
  * @compile -processor TestGetConstantExpression Foo.java
  */
--- a/langtools/test/tools/javac/processing/model/util/elements/TestGetPackageOf.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/model/util/elements/TestGetPackageOf.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 6453386
  * @summary Test Elements.getPackageOf
  * @author  Joseph D. Darcy
- * @library ../../../../lib
+ * @library /tools/javac/lib
  * @build   JavacTestingAbstractProcessor TestGetPackageOf
  * @compile -processor TestGetPackageOf -proc:only TestGetPackageOf.java
  */
--- a/langtools/test/tools/javac/processing/model/util/filter/TestIterables.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/model/util/filter/TestIterables.java	Wed Jul 05 18:34:52 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 6406164
  * @summary Test that ElementFilter iterable methods behave properly.
  * @author  Joseph D. Darcy
- * @library ../../../../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor
  * @compile TestIterables.java
  * @compile -processor TestIterables -proc:only Foo1.java
--- a/langtools/test/tools/javac/processing/options/testCommandLineClasses/Test.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/options/testCommandLineClasses/Test.java	Wed Jul 05 18:34:52 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 6930508
  * @summary Passing nested class names on javac command line interfere with subsequent name -> class lookup
- * @library ../../../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor p.NestedExamples Test
  * @run main Test
  */
--- a/langtools/test/tools/javac/processing/options/testPrintProcessorInfo/Test.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/options/testPrintProcessorInfo/Test.java	Wed Jul 05 18:34:52 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 6987384
  * @summary -XprintProcessorRoundsInfo message printed with different timing than previous
- * @library ../../../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor Test
  * @compile/fail/ref=Test.out -XDrawDiagnostics -XprintProcessorInfo -Werror -proc:only -processor Test Test.java
  */
--- a/langtools/test/tools/javac/processing/options/testPrintProcessorInfo/TestWithXstdout.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/options/testPrintProcessorInfo/TestWithXstdout.java	Wed Jul 05 18:34:52 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 6987384
  * @summary -XprintProcessorRoundsInfo message printed with different timing than previous
- * @library ../../../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor Test TestWithXstdout
  * @run main TestWithXstdout
  */
--- a/langtools/test/tools/javac/processing/warnings/UseImplicit/TestProcUseImplicitWarning.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/warnings/UseImplicit/TestProcUseImplicitWarning.java	Wed Jul 05 18:34:52 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 6986892
  * @summary confusing warning given after errors in annotation processing
- * @library ../../../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor TestProcUseImplicitWarning
  * @clean C1 p.C2
  * @compile/fail/ref=err.out -XDrawDiagnostics -processor TestProcUseImplicitWarning -Aerror C1.java
--- a/langtools/test/tools/javac/processing/werror/WError1.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/werror/WError1.java	Wed Jul 05 18:34:52 2017 +0200
@@ -24,7 +24,7 @@
 /*
  * @test 6403456
  * @summary -Werror should work with annotation processing
- * @library ../../lib
+ * @library /tools/javac/lib
  * @build   JavacTestingAbstractProcessor
  * @compile WError1.java
  * @compile -proc:only -processor WError1 WError1.java
--- a/langtools/test/tools/javac/processing/werror/WErrorGen.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/werror/WErrorGen.java	Wed Jul 05 18:34:52 2017 +0200
@@ -24,7 +24,7 @@
 /*
  * @test 6403456
  * @summary -Werror should work with annotation processing
- * @library ../../lib
+ * @library /tools/javac/lib
  * @build   JavacTestingAbstractProcessor
  * @compile WErrorGen.java
  * @compile -proc:only -processor WErrorGen WErrorGen.java
--- a/langtools/test/tools/javac/processing/werror/WErrorLast.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/processing/werror/WErrorLast.java	Wed Jul 05 18:34:52 2017 +0200
@@ -24,7 +24,7 @@
 /*
  * @test 6403456
  * @summary -Werror should work with annotation processing
- * @library ../../lib
+ * @library /tools/javac/lib
  * @build   JavacTestingAbstractProcessor
  * @compile WErrorLast.java
  * @compile -proc:only -processor WErrorLast WErrorLast.java
--- a/langtools/test/tools/javac/resolve/ResolveHarness.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/resolve/ResolveHarness.java	Wed Jul 05 18:34:52 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 7098660
  * @summary Write better overload resolution/inference tests
- * @library ../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor ResolveHarness
  * @run main ResolveHarness
  */
--- a/langtools/test/tools/javac/util/T6597678.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/util/T6597678.java	Wed Jul 05 18:34:52 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 6597678 6449184
  * @summary Ensure Messages propogated between rounds
- * @library ../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor T6597678
  * @run main T6597678
  */
--- a/langtools/test/tools/javac/util/context/T7021650.java	Wed Jul 05 18:33:59 2017 +0200
+++ b/langtools/test/tools/javac/util/context/T7021650.java	Wed Jul 05 18:34:52 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @bug 7021650
  * @summary Fix Context issues
- * @library ../../lib
+ * @library /tools/javac/lib
  * @build JavacTestingAbstractProcessor T7021650
  * @run main T7021650
  */