Merge
authorduke
Wed, 05 Jul 2017 21:10:50 +0200
changeset 34852 bd26599f2098
parent 34851 3359dd18cde0 (current diff)
parent 34848 a3eed4c1badb (diff)
child 34858 ec69df775846
Merge
jdk/src/java.base/share/classes/sun/misc/CompoundEnumeration.java
jdk/src/java.base/share/classes/sun/misc/DoubleConsts.java
jdk/src/java.base/share/classes/sun/misc/FDBigInteger.java
jdk/src/java.base/share/classes/sun/misc/FloatConsts.java
jdk/src/java.base/share/classes/sun/misc/FloatingDecimal.java
jdk/src/java.base/share/classes/sun/misc/FormattedFloatingDecimal.java
jdk/test/java/awt/Mouse/MaximizedFrameTest/MaximizedFrameTest.html
jdk/test/javax/sound/midi/MidiDeviceProvider/FakeInfo.java
jdk/test/javax/sound/midi/MidiDeviceProvider/NullInfo.java
jdk/test/javax/sound/midi/MidiDeviceProvider/UnsupportedInfo.java
jdk/test/sun/misc/FloatingDecimal/OldFDBigIntForTest.java
jdk/test/sun/misc/FloatingDecimal/OldFloatingDecimalForTest.java
jdk/test/sun/misc/FloatingDecimal/TestFDBigInteger.java
jdk/test/sun/misc/FloatingDecimal/TestFloatingDecimal.java
--- a/.hgtags-top-repo	Thu Dec 24 10:33:21 2015 -0800
+++ b/.hgtags-top-repo	Wed Jul 05 21:10:50 2017 +0200
@@ -341,3 +341,4 @@
 5582a79892596169ebddb3e2c2aa44939e4e3f40 jdk-9+96
 75c3897541ecb52ee16d001ea605b12971df7303 jdk-9+97
 48987460c7d49a29013963ee44d090194396bb61 jdk-9+98
+7c0577bea4c65d69c5bef67023a89d2efa4fb2f7 jdk-9+99
--- a/common/bin/jib.sh	Thu Dec 24 10:33:21 2015 -0800
+++ b/common/bin/jib.sh	Wed Jul 05 21:10:50 2017 +0200
@@ -32,7 +32,7 @@
 install_data=${mydir}/../../.jib/.data
 
 setup_url() {
-    if [ -f "~/.config/jib/jib.conf" ]; then
+    if [ -f ~/.config/jib/jib.conf ]; then
         source ~/.config/jib/jib.conf
     fi
 
@@ -50,6 +50,9 @@
     if [ -n "${JIB_SERVER}" ]; then
         jib_server="${JIB_SERVER}"
     fi
+    if [ -n "${JIB_SERVER_MIRRORS}" ]; then
+        jib_server_mirrors="${JIB_SERVER_MIRRORS}"
+    fi
     if [ -n "${JIB_REPOSITORY}" ]; then
         jib_repository="${JIB_REPOSITORY}"
     fi
@@ -70,8 +73,9 @@
         jib_url="${JIB_URL}"
         data_string="${jib_url}"
     else
-        data_string="${jib_repository}/${jib_organization}/${jib_module}/${jib_revision}/${jib_module}-${jib_revision}.${jib_ext}"
-        jib_url="${jib_server}/${data_string}"
+        jib_path="${jib_repository}/${jib_organization}/${jib_module}/${jib_revision}/${jib_module}-${jib_revision}.${jib_ext}"
+        data_string="${jib_path}"
+        jib_url="${jib_server}/${jib_path}"
     fi
 }
 
@@ -104,7 +108,25 @@
     ${getcmd} ${jib_url} > "${installed_jib_script}.gz"
     if [ ! -s "${installed_jib_script}.gz" ]; then
         echo "Failed to download ${jib_url}"
-        exit 1
+        if [ -n "${jib_path}" -a -n "${jib_server_mirrors}" ]; then
+            OLD_IFS="${IFS}"
+            IFS=" ,"
+            for mirror in ${jib_server_mirrors}; do
+                echo "Trying mirror ${mirror}"
+                jib_url="${mirror}/${jib_path}"
+                ${getcmd} ${jib_url} > "${installed_jib_script}.gz"
+                if [ -s "${installed_jib_script}.gz" ]; then
+                    echo "Download from mirror successful"
+                    break
+                else
+                    echo "Failed to download ${jib_url}"
+                fi
+            done
+            IFS="${OLD_IFS}"
+        fi
+        if [ ! -s "${installed_jib_script}.gz" ]; then
+            exit 1
+        fi
     fi
     echo "Extracting JIB bootstrap script"
     rm -f "${installed_jib_script}"
--- a/corba/.hgtags	Thu Dec 24 10:33:21 2015 -0800
+++ b/corba/.hgtags	Wed Jul 05 21:10:50 2017 +0200
@@ -341,3 +341,4 @@
 feb1bd85d7990dcf5584ca9e53104269c01db006 jdk-9+96
 10a482b863582376d4ca229090334b23b05159fc jdk-9+97
 ea285530245cf4e0edf0479121a41347d3030eba jdk-9+98
+180212ee1d8710691ba9944593dfc1ff3e4f1532 jdk-9+99
--- a/hotspot/.hgtags	Thu Dec 24 10:33:21 2015 -0800
+++ b/hotspot/.hgtags	Wed Jul 05 21:10:50 2017 +0200
@@ -501,3 +501,4 @@
 a94bb7203596dd632486f1e3655fa5f70541dc08 jdk-9+96
 de592ea5f7ba0f8a8c5afc03bd169f7690c72b6f jdk-9+97
 e5b1a23be1e105417ba1c4c576ab373eb3fa2c2b jdk-9+98
+f008e8cc10d5b3212fb22d58c96fa01d38654f19 jdk-9+99
--- a/jaxp/.hgtags	Thu Dec 24 10:33:21 2015 -0800
+++ b/jaxp/.hgtags	Wed Jul 05 21:10:50 2017 +0200
@@ -341,3 +341,4 @@
 1f3182529f2c474e5506955ccb3820cfa5822265 jdk-9+96
 9c107c050335d7ee63b2a8b38ca5d498f19713a2 jdk-9+97
 52b01339235f24c93b679bd6b8fb36a1072ad0ac jdk-9+98
+52774b544850c791f1d1c67db2601b33739b18c9 jdk-9+99
--- a/jdk/.hgtags	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/.hgtags	Wed Jul 05 21:10:50 2017 +0200
@@ -341,3 +341,4 @@
 c021b855f51e572e63982654b17742cb1f814fb4 jdk-9+96
 fdd84b2265ddce7f50e084b7c8635189bba6f012 jdk-9+97
 f86ee68d1107dad41a27efc34306e0e56244a12e jdk-9+98
+e1a789be1535741274c9779f4d4ca3495196b5c3 jdk-9+99
--- a/jdk/make/launcher/Launcher-jdk.accessibility.gmk	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/make/launcher/Launcher-jdk.accessibility.gmk	Wed Jul 05 21:10:50 2017 +0200
@@ -73,8 +73,9 @@
     $$(eval $$(call SetupNativeCompilation, BUILD_JACCESSINSPECTOR$1, \
       SRC := $(TOPDIR)/jaccessinspector $(TOPDIR)/common \
           $(TOPDIR)/toolscommon $(TOPDIR)/include/bridge, \
-      CFLAGS := $$(CFLAGS_JDKEXE) $(TOOLS_CFLAGS) -DACCESSBRIDGE_ARCH_$2 /EHsc, \
-      LDFLAGS := $$(LDFLAGS_JDKEXE) /STACK:655360 Advapi32.lib User32.lib, \
+      CFLAGS := $$(CFLAGS_JDKEXE) $(TOOLS_CFLAGS) -DACCESSBRIDGE_ARCH_$2 -EHsc, \
+      LDFLAGS := $$(LDFLAGS_JDKEXE) -stack:655360, \
+      LIBS := advapi32.lib user32.lib, \
       OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/jdk.accessibility/jaccessinspector$1, \
       OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/modules_cmds/jdk.accessibility, \
       PROGRAM := jaccessinspector$1, \
@@ -100,8 +101,9 @@
     $$(eval $$(call SetupNativeCompilation,BUILD_JACCESSWALKER$1, \
       SRC := $(TOPDIR)/jaccesswalker $(TOPDIR)/common \
           $(TOPDIR)/toolscommon $(TOPDIR)/include/bridge, \
-      CFLAGS :== $$(CFLAGS_JDKEXE) $(TOOLS_CFLAGS) -DACCESSBRIDGE_ARCH_$2 /EHsc, \
-      LDFLAGS := $$(LDFLAGS_JDKEXE) /STACK:655360 Advapi32.lib Comctl32.lib Gdi32.lib User32.lib, \
+      CFLAGS := $$(CFLAGS_JDKEXE) $(TOOLS_CFLAGS) -DACCESSBRIDGE_ARCH_$2 -EHsc, \
+      LDFLAGS := $$(LDFLAGS_JDKEXE) -stack:655360, \
+      LIBS := advapi32.lib comctl32.lib gdi32.lib user32.lib, \
       OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/jdk.accessibility/jaccesswalker$1, \
       OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/modules_cmds/jdk.accessibility, \
       PROGRAM := jaccesswalker$1, \
--- a/jdk/src/java.base/linux/classes/sun/nio/ch/EPollSelectorImpl.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/linux/classes/sun/nio/ch/EPollSelectorImpl.java	Wed Jul 05 21:10:50 2017 +0200
@@ -29,7 +29,6 @@
 import java.nio.channels.*;
 import java.nio.channels.spi.*;
 import java.util.*;
-import sun.misc.*;
 
 /**
  * An implementation of Selector for Linux 2.6+ kernels that uses
@@ -50,7 +49,7 @@
     private Map<Integer,SelectionKeyImpl> fdToKey;
 
     // True if this Selector has been closed
-    private volatile boolean closed = false;
+    private volatile boolean closed;
 
     // Lock for interrupt triggering and clearing
     private final Object interruptLock = new Object();
--- a/jdk/src/java.base/linux/classes/sun/nio/fs/LinuxWatchService.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/linux/classes/sun/nio/fs/LinuxWatchService.java	Wed Jul 05 21:10:50 2017 +0200
@@ -322,19 +322,6 @@
                         bytesRead = 0;
                     }
 
-                    // process any pending requests
-                    if ((nReady > 1) || (nReady == 1 && bytesRead == 0)) {
-                        try {
-                            read(socketpair[0], address, BUFFER_SIZE);
-                            boolean shutdown = processRequests();
-                            if (shutdown)
-                                break;
-                        } catch (UnixException x) {
-                            if (x.errno() != UnixConstants.EAGAIN)
-                                throw x;
-                        }
-                    }
-
                     // iterate over buffer to decode events
                     int offset = 0;
                     while (offset < bytesRead) {
@@ -369,6 +356,19 @@
 
                         offset += (SIZEOF_INOTIFY_EVENT + len);
                     }
+
+                    // process any pending requests
+                    if ((nReady > 1) || (nReady == 1 && bytesRead == 0)) {
+                        try {
+                            read(socketpair[0], address, BUFFER_SIZE);
+                            boolean shutdown = processRequests();
+                            if (shutdown)
+                                break;
+                        } catch (UnixException x) {
+                            if (x.errno() != UnixConstants.EAGAIN)
+                                throw x;
+                        }
+                    }
                 }
             } catch (UnixException x) {
                 x.printStackTrace();
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java	Wed Jul 05 21:10:50 2017 +0200
@@ -93,7 +93,7 @@
 
     // Instance of this provider, so we don't have to call the provider list
     // to find ourselves or run the risk of not being in the list.
-    private static volatile SunJCE instance = null;
+    private static volatile SunJCE instance;
 
     // lazy initialize SecureRandom to avoid potential recursion if Sun
     // provider has not been installed yet
--- a/jdk/src/java.base/share/classes/java/io/File.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/io/File.java	Wed Jul 05 21:10:50 2017 +0200
@@ -420,11 +420,11 @@
         String scheme = uri.getScheme();
         if ((scheme == null) || !scheme.equalsIgnoreCase("file"))
             throw new IllegalArgumentException("URI scheme is not \"file\"");
-        if (uri.getAuthority() != null)
+        if (uri.getRawAuthority() != null)
             throw new IllegalArgumentException("URI has an authority component");
-        if (uri.getFragment() != null)
+        if (uri.getRawFragment() != null)
             throw new IllegalArgumentException("URI has a fragment component");
-        if (uri.getQuery() != null)
+        if (uri.getRawQuery() != null)
             throw new IllegalArgumentException("URI has a query component");
         String p = uri.getPath();
         if (p.equals(""))
--- a/jdk/src/java.base/share/classes/java/io/PipedInputStream.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/io/PipedInputStream.java	Wed Jul 05 21:10:50 2017 +0200
@@ -48,9 +48,9 @@
  * @since   1.0
  */
 public class PipedInputStream extends InputStream {
-    boolean closedByWriter = false;
-    volatile boolean closedByReader = false;
-    boolean connected = false;
+    boolean closedByWriter;
+    volatile boolean closedByReader;
+    boolean connected;
 
         /* REMIND: identification of the read and write sides needs to be
            more sophisticated.  Either using thread groups (but what about
--- a/jdk/src/java.base/share/classes/java/lang/AbstractStringBuilder.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/AbstractStringBuilder.java	Wed Jul 05 21:10:50 2017 +0200
@@ -25,7 +25,7 @@
 
 package java.lang;
 
-import sun.misc.FloatingDecimal;
+import jdk.internal.math.FloatingDecimal;
 import java.util.Arrays;
 import java.util.Spliterator;
 import java.util.stream.IntStream;
--- a/jdk/src/java.base/share/classes/java/lang/Class.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/Class.java	Wed Jul 05 21:10:50 2017 +0200
@@ -2518,7 +2518,7 @@
 
     // Incremented by the VM on each call to JVM TI RedefineClasses()
     // that redefines this class or a superclass.
-    private transient volatile int classRedefinedCount = 0;
+    private transient volatile int classRedefinedCount;
 
     // Lazily create and cache ReflectionData
     private ReflectionData<T> reflectionData() {
@@ -3331,7 +3331,8 @@
      * uncloned, cached, and shared by all callers.
      */
     T[] getEnumConstantsShared() {
-        if (enumConstants == null) {
+        T[] constants = enumConstants;
+        if (constants == null) {
             if (!isEnum()) return null;
             try {
                 final Method values = getMethod("values");
@@ -3344,16 +3345,16 @@
                         });
                 @SuppressWarnings("unchecked")
                 T[] temporaryConstants = (T[])values.invoke(null);
-                enumConstants = temporaryConstants;
+                enumConstants = constants = temporaryConstants;
             }
             // These can happen when users concoct enum-like classes
             // that don't comply with the enum spec.
             catch (InvocationTargetException | NoSuchMethodException |
                    IllegalAccessException ex) { return null; }
         }
-        return enumConstants;
+        return constants;
     }
-    private transient volatile T[] enumConstants = null;
+    private transient volatile T[] enumConstants;
 
     /**
      * Returns a map from simple name to enum constant.  This package-private
@@ -3363,19 +3364,21 @@
      * created lazily on first use.  Typically it won't ever get created.
      */
     Map<String, T> enumConstantDirectory() {
-        if (enumConstantDirectory == null) {
+        Map<String, T> directory = enumConstantDirectory;
+        if (directory == null) {
             T[] universe = getEnumConstantsShared();
             if (universe == null)
                 throw new IllegalArgumentException(
                     getName() + " is not an enum type");
-            Map<String, T> m = new HashMap<>(2 * universe.length);
-            for (T constant : universe)
-                m.put(((Enum<?>)constant).name(), constant);
-            enumConstantDirectory = m;
+            directory = new HashMap<>(2 * universe.length);
+            for (T constant : universe) {
+                directory.put(((Enum<?>)constant).name(), constant);
+            }
+            enumConstantDirectory = directory;
         }
-        return enumConstantDirectory;
+        return directory;
     }
-    private transient volatile Map<String, T> enumConstantDirectory = null;
+    private transient volatile Map<String, T> enumConstantDirectory;
 
     /**
      * Casts an object to the class or interface represented
--- a/jdk/src/java.base/share/classes/java/lang/ClassLoader.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/ClassLoader.java	Wed Jul 05 21:10:50 2017 +0200
@@ -45,11 +45,11 @@
 import java.util.Set;
 import java.util.Stack;
 import java.util.Map;
+import java.util.NoSuchElementException;
 import java.util.Vector;
 import java.util.Hashtable;
 import java.util.WeakHashMap;
 import java.util.concurrent.ConcurrentHashMap;
-import sun.misc.CompoundEnumeration;
 import sun.misc.Resource;
 import sun.misc.URLClassPath;
 import sun.reflect.CallerSensitive;
@@ -2206,3 +2206,36 @@
         return sys;
     }
 }
+
+/*
+ * A utility class that will enumerate over an array of enumerations.
+ */
+final class CompoundEnumeration<E> implements Enumeration<E> {
+    private final Enumeration<E>[] enums;
+    private int index;
+
+    public CompoundEnumeration(Enumeration<E>[] enums) {
+        this.enums = enums;
+    }
+
+    private boolean next() {
+        while (index < enums.length) {
+            if (enums[index] != null && enums[index].hasMoreElements()) {
+                return true;
+            }
+            index++;
+        }
+        return false;
+    }
+
+    public boolean hasMoreElements() {
+        return next();
+    }
+
+    public E nextElement() {
+        if (!next()) {
+            throw new NoSuchElementException();
+        }
+        return enums[index].nextElement();
+    }
+}
--- a/jdk/src/java.base/share/classes/java/lang/Double.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/Double.java	Wed Jul 05 21:10:50 2017 +0200
@@ -25,8 +25,8 @@
 
 package java.lang;
 
-import sun.misc.FloatingDecimal;
-import sun.misc.DoubleConsts;
+import jdk.internal.math.FloatingDecimal;
+import jdk.internal.math.DoubleConsts;
 import jdk.internal.HotSpotIntrinsicCandidate;
 
 /**
--- a/jdk/src/java.base/share/classes/java/lang/Float.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/Float.java	Wed Jul 05 21:10:50 2017 +0200
@@ -25,9 +25,9 @@
 
 package java.lang;
 
-import sun.misc.FloatingDecimal;
-import sun.misc.FloatConsts;
-import sun.misc.DoubleConsts;
+import jdk.internal.math.FloatingDecimal;
+import jdk.internal.math.FloatConsts;
+import jdk.internal.math.DoubleConsts;
 import jdk.internal.HotSpotIntrinsicCandidate;
 
 /**
--- a/jdk/src/java.base/share/classes/java/lang/Math.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/Math.java	Wed Jul 05 21:10:50 2017 +0200
@@ -26,8 +26,8 @@
 package java.lang;
 
 import java.util.Random;
-import sun.misc.FloatConsts;
-import sun.misc.DoubleConsts;
+import jdk.internal.math.FloatConsts;
+import jdk.internal.math.DoubleConsts;
 import jdk.internal.HotSpotIntrinsicCandidate;
 
 /**
--- a/jdk/src/java.base/share/classes/java/lang/StrictMath.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/StrictMath.java	Wed Jul 05 21:10:50 2017 +0200
@@ -26,7 +26,7 @@
 package java.lang;
 
 import java.util.Random;
-import sun.misc.DoubleConsts;
+import jdk.internal.math.DoubleConsts;
 import jdk.internal.HotSpotIntrinsicCandidate;
 
 /**
--- a/jdk/src/java.base/share/classes/java/lang/System.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/System.java	Wed Jul 05 21:10:50 2017 +0200
@@ -132,7 +132,7 @@
 
     /* The security manager for the system.
      */
-    private static volatile SecurityManager security = null;
+    private static volatile SecurityManager security;
 
     /**
      * Reassigns the "standard" input stream.
@@ -206,7 +206,7 @@
         setErr0(err);
     }
 
-    private static volatile Console cons = null;
+    private static volatile Console cons;
     /**
      * Returns the unique {@link java.io.Console Console} object associated
      * with the current Java virtual machine, if any.
@@ -216,12 +216,13 @@
      * @since   1.6
      */
      public static Console console() {
-         if (cons == null) {
+         Console c = cons;
+         if (c == null) {
              synchronized (System.class) {
-                 cons = SharedSecrets.getJavaIOAccess().console();
+                 cons = c = SharedSecrets.getJavaIOAccess().console();
              }
          }
-         return cons;
+         return c;
      }
 
     /**
--- a/jdk/src/java.base/share/classes/java/lang/Thread.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/Thread.java	Wed Jul 05 21:10:50 2017 +0200
@@ -207,12 +207,10 @@
     /* For generating thread ID */
     private static long threadSeqNumber;
 
-    /* Java thread status for tools,
-     * initialized to indicate thread 'not yet started'
+    /*
+     * Java thread status for tools, default indicates thread 'not yet started'
      */
-
-    private volatile int threadStatus = 0;
-
+    private volatile int threadStatus;
 
     private static synchronized long nextThreadID() {
         return ++threadSeqNumber;
--- a/jdk/src/java.base/share/classes/java/lang/ref/ReferenceQueue.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/ref/ReferenceQueue.java	Wed Jul 05 21:10:50 2017 +0200
@@ -53,7 +53,7 @@
 
     private static class Lock { };
     private Lock lock = new Lock();
-    private volatile Reference<? extends T> head = null;
+    private volatile Reference<? extends T> head;
     private long queueLength = 0;
 
     boolean enqueue(Reference<? extends T> r) { /* Called only by Reference class */
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Parameter.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/Parameter.java	Wed Jul 05 21:10:50 2017 +0200
@@ -205,7 +205,7 @@
         return tmp;
     }
 
-    private transient volatile Type parameterTypeCache = null;
+    private transient volatile Type parameterTypeCache;
 
     /**
      * Returns a {@code Class} object that identifies the
@@ -237,7 +237,7 @@
         return executable.getAnnotatedParameterTypes()[index];
     }
 
-    private transient volatile Class<?> parameterClassCache = null;
+    private transient volatile Class<?> parameterClassCache;
 
     /**
      * Returns {@code true} if this parameter is implicitly declared
--- a/jdk/src/java.base/share/classes/java/math/BigInteger.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/math/BigInteger.java	Wed Jul 05 21:10:50 2017 +0200
@@ -38,8 +38,8 @@
 import java.util.Random;
 import java.util.concurrent.ThreadLocalRandom;
 
-import sun.misc.DoubleConsts;
-import sun.misc.FloatConsts;
+import jdk.internal.math.DoubleConsts;
+import jdk.internal.math.FloatConsts;
 import jdk.internal.HotSpotIntrinsicCandidate;
 
 /**
--- a/jdk/src/java.base/share/classes/java/net/URI.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/net/URI.java	Wed Jul 05 21:10:50 2017 +0200
@@ -33,7 +33,6 @@
 import java.nio.ByteBuffer;
 import java.nio.CharBuffer;
 import java.nio.charset.CharsetDecoder;
-import java.nio.charset.CharsetEncoder;
 import java.nio.charset.CoderResult;
 import java.nio.charset.CodingErrorAction;
 import java.nio.charset.CharacterCodingException;
@@ -490,17 +489,17 @@
     private transient String path;              // null ==> opaque
     private transient String query;
 
-    // The remaining fields may be computed on demand
-
-    private transient volatile String schemeSpecificPart;
-    private transient volatile int hash;        // Zero ==> undefined
-
-    private transient volatile String decodedUserInfo = null;
-    private transient volatile String decodedAuthority = null;
-    private transient volatile String decodedPath = null;
-    private transient volatile String decodedQuery = null;
-    private transient volatile String decodedFragment = null;
-    private transient volatile String decodedSchemeSpecificPart = null;
+    // The remaining fields may be computed on demand, which is safe even in
+    // the face of multiple threads racing to initialize them
+    private transient String schemeSpecificPart;
+    private transient int hash;        // Zero ==> undefined
+
+    private transient String decodedUserInfo;
+    private transient String decodedAuthority;
+    private transient String decodedPath;
+    private transient String decodedQuery;
+    private transient String decodedFragment;
+    private transient String decodedSchemeSpecificPart;
 
     /**
      * The string form of this URI.
@@ -911,8 +910,7 @@
         // either more fields or a more-obscure representation.
         if ((host != null) || (authority == null))
             return this;
-        defineString();
-        new Parser(string).parse(true);
+        new Parser(toString()).parse(true);
         return this;
     }
 
@@ -1144,8 +1142,17 @@
      *          (never {@code null})
      */
     public String getRawSchemeSpecificPart() {
-        defineSchemeSpecificPart();
-        return schemeSpecificPart;
+        String part = schemeSpecificPart;
+        if (part != null) {
+            return part;
+        }
+        StringBuilder sb = new StringBuilder();
+        appendSchemeSpecificPart(sb, null, getAuthority(), getUserInfo(),
+                                 host, port, getPath(), getQuery());
+        if (sb.length() == 0) {
+            return null;
+        }
+        return schemeSpecificPart = sb.toString();
     }
 
     /**
@@ -1160,9 +1167,11 @@
      *          (never {@code null})
      */
     public String getSchemeSpecificPart() {
-        if (decodedSchemeSpecificPart == null)
-            decodedSchemeSpecificPart = decode(getRawSchemeSpecificPart());
-        return decodedSchemeSpecificPart;
+        String part = decodedSchemeSpecificPart;
+        if (part == null) {
+            decodedSchemeSpecificPart = part = decode(getRawSchemeSpecificPart());
+        }
+        return part;
     }
 
     /**
@@ -1193,9 +1202,11 @@
      *          or {@code null} if the authority is undefined
      */
     public String getAuthority() {
-        if (decodedAuthority == null)
-            decodedAuthority = decode(authority);
-        return decodedAuthority;
+        String auth = decodedAuthority;
+        if ((auth == null) && (authority != null)) {
+            decodedAuthority = auth = decode(authority);
+        }
+        return auth;
     }
 
     /**
@@ -1223,9 +1234,11 @@
      *          or {@code null} if the user information is undefined
      */
     public String getUserInfo() {
-        if ((decodedUserInfo == null) && (userInfo != null))
-            decodedUserInfo = decode(userInfo);
-        return decodedUserInfo;
+        String user = decodedUserInfo;
+        if ((user == null) && (userInfo != null)) {
+            decodedUserInfo = user = decode(userInfo);
+        }
+        return user;
     }
 
     /**
@@ -1307,9 +1320,11 @@
      *          or {@code null} if the path is undefined
      */
     public String getPath() {
-        if ((decodedPath == null) && (path != null))
-            decodedPath = decode(path);
-        return decodedPath;
+        String decoded = decodedPath;
+        if ((decoded == null) && (path != null)) {
+            decodedPath = decoded = decode(path);
+        }
+        return decoded;
     }
 
     /**
@@ -1336,9 +1351,11 @@
      *          or {@code null} if the query is undefined
      */
     public String getQuery() {
-        if ((decodedQuery == null) && (query != null))
-            decodedQuery = decode(query, false);
-        return decodedQuery;
+        String decoded = decodedQuery;
+        if ((decoded == null) && (query != null)) {
+            decodedQuery = decoded = decode(query, false);
+        }
+        return decoded;
     }
 
     /**
@@ -1365,9 +1382,11 @@
      *          or {@code null} if the fragment is undefined
      */
     public String getFragment() {
-        if ((decodedFragment == null) && (fragment != null))
-            decodedFragment = decode(fragment, false);
-        return decodedFragment;
+        String decoded = decodedFragment;
+        if ((decoded == null) && (fragment != null)) {
+            decodedFragment = decoded = decode(fragment, false);
+        }
+        return decoded;
     }
 
 
@@ -1453,24 +1472,27 @@
      * @return  A hash-code value for this URI
      */
     public int hashCode() {
-        if (hash != 0)
-            return hash;
-        int h = hashIgnoringCase(0, scheme);
-        h = hash(h, fragment);
-        if (isOpaque()) {
-            h = hash(h, schemeSpecificPart);
-        } else {
-            h = hash(h, path);
-            h = hash(h, query);
-            if (host != null) {
-                h = hash(h, userInfo);
-                h = hashIgnoringCase(h, host);
-                h += 1949 * port;
+        int h = hash;
+        if (h == 0) {
+            h = hashIgnoringCase(0, scheme);
+            h = hash(h, fragment);
+            if (isOpaque()) {
+                h = hash(h, schemeSpecificPart);
             } else {
-                h = hash(h, authority);
+                h = hash(h, path);
+                h = hash(h, query);
+                if (host != null) {
+                    h = hash(h, userInfo);
+                    h = hashIgnoringCase(h, host);
+                    h += 1949 * port;
+                } else {
+                    h = hash(h, authority);
+                }
+            }
+            if (h != 0) {
+                hash = h;
             }
         }
-        hash = h;
         return h;
     }
 
@@ -1600,8 +1622,59 @@
      * @return  The string form of this URI
      */
     public String toString() {
-        defineString();
-        return string;
+        String s = string;
+        if (s == null) {
+            s = defineString();
+        }
+        return s;
+    }
+
+    private String defineString() {
+        String s = string;
+        if (s != null) {
+            return s;
+        }
+
+        StringBuilder sb = new StringBuilder();
+        if (scheme != null) {
+            sb.append(scheme);
+            sb.append(':');
+        }
+        if (isOpaque()) {
+            sb.append(schemeSpecificPart);
+        } else {
+            if (host != null) {
+                sb.append("//");
+                if (userInfo != null) {
+                    sb.append(userInfo);
+                    sb.append('@');
+                }
+                boolean needBrackets = ((host.indexOf(':') >= 0)
+                        && !host.startsWith("[")
+                        && !host.endsWith("]"));
+                if (needBrackets) sb.append('[');
+                sb.append(host);
+                if (needBrackets) sb.append(']');
+                if (port != -1) {
+                    sb.append(':');
+                    sb.append(port);
+                }
+            } else if (authority != null) {
+                sb.append("//");
+                sb.append(authority);
+            }
+            if (path != null)
+                sb.append(path);
+            if (query != null) {
+                sb.append('?');
+                sb.append(query);
+            }
+        }
+        if (fragment != null) {
+            sb.append('#');
+            sb.append(fragment);
+        }
+        return string = sb.toString();
     }
 
     /**
@@ -1618,8 +1691,7 @@
      *          charset
      */
     public String toASCIIString() {
-        defineString();
-        return encode(string);
+        return encode(toString());
     }
 
 
@@ -1825,7 +1897,7 @@
         }
     }
 
-    private void appendAuthority(StringBuffer sb,
+    private void appendAuthority(StringBuilder sb,
                                  String authority,
                                  String userInfo,
                                  String host,
@@ -1875,7 +1947,7 @@
         }
     }
 
-    private void appendSchemeSpecificPart(StringBuffer sb,
+    private void appendSchemeSpecificPart(StringBuilder sb,
                                           String opaquePart,
                                           String authority,
                                           String userInfo,
@@ -1916,7 +1988,7 @@
         }
     }
 
-    private void appendFragment(StringBuffer sb, String fragment) {
+    private void appendFragment(StringBuilder sb, String fragment) {
         if (fragment != null) {
             sb.append('#');
             sb.append(quote(fragment, L_URIC, H_URIC));
@@ -1933,7 +2005,7 @@
                             String query,
                             String fragment)
     {
-        StringBuffer sb = new StringBuffer();
+        StringBuilder sb = new StringBuilder();
         if (scheme != null) {
             sb.append(scheme);
             sb.append(':');
@@ -1945,61 +2017,6 @@
         return sb.toString();
     }
 
-    private void defineSchemeSpecificPart() {
-        if (schemeSpecificPart != null) return;
-        StringBuffer sb = new StringBuffer();
-        appendSchemeSpecificPart(sb, null, getAuthority(), getUserInfo(),
-                                 host, port, getPath(), getQuery());
-        if (sb.length() == 0) return;
-        schemeSpecificPart = sb.toString();
-    }
-
-    private void defineString() {
-        if (string != null) return;
-
-        StringBuilder sb = new StringBuilder();
-        if (scheme != null) {
-            sb.append(scheme);
-            sb.append(':');
-        }
-        if (isOpaque()) {
-            sb.append(schemeSpecificPart);
-        } else {
-            if (host != null) {
-                sb.append("//");
-                if (userInfo != null) {
-                    sb.append(userInfo);
-                    sb.append('@');
-                }
-                boolean needBrackets = ((host.indexOf(':') >= 0)
-                                    && !host.startsWith("[")
-                                    && !host.endsWith("]"));
-                if (needBrackets) sb.append('[');
-                sb.append(host);
-                if (needBrackets) sb.append(']');
-                if (port != -1) {
-                    sb.append(':');
-                    sb.append(port);
-                }
-            } else if (authority != null) {
-                sb.append("//");
-                sb.append(authority);
-            }
-            if (path != null)
-                sb.append(path);
-            if (query != null) {
-                sb.append('?');
-                sb.append(query);
-            }
-        }
-        if (fragment != null) {
-            sb.append('#');
-            sb.append(fragment);
-        }
-        string = sb.toString();
-    }
-
-
     // -- Normalization, resolution, and relativization --
 
     // RFC2396 5.2 (6)
@@ -2650,13 +2667,13 @@
         '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
     };
 
-    private static void appendEscape(StringBuffer sb, byte b) {
+    private static void appendEscape(StringBuilder sb, byte b) {
         sb.append('%');
         sb.append(hexDigits[(b >> 4) & 0x0f]);
         sb.append(hexDigits[(b >> 0) & 0x0f]);
     }
 
-    private static void appendEncoded(StringBuffer sb, char c) {
+    private static void appendEncoded(StringBuilder sb, char c) {
         ByteBuffer bb = null;
         try {
             bb = ThreadLocalCoders.encoderFor("UTF-8")
@@ -2677,15 +2694,14 @@
     // by the given mask pair
     //
     private static String quote(String s, long lowMask, long highMask) {
-        int n = s.length();
-        StringBuffer sb = null;
+        StringBuilder sb = null;
         boolean allowNonASCII = ((lowMask & L_ESCAPED) != 0);
         for (int i = 0; i < s.length(); i++) {
             char c = s.charAt(i);
             if (c < '\u0080') {
                 if (!match(c, lowMask, highMask)) {
                     if (sb == null) {
-                        sb = new StringBuffer();
+                        sb = new StringBuilder();
                         sb.append(s, 0, i);
                     }
                     appendEscape(sb, (byte)c);
@@ -2697,7 +2713,7 @@
                        && (Character.isSpaceChar(c)
                            || Character.isISOControl(c))) {
                 if (sb == null) {
-                    sb = new StringBuffer();
+                    sb = new StringBuilder();
                     sb.append(s, 0, i);
                 }
                 appendEncoded(sb, c);
@@ -2734,7 +2750,7 @@
             assert false;
         }
 
-        StringBuffer sb = new StringBuffer();
+        StringBuilder sb = new StringBuilder();
         while (bb.hasRemaining()) {
             int b = bb.get() & 0xff;
             if (b >= 0x80)
@@ -2865,12 +2881,6 @@
             fail("Expected " + expected, p);
         }
 
-        private void failExpecting(String expected, String prior, int p)
-            throws URISyntaxException
-        {
-            fail("Expected " + expected + " following " + prior, p);
-        }
-
 
         // -- Simple access to the input string --
 
--- a/jdk/src/java.base/share/classes/java/net/URL.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/net/URL.java	Wed Jul 05 21:10:50 2017 +0200
@@ -310,7 +310,8 @@
      * @param      host       the name of the host.
      * @param      port       the port number on the host.
      * @param      file       the file on the host
-     * @exception  MalformedURLException  if an unknown protocol is specified.
+     * @exception  MalformedURLException  if an unknown protocol or the port
+     *                  is a negative number other than -1
      * @see        java.lang.System#getProperty(java.lang.String)
      * @see        java.net.URL#setURLStreamHandlerFactory(
      *                  java.net.URLStreamHandlerFactory)
@@ -329,9 +330,9 @@
      * name, {@code host} name, and {@code file} name. The
      * default port for the specified protocol is used.
      * <p>
-     * This method is equivalent to calling the four-argument
-     * constructor with the arguments being {@code protocol},
-     * {@code host}, {@code -1}, and {@code file}.
+     * This constructor is equivalent to the four-argument
+     * constructor with the only difference of using the
+     * default port for the specified protocol.
      *
      * No validation of the inputs is performed by this constructor.
      *
@@ -372,7 +373,8 @@
      * @param      port       the port number on the host.
      * @param      file       the file on the host
      * @param      handler    the stream handler for the URL.
-     * @exception  MalformedURLException  if an unknown protocol is specified.
+     * @exception  MalformedURLException  if an unknown protocol or the port
+                        is a negative number other than -1
      * @exception  SecurityException
      *        if a security manager exists and its
      *        {@code checkPermission} method doesn't allow
@@ -446,7 +448,9 @@
      *
      * @param      spec   the {@code String} to parse as a URL.
      * @exception  MalformedURLException  if no protocol is specified, or an
-     *               unknown protocol is found, or {@code spec} is {@code null}.
+     *               unknown protocol is found, or {@code spec} is {@code null},
+     *               or the parsed URL fails to comply with the specific syntax
+     *               of the associated protocol.
      * @see        java.net.URL#URL(java.net.URL, java.lang.String)
      */
     public URL(String spec) throws MalformedURLException {
@@ -493,7 +497,9 @@
      * @param      context   the context in which to parse the specification.
      * @param      spec      the {@code String} to parse as a URL.
      * @exception  MalformedURLException  if no protocol is specified, or an
-     *               unknown protocol is found, or {@code spec} is {@code null}.
+     *               unknown protocol is found, or {@code spec} is {@code null},
+     *               or the parsed URL fails to comply with the specific syntax
+     *               of the associated protocol.
      * @see        java.net.URL#URL(java.lang.String, java.lang.String,
      *                  int, java.lang.String)
      * @see        java.net.URLStreamHandler
@@ -513,7 +519,9 @@
      * @param      spec      the {@code String} to parse as a URL.
      * @param      handler   the stream handler for the URL.
      * @exception  MalformedURLException  if no protocol is specified, or an
-     *               unknown protocol is found, or {@code spec} is {@code null}.
+     *               unknown protocol is found, or {@code spec} is {@code null},
+     *               or the parsed URL fails to comply with the specific syntax
+     *               of the associated protocol.
      * @exception  SecurityException
      *        if a security manager exists and its
      *        {@code checkPermission} method doesn't allow
--- a/jdk/src/java.base/share/classes/java/net/URLConnection.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/net/URLConnection.java	Wed Jul 05 21:10:50 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -1550,7 +1550,7 @@
         }
 
         if (c1 == 0xFF && c2 == 0xD8 && c3 == 0xFF) {
-            if (c4 == 0xE0) {
+            if (c4 == 0xE0 || c4 == 0xEE) {
                 return "image/jpeg";
             }
 
@@ -1565,10 +1565,6 @@
                  c11 == 0)) {
                 return "image/jpeg";
             }
-
-            if (c4 == 0xEE) {
-                return "image/jpg";
-            }
         }
 
         if (c1 == 0xD0 && c2 == 0xCF && c3 == 0x11 && c4 == 0xE0 &&
--- a/jdk/src/java.base/share/classes/java/nio/Bits.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/nio/Bits.java	Wed Jul 05 21:10:50 2017 +0200
@@ -25,9 +25,7 @@
 
 package java.nio;
 
-import java.security.AccessController;
 import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.atomic.LongAdder;
 
 import jdk.internal.misc.JavaNioAccess;
 import jdk.internal.misc.JavaLangRefAccess;
@@ -603,7 +601,8 @@
     private static final AtomicLong reservedMemory = new AtomicLong();
     private static final AtomicLong totalCapacity = new AtomicLong();
     private static final AtomicLong count = new AtomicLong();
-    private static volatile boolean memoryLimitSet = false;
+    private static volatile boolean memoryLimitSet;
+
     // max. number of sleeps during try-reserving with exponentially
     // increasing delay before throwing OutOfMemoryError:
     // 1, 2, 4, 8, 16, 32, 64, 128, 256 (total 511 ms ~ 0.5 s)
--- a/jdk/src/java.base/share/classes/java/nio/channels/SelectionKey.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/nio/channels/SelectionKey.java	Wed Jul 05 21:10:50 2017 +0200
@@ -26,8 +26,6 @@
 package java.nio.channels;
 
 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
-import java.io.IOException;
-
 
 /**
  * A token representing the registration of a {@link SelectableChannel} with a
@@ -363,7 +361,7 @@
 
     // -- Attachments --
 
-    private volatile Object attachment = null;
+    private volatile Object attachment;
 
     private static final AtomicReferenceFieldUpdater<SelectionKey,Object>
         attachmentUpdater = AtomicReferenceFieldUpdater.newUpdater(
--- a/jdk/src/java.base/share/classes/java/nio/channels/spi/AbstractInterruptibleChannel.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/nio/channels/spi/AbstractInterruptibleChannel.java	Wed Jul 05 21:10:50 2017 +0200
@@ -29,11 +29,7 @@
 package java.nio.channels.spi;
 
 import java.io.IOException;
-import java.lang.reflect.Method;
-import java.lang.reflect.InvocationTargetException;
 import java.nio.channels.*;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
 import jdk.internal.misc.SharedSecrets;
 import sun.nio.ch.Interruptible;
 
@@ -90,7 +86,7 @@
 {
 
     private final Object closeLock = new Object();
-    private volatile boolean open = true;
+    private volatile boolean closed;
 
     /**
      * Initializes a new instance of this class.
@@ -110,9 +106,9 @@
      */
     public final void close() throws IOException {
         synchronized (closeLock) {
-            if (!open)
+            if (closed)
                 return;
-            open = false;
+            closed = true;
             implCloseChannel();
         }
     }
@@ -136,7 +132,7 @@
     protected abstract void implCloseChannel() throws IOException;
 
     public final boolean isOpen() {
-        return open;
+        return !closed;
     }
 
 
@@ -158,9 +154,9 @@
             interruptor = new Interruptible() {
                     public void interrupt(Thread target) {
                         synchronized (closeLock) {
-                            if (!open)
+                            if (closed)
                                 return;
-                            open = false;
+                            closed = true;
                             interrupted = target;
                             try {
                                 AbstractInterruptibleChannel.this.implCloseChannel();
@@ -202,7 +198,7 @@
             this.interrupted = null;
             throw new ClosedByInterruptException();
         }
-        if (!completed && !open)
+        if (!completed && closed)
             throw new AsynchronousCloseException();
     }
 
--- a/jdk/src/java.base/share/classes/java/nio/charset/Charset.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/nio/charset/Charset.java	Wed Jul 05 21:10:50 2017 +0200
@@ -276,7 +276,7 @@
 
     /* -- Static methods -- */
 
-    private static volatile String bugLevel = null;
+    private static volatile String bugLevel;
 
     static boolean atBugLevel(String bl) {              // package-private
         String level = bugLevel;
@@ -324,8 +324,8 @@
     // Cache of the most-recently-returned charsets,
     // along with the names that were used to find them
     //
-    private static volatile Object[] cache1 = null; // "Level 1" cache
-    private static volatile Object[] cache2 = null; // "Level 2" cache
+    private static volatile Object[] cache1; // "Level 1" cache
+    private static volatile Object[] cache2; // "Level 2" cache
 
     private static void cache(String charsetName, Charset cs) {
         cache2 = cache1;
--- a/jdk/src/java.base/share/classes/java/security/SecureRandom.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/security/SecureRandom.java	Wed Jul 05 21:10:50 2017 +0200
@@ -124,7 +124,7 @@
     private String algorithm;
 
     // Seed Generator
-    private static volatile SecureRandom seedGenerator = null;
+    private static volatile SecureRandom seedGenerator;
 
     /**
      * Constructs a secure random number generator (RNG) implementing the
@@ -522,10 +522,12 @@
      * @see #setSeed
      */
     public static byte[] getSeed(int numBytes) {
-        if (seedGenerator == null) {
-            seedGenerator = new SecureRandom();
+        SecureRandom seedGen = seedGenerator;
+        if (seedGen == null) {
+            seedGen = new SecureRandom();
+            seedGenerator = seedGen;
         }
-        return seedGenerator.generateSeed(numBytes);
+        return seedGen.generateSeed(numBytes);
     }
 
     /**
--- a/jdk/src/java.base/share/classes/java/text/DateFormatSymbols.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/text/DateFormatSymbols.java	Wed Jul 05 21:10:50 2017 +0200
@@ -630,7 +630,9 @@
             hashCode = 11 * hashCode + Arrays.hashCode(ampms);
             hashCode = 11 * hashCode + Arrays.deepHashCode(getZoneStringsWrapper());
             hashCode = 11 * hashCode + Objects.hashCode(localPatternChars);
-            cachedHashCode = hashCode;
+            if (hashCode != 0) {
+                cachedHashCode = hashCode;
+            }
         }
 
         return hashCode;
@@ -670,12 +672,12 @@
     private static final ConcurrentMap<Locale, SoftReference<DateFormatSymbols>> cachedInstances
         = new ConcurrentHashMap<>(3);
 
-    private transient int lastZoneIndex = 0;
+    private transient int lastZoneIndex;
 
     /**
      * Cached hash code
      */
-    transient volatile int cachedHashCode = 0;
+    transient volatile int cachedHashCode;
 
     private void initializeData(Locale desiredLocale) {
         locale = desiredLocale;
--- a/jdk/src/java.base/share/classes/java/text/DecimalFormatSymbols.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/text/DecimalFormatSymbols.java	Wed Jul 05 21:10:50 2017 +0200
@@ -42,14 +42,8 @@
 import java.io.ObjectInputStream;
 import java.io.Serializable;
 import java.text.spi.DecimalFormatSymbolsProvider;
-import java.util.ArrayList;
 import java.util.Currency;
-import java.util.List;
 import java.util.Locale;
-import java.util.MissingResourceException;
-import java.util.ResourceBundle;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
 import sun.util.locale.provider.LocaleProviderAdapter;
 import sun.util.locale.provider.LocaleServiceProviderPool;
 import sun.util.locale.provider.ResourceBundleBasedAdapter;
@@ -875,7 +869,7 @@
 
     // currency; only the ISO code is serialized.
     private transient Currency currency;
-    private transient volatile boolean currencyInitialized = false;
+    private transient volatile boolean currencyInitialized;
 
     // Proclaim JDK 1.1 FCS compatibility
     static final long serialVersionUID = 5772796243397350300L;
--- a/jdk/src/java.base/share/classes/java/text/DigitList.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/text/DigitList.java	Wed Jul 05 21:10:50 2017 +0200
@@ -41,7 +41,7 @@
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.math.RoundingMode;
-import sun.misc.FloatingDecimal;
+import jdk.internal.math.FloatingDecimal;
 
 /**
  * Digit List. Private to DecimalFormat.
--- a/jdk/src/java.base/share/classes/java/time/LocalDate.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/time/LocalDate.java	Wed Jul 05 21:10:50 2017 +0200
@@ -147,6 +147,10 @@
      * This could be used by an application as a "far future" date.
      */
     public static final LocalDate MAX = LocalDate.of(Year.MAX_VALUE, 12, 31);
+    /**
+     * The epoch year {@code LocalDate}, '1970-01-01'.
+     */
+    public static final LocalDate EPOCH = LocalDate.of(1970, 1, 1);
 
     /**
      * Serialization version.
@@ -1864,6 +1868,29 @@
         return total - DAYS_0000_TO_1970;
     }
 
+    /**
+     * Converts this {@code LocalDate} to the number of seconds since the epoch
+     * of 1970-01-01T00:00:00Z.
+     * <p>
+     * This combines this local date with the specified time and
+     * offset to calculate the epoch-second value, which is the
+     * number of elapsed seconds from 1970-01-01T00:00:00Z.
+     * Instants on the time-line after the epoch are positive, earlier
+     * are negative.
+     *
+     * @param time the local time, not null
+     * @param offset the zone offset, not null
+     * @return the number of seconds since the epoch of 1970-01-01T00:00:00Z, may be negative
+     * @since 9
+     */
+    public long toEpochSecond(LocalTime time, ZoneOffset offset) {
+        Objects.requireNonNull(time, "time");
+        Objects.requireNonNull(offset, "offset");
+        long secs = toEpochDay() * SECONDS_PER_DAY + time.toSecondOfDay();
+        secs -= offset.getTotalSeconds();
+        return secs;
+    }
+
     //-----------------------------------------------------------------------
     /**
      * Compares this date to another date.
--- a/jdk/src/java.base/share/classes/java/time/LocalTime.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/time/LocalTime.java	Wed Jul 05 21:10:50 2017 +0200
@@ -1490,6 +1490,30 @@
         return total;
     }
 
+    /**
+     * Converts this {@code LocalTime} to the number of seconds since the epoch
+     * of 1970-01-01T00:00:00Z.
+     * <p>
+     * This combines this local time with the specified date and
+     * offset to calculate the epoch-second value, which is the
+     * number of elapsed seconds from 1970-01-01T00:00:00Z.
+     * Instants on the time-line after the epoch are positive, earlier
+     * are negative.
+     *
+     * @param date the local date, not null
+     * @param offset the zone offset, not null
+     * @return the number of seconds since the epoch of 1970-01-01T00:00:00Z, may be negative
+     * @since 9
+     */
+    public long toEpochSecond(LocalDate date, ZoneOffset offset) {
+        Objects.requireNonNull(date, "date");
+        Objects.requireNonNull(offset, "offset");
+        long epochDay = date.toEpochDay();
+        long secs = epochDay * 86400 + toSecondOfDay();
+        secs -= offset.getTotalSeconds();
+        return secs;
+    }
+
     //-----------------------------------------------------------------------
     /**
      * Compares this time to another time.
--- a/jdk/src/java.base/share/classes/java/time/OffsetTime.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/time/OffsetTime.java	Wed Jul 05 21:10:50 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -1232,6 +1232,28 @@
         return nod - offsetNanos;
     }
 
+    /**
+     * Converts this {@code OffsetTime} to the number of seconds since the epoch
+     * of 1970-01-01T00:00:00Z.
+     * <p>
+     * This combines this offset time with the specified date to calculate the
+     * epoch-second value, which is the number of elapsed seconds from
+     * 1970-01-01T00:00:00Z.
+     * Instants on the time-line after the epoch are positive, earlier
+     * are negative.
+     *
+     * @param date the localdate, not null
+     * @return the number of seconds since the epoch of 1970-01-01T00:00:00Z, may be negative
+     * @since 9
+     */
+    public long toEpochSecond(LocalDate date) {
+        Objects.requireNonNull(date, "date");
+        long epochDay = date.toEpochDay();
+        long secs = epochDay * 86400 + time.toSecondOfDay();
+        secs -= offset.getTotalSeconds();
+        return secs;
+    }
+
     //-----------------------------------------------------------------------
     /**
      * Compares this {@code OffsetTime} to another time.
--- a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatter.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatter.java	Wed Jul 05 21:10:50 2017 +0200
@@ -80,6 +80,7 @@
 import java.time.Period;
 import java.time.ZoneId;
 import java.time.ZoneOffset;
+import java.time.chrono.ChronoLocalDateTime;
 import java.time.chrono.Chronology;
 import java.time.chrono.IsoChronology;
 import java.time.format.DateTimeFormatterBuilder.CompositePrinterParser;
@@ -473,6 +474,17 @@
  * day-of-week was valid for the date.
  * <li>If an {@linkplain #parsedExcessDays() excess number of days}
  * was parsed then it is added to the date if a date is available.
+ * <li> If a second-based field is present, but {@code LocalTime} was not parsed,
+ * then the resolver ensures that milli, micro and nano second values are
+ * available to meet the contract of {@link ChronoField}.
+ * These will be set to zero if missing.
+ * <li>If both date and time were parsed and either an offset or zone is present,
+ * the field {@link ChronoField#INSTANT_SECONDS} is created.
+ * If an offset was parsed then the offset will be combined with the
+ * {@code LocalDateTime} to form the instant, with any zone ignored.
+ * If a {@code ZoneId} was parsed without an offset then the zone will be
+ * combined with the {@code LocalDateTime} to form the instant using the rules
+ * of {@link ChronoLocalDateTime#atZone(ZoneId)}.
  * </ol>
  *
  * @implSpec
--- a/jdk/src/java.base/share/classes/java/time/format/Parsed.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/time/format/Parsed.java	Wed Jul 05 21:10:50 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -594,15 +594,16 @@
 
     private void resolveInstant() {
         // add instant seconds if we have date, time and zone
+        // Offset (if present) will be given priority over the zone.
         if (date != null && time != null) {
-            if (zone != null) {
-                long instant = date.atTime(time).atZone(zone).getLong(ChronoField.INSTANT_SECONDS);
+            Long offsetSecs = fieldValues.get(OFFSET_SECONDS);
+            if (offsetSecs != null) {
+                ZoneOffset offset = ZoneOffset.ofTotalSeconds(offsetSecs.intValue());
+                long instant = date.atTime(time).atZone(offset).toEpochSecond();
                 fieldValues.put(INSTANT_SECONDS, instant);
             } else {
-                Long offsetSecs = fieldValues.get(OFFSET_SECONDS);
-                if (offsetSecs != null) {
-                    ZoneOffset offset = ZoneOffset.ofTotalSeconds(offsetSecs.intValue());
-                    long instant = date.atTime(time).atZone(offset).getLong(ChronoField.INSTANT_SECONDS);
+                if (zone != null) {
+                    long instant = date.atTime(time).atZone(zone).toEpochSecond();
                     fieldValues.put(INSTANT_SECONDS, instant);
                 }
             }
--- a/jdk/src/java.base/share/classes/java/util/Formatter.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/util/Formatter.java	Wed Jul 05 21:10:50 2017 +0200
@@ -60,8 +60,8 @@
 import java.time.temporal.TemporalQueries;
 import java.time.temporal.UnsupportedTemporalTypeException;
 
-import sun.misc.DoubleConsts;
-import sun.misc.FormattedFloatingDecimal;
+import jdk.internal.math.DoubleConsts;
+import jdk.internal.math.FormattedFloatingDecimal;
 
 /**
  * An interpreter for printf-style format strings.  This class provides support
--- a/jdk/src/java.base/share/classes/java/util/Locale.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/util/Locale.java	Wed Jul 05 21:10:50 2017 +0200
@@ -62,7 +62,6 @@
 import sun.util.locale.provider.LocaleProviderAdapter;
 import sun.util.locale.provider.LocaleResources;
 import sun.util.locale.provider.LocaleServiceProviderPool;
-import sun.util.locale.provider.ResourceBundleBasedAdapter;
 
 /**
  * A <code>Locale</code> object represents a specific geographical, political,
@@ -2016,11 +2015,11 @@
     /**
      * Calculated hashcode
      */
-    private transient volatile int hashCodeValue = 0;
+    private transient volatile int hashCodeValue;
 
     private static volatile Locale defaultLocale = initDefault();
-    private static volatile Locale defaultDisplayLocale = null;
-    private static volatile Locale defaultFormatLocale = null;
+    private static volatile Locale defaultDisplayLocale;
+    private static volatile Locale defaultFormatLocale;
 
     private transient volatile String languageTag;
 
@@ -2207,9 +2206,9 @@
                 baseLocale.getRegion(), baseLocale.getVariant(), localeExtensions);
     }
 
-    private static volatile String[] isoLanguages = null;
+    private static volatile String[] isoLanguages;
 
-    private static volatile String[] isoCountries = null;
+    private static volatile String[] isoCountries;
 
     private static String convertOldISOCodes(String language) {
         // we accept both the old and the new ISO codes for the languages whose ISO
@@ -2851,7 +2850,7 @@
         private final String range;
         private final double weight;
 
-        private volatile int hash = 0;
+        private volatile int hash;
 
         /**
          * Constructs a {@code LanguageRange} using the given {@code range}.
@@ -3108,14 +3107,17 @@
          */
         @Override
         public int hashCode() {
-            if (hash == 0) {
-                int result = 17;
-                result = 37*result + range.hashCode();
+            int h = hash;
+            if (h == 0) {
+                h = 17;
+                h = 37*h + range.hashCode();
                 long bitsWeight = Double.doubleToLongBits(weight);
-                result = 37*result + (int)(bitsWeight ^ (bitsWeight >>> 32));
-                hash = result;
+                h = 37*h + (int)(bitsWeight ^ (bitsWeight >>> 32));
+                if (h != 0) {
+                    hash = h;
+                }
             }
-            return hash;
+            return h;
         }
 
         /**
--- a/jdk/src/java.base/share/classes/java/util/regex/Pattern.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/util/regex/Pattern.java	Wed Jul 05 21:10:50 2017 +0200
@@ -950,7 +950,7 @@
      * Boolean indicating this Pattern is compiled; this is necessary in order
      * to lazily compile deserialized Patterns.
      */
-    private transient volatile boolean compiled = false;
+    private transient volatile boolean compiled;
 
     /**
      * The normalized pattern string.
@@ -1332,7 +1332,6 @@
         localCount = 0;
 
         // if length > 0, the Pattern is lazily compiled
-        compiled = false;
         if (pattern.length() == 0) {
             root = new Start(lastAccept);
             matchRoot = lastAccept;
@@ -1377,7 +1376,6 @@
      * equivalences of the characters.
      */
     private void normalize() {
-        boolean inCharClass = false;
         int lastCodePoint = -1;
 
         // Convert pattern into normalized form
@@ -1551,7 +1549,6 @@
         // offset maintains the index in code units.
 loop:   for(int x=0, offset=0; x<nCodePoints; x++, offset+=len) {
             len = countChars(input, offset, 1);
-            boolean skip = false;
             for(int y=x-1; y>=0; y--) {
                 if (combClass[y] == combClass[x]) {
                     continue loop;
@@ -1566,8 +1563,7 @@
                 temp[index++] = prefix + sre;
         }
         String[] result = new String[index];
-        for (int x=0; x<index; x++)
-            result[x] = temp[x];
+        System.arraycopy(temp, 0, result, 0, index);
         return result;
     }
 
@@ -1742,9 +1738,11 @@
     }
 
     Map<String, Integer> namedGroups() {
-        if (namedGroups == null)
-            namedGroups = new HashMap<>(2);
-        return namedGroups;
+        Map<String, Integer> groups = namedGroups;
+        if (groups == null) {
+            namedGroups = groups = new HashMap<>(2);
+        }
+        return groups;
     }
 
     /**
--- a/jdk/src/java.base/share/classes/java/util/zip/ZipFile.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/util/zip/ZipFile.java	Wed Jul 05 21:10:50 2017 +0200
@@ -72,7 +72,7 @@
 class ZipFile implements ZipConstants, Closeable {
 
     private final String name;     // zip file name
-    private volatile boolean closeRequested = false;
+    private volatile boolean closeRequested;
     private Source zsrc;
     private ZipCoder zc;
 
@@ -366,7 +366,7 @@
     }
 
     private class ZipFileInflaterInputStream extends InflaterInputStream {
-        private volatile boolean closeRequested = false;
+        private volatile boolean closeRequested;
         private boolean eof = false;
         private final ZipFileInputStream zfin;
 
@@ -653,7 +653,7 @@
      * (possibly compressed) zip file entry.
      */
    private class ZipFileInputStream extends InputStream {
-        private volatile boolean closeRequested = false;
+        private volatile boolean closeRequested;
         private   long pos;     // current position within entry data
         protected long rem;     // number of remaining bytes within entry
         protected long size;    // uncompressed size of this entry
--- a/jdk/src/java.base/share/classes/jdk/internal/logger/LazyLoggers.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/jdk/internal/logger/LazyLoggers.java	Wed Jul 05 21:10:50 2017 +0200
@@ -326,20 +326,22 @@
     }
 
     // Do not expose this outside of this package.
-    private static volatile LoggerFinder provider = null;
+    private static volatile LoggerFinder provider;
     private static LoggerFinder accessLoggerFinder() {
-        if (provider == null) {
+        LoggerFinder prov = provider;
+        if (prov == null) {
             // no need to lock: it doesn't matter if we call
             // getLoggerFinder() twice - since LoggerFinder already caches
             // the result.
             // This is just an optimization to avoid the cost of calling
             // doPrivileged every time.
             final SecurityManager sm = System.getSecurityManager();
-            provider = sm == null ? LoggerFinder.getLoggerFinder() :
+            prov = sm == null ? LoggerFinder.getLoggerFinder() :
                 AccessController.doPrivileged(
                         (PrivilegedAction<LoggerFinder>)LoggerFinder::getLoggerFinder);
+            provider = prov;
         }
-        return provider;
+        return prov;
     }
 
     // Avoid using lambda here as lazy loggers could be created early
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/math/DoubleConsts.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.math;
+
+/**
+ * This class contains additional constants documenting limits of the
+ * <code>double</code> type.
+ *
+ * @author Joseph D. Darcy
+ */
+
+public class DoubleConsts {
+    /**
+     * Don't let anyone instantiate this class.
+     */
+    private DoubleConsts() {}
+
+    public static final double POSITIVE_INFINITY = java.lang.Double.POSITIVE_INFINITY;
+    public static final double NEGATIVE_INFINITY = java.lang.Double.NEGATIVE_INFINITY;
+    public static final double NaN = java.lang.Double.NaN;
+    public static final double MAX_VALUE = java.lang.Double.MAX_VALUE;
+    public static final double MIN_VALUE = java.lang.Double.MIN_VALUE;
+
+    /**
+     * A constant holding the smallest positive normal value of type
+     * <code>double</code>, 2<sup>-1022</sup>.  It is equal to the
+     * value returned by
+     * <code>Double.longBitsToDouble(0x0010000000000000L)</code>.
+     *
+     * @since 1.5
+     */
+    public static final double  MIN_NORMAL      = 2.2250738585072014E-308;
+
+
+    /**
+     * The number of logical bits in the significand of a
+     * <code>double</code> number, including the implicit bit.
+     */
+    public static final int SIGNIFICAND_WIDTH   = 53;
+
+    /**
+     * Maximum exponent a finite <code>double</code> number may have.
+     * It is equal to the value returned by
+     * <code>Math.ilogb(Double.MAX_VALUE)</code>.
+     */
+    public static final int     MAX_EXPONENT    = 1023;
+
+    /**
+     * Minimum exponent a normalized <code>double</code> number may
+     * have.  It is equal to the value returned by
+     * <code>Math.ilogb(Double.MIN_NORMAL)</code>.
+     */
+    public static final int     MIN_EXPONENT    = -1022;
+
+    /**
+     * The exponent the smallest positive <code>double</code>
+     * subnormal value would have if it could be normalized..
+     */
+    public static final int     MIN_SUB_EXPONENT = MIN_EXPONENT -
+                                                   (SIGNIFICAND_WIDTH - 1);
+
+    /**
+     * Bias used in representing a <code>double</code> exponent.
+     */
+    public static final int     EXP_BIAS        = 1023;
+
+    /**
+     * Bit mask to isolate the sign bit of a <code>double</code>.
+     */
+    public static final long    SIGN_BIT_MASK   = 0x8000000000000000L;
+
+    /**
+     * Bit mask to isolate the exponent field of a
+     * <code>double</code>.
+     */
+    public static final long    EXP_BIT_MASK    = 0x7FF0000000000000L;
+
+    /**
+     * Bit mask to isolate the significand field of a
+     * <code>double</code>.
+     */
+    public static final long    SIGNIF_BIT_MASK = 0x000FFFFFFFFFFFFFL;
+
+    static {
+        // verify bit masks cover all bit positions and that the bit
+        // masks are non-overlapping
+        assert(((SIGN_BIT_MASK | EXP_BIT_MASK | SIGNIF_BIT_MASK) == ~0L) &&
+               (((SIGN_BIT_MASK & EXP_BIT_MASK) == 0L) &&
+                ((SIGN_BIT_MASK & SIGNIF_BIT_MASK) == 0L) &&
+                ((EXP_BIT_MASK & SIGNIF_BIT_MASK) == 0L)));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/math/FDBigInteger.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,1508 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.math;
+
+import java.math.BigInteger;
+import java.util.Arrays;
+//@ model import org.jmlspecs.models.JMLMath;
+
+/**
+ * A simple big integer package specifically for floating point base conversion.
+ */
+public /*@ spec_bigint_math @*/ class FDBigInteger {
+
+    //
+    // This class contains many comments that start with "/*@" mark.
+    // They are behavourial specification in
+    // the Java Modelling Language (JML):
+    // http://www.eecs.ucf.edu/~leavens/JML//index.shtml
+    //
+
+    /*@
+    @ public pure model static \bigint UNSIGNED(int v) {
+    @     return v >= 0 ? v : v + (((\bigint)1) << 32);
+    @ }
+    @
+    @ public pure model static \bigint UNSIGNED(long v) {
+    @     return v >= 0 ? v : v + (((\bigint)1) << 64);
+    @ }
+    @
+    @ public pure model static \bigint AP(int[] data, int len) {
+    @     return (\sum int i; 0 <= 0 && i < len; UNSIGNED(data[i]) << (i*32));
+    @ }
+    @
+    @ public pure model static \bigint pow52(int p5, int p2) {
+    @     ghost \bigint v = 1;
+    @     for (int i = 0; i < p5; i++) v *= 5;
+    @     return v << p2;
+    @ }
+    @
+    @ public pure model static \bigint pow10(int p10) {
+    @     return pow52(p10, p10);
+    @ }
+    @*/
+
+    static final int[] SMALL_5_POW = {
+            1,
+            5,
+            5 * 5,
+            5 * 5 * 5,
+            5 * 5 * 5 * 5,
+            5 * 5 * 5 * 5 * 5,
+            5 * 5 * 5 * 5 * 5 * 5,
+            5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5
+    };
+
+    static final long[] LONG_5_POW = {
+            1L,
+            5L,
+            5L * 5,
+            5L * 5 * 5,
+            5L * 5 * 5 * 5,
+            5L * 5 * 5 * 5 * 5,
+            5L * 5 * 5 * 5 * 5 * 5,
+            5L * 5 * 5 * 5 * 5 * 5 * 5,
+            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+    };
+
+    // Maximum size of cache of powers of 5 as FDBigIntegers.
+    private static final int MAX_FIVE_POW = 340;
+
+    // Cache of big powers of 5 as FDBigIntegers.
+    private static final FDBigInteger POW_5_CACHE[];
+
+    // Initialize FDBigInteger cache of powers of 5.
+    static {
+        POW_5_CACHE = new FDBigInteger[MAX_FIVE_POW];
+        int i = 0;
+        while (i < SMALL_5_POW.length) {
+            FDBigInteger pow5 = new FDBigInteger(new int[]{SMALL_5_POW[i]}, 0);
+            pow5.makeImmutable();
+            POW_5_CACHE[i] = pow5;
+            i++;
+        }
+        FDBigInteger prev = POW_5_CACHE[i - 1];
+        while (i < MAX_FIVE_POW) {
+            POW_5_CACHE[i] = prev = prev.mult(5);
+            prev.makeImmutable();
+            i++;
+        }
+    }
+
+    // Zero as an FDBigInteger.
+    public static final FDBigInteger ZERO = new FDBigInteger(new int[0], 0);
+
+    // Ensure ZERO is immutable.
+    static {
+        ZERO.makeImmutable();
+    }
+
+    // Constant for casting an int to a long via bitwise AND.
+    private static final long LONG_MASK = 0xffffffffL;
+
+    //@ spec_public non_null;
+    private int data[];  // value: data[0] is least significant
+    //@ spec_public;
+    private int offset;  // number of least significant zero padding ints
+    //@ spec_public;
+    private int nWords;  // data[nWords-1]!=0, all values above are zero
+                 // if nWords==0 -> this FDBigInteger is zero
+    //@ spec_public;
+    private boolean isImmutable = false;
+
+    /*@
+     @ public invariant 0 <= nWords && nWords <= data.length && offset >= 0;
+     @ public invariant nWords == 0 ==> offset == 0;
+     @ public invariant nWords > 0 ==> data[nWords - 1] != 0;
+     @ public invariant (\forall int i; nWords <= i && i < data.length; data[i] == 0);
+     @ public pure model \bigint value() {
+     @     return AP(data, nWords) << (offset*32);
+     @ }
+     @*/
+
+    /**
+     * Constructs an <code>FDBigInteger</code> from data and padding. The
+     * <code>data</code> parameter has the least significant <code>int</code> at
+     * the zeroth index. The <code>offset</code> parameter gives the number of
+     * zero <code>int</code>s to be inferred below the least significant element
+     * of <code>data</code>.
+     *
+     * @param data An array containing all non-zero <code>int</code>s of the value.
+     * @param offset An offset indicating the number of zero <code>int</code>s to pad
+     * below the least significant element of <code>data</code>.
+     */
+    /*@
+     @ requires data != null && offset >= 0;
+     @ ensures this.value() == \old(AP(data, data.length) << (offset*32));
+     @ ensures this.data == \old(data);
+     @*/
+    private FDBigInteger(int[] data, int offset) {
+        this.data = data;
+        this.offset = offset;
+        this.nWords = data.length;
+        trimLeadingZeros();
+    }
+
+    /**
+     * Constructs an <code>FDBigInteger</code> from a starting value and some
+     * decimal digits.
+     *
+     * @param lValue The starting value.
+     * @param digits The decimal digits.
+     * @param kDigits The initial index into <code>digits</code>.
+     * @param nDigits The final index into <code>digits</code>.
+     */
+    /*@
+     @ requires digits != null;
+     @ requires 0 <= kDigits && kDigits <= nDigits && nDigits <= digits.length;
+     @ requires (\forall int i; 0 <= i && i < nDigits; '0' <= digits[i] && digits[i] <= '9');
+     @ ensures this.value() == \old(lValue * pow10(nDigits - kDigits) + (\sum int i; kDigits <= i && i < nDigits; (digits[i] - '0') * pow10(nDigits - i - 1)));
+     @*/
+    public FDBigInteger(long lValue, char[] digits, int kDigits, int nDigits) {
+        int n = Math.max((nDigits + 8) / 9, 2);        // estimate size needed.
+        data = new int[n];      // allocate enough space
+        data[0] = (int) lValue;    // starting value
+        data[1] = (int) (lValue >>> 32);
+        offset = 0;
+        nWords = 2;
+        int i = kDigits;
+        int limit = nDigits - 5;       // slurp digits 5 at a time.
+        int v;
+        while (i < limit) {
+            int ilim = i + 5;
+            v = (int) digits[i++] - (int) '0';
+            while (i < ilim) {
+                v = 10 * v + (int) digits[i++] - (int) '0';
+            }
+            multAddMe(100000, v); // ... where 100000 is 10^5.
+        }
+        int factor = 1;
+        v = 0;
+        while (i < nDigits) {
+            v = 10 * v + (int) digits[i++] - (int) '0';
+            factor *= 10;
+        }
+        if (factor != 1) {
+            multAddMe(factor, v);
+        }
+        trimLeadingZeros();
+    }
+
+    /**
+     * Returns an <code>FDBigInteger</code> with the numerical value
+     * <code>5<sup>p5</sup> * 2<sup>p2</sup></code>.
+     *
+     * @param p5 The exponent of the power-of-five factor.
+     * @param p2 The exponent of the power-of-two factor.
+     * @return <code>5<sup>p5</sup> * 2<sup>p2</sup></code>
+     */
+    /*@
+     @ requires p5 >= 0 && p2 >= 0;
+     @ assignable \nothing;
+     @ ensures \result.value() == \old(pow52(p5, p2));
+     @*/
+    public static FDBigInteger valueOfPow52(int p5, int p2) {
+        if (p5 != 0) {
+            if (p2 == 0) {
+                return big5pow(p5);
+            } else if (p5 < SMALL_5_POW.length) {
+                int pow5 = SMALL_5_POW[p5];
+                int wordcount = p2 >> 5;
+                int bitcount = p2 & 0x1f;
+                if (bitcount == 0) {
+                    return new FDBigInteger(new int[]{pow5}, wordcount);
+                } else {
+                    return new FDBigInteger(new int[]{
+                            pow5 << bitcount,
+                            pow5 >>> (32 - bitcount)
+                    }, wordcount);
+                }
+            } else {
+                return big5pow(p5).leftShift(p2);
+            }
+        } else {
+            return valueOfPow2(p2);
+        }
+    }
+
+    /**
+     * Returns an <code>FDBigInteger</code> with the numerical value
+     * <code>value * 5<sup>p5</sup> * 2<sup>p2</sup></code>.
+     *
+     * @param value The constant factor.
+     * @param p5 The exponent of the power-of-five factor.
+     * @param p2 The exponent of the power-of-two factor.
+     * @return <code>value * 5<sup>p5</sup> * 2<sup>p2</sup></code>
+     */
+    /*@
+     @ requires p5 >= 0 && p2 >= 0;
+     @ assignable \nothing;
+     @ ensures \result.value() == \old(UNSIGNED(value) * pow52(p5, p2));
+     @*/
+    public static FDBigInteger valueOfMulPow52(long value, int p5, int p2) {
+        assert p5 >= 0 : p5;
+        assert p2 >= 0 : p2;
+        int v0 = (int) value;
+        int v1 = (int) (value >>> 32);
+        int wordcount = p2 >> 5;
+        int bitcount = p2 & 0x1f;
+        if (p5 != 0) {
+            if (p5 < SMALL_5_POW.length) {
+                long pow5 = SMALL_5_POW[p5] & LONG_MASK;
+                long carry = (v0 & LONG_MASK) * pow5;
+                v0 = (int) carry;
+                carry >>>= 32;
+                carry = (v1 & LONG_MASK) * pow5 + carry;
+                v1 = (int) carry;
+                int v2 = (int) (carry >>> 32);
+                if (bitcount == 0) {
+                    return new FDBigInteger(new int[]{v0, v1, v2}, wordcount);
+                } else {
+                    return new FDBigInteger(new int[]{
+                            v0 << bitcount,
+                            (v1 << bitcount) | (v0 >>> (32 - bitcount)),
+                            (v2 << bitcount) | (v1 >>> (32 - bitcount)),
+                            v2 >>> (32 - bitcount)
+                    }, wordcount);
+                }
+            } else {
+                FDBigInteger pow5 = big5pow(p5);
+                int[] r;
+                if (v1 == 0) {
+                    r = new int[pow5.nWords + 1 + ((p2 != 0) ? 1 : 0)];
+                    mult(pow5.data, pow5.nWords, v0, r);
+                } else {
+                    r = new int[pow5.nWords + 2 + ((p2 != 0) ? 1 : 0)];
+                    mult(pow5.data, pow5.nWords, v0, v1, r);
+                }
+                return (new FDBigInteger(r, pow5.offset)).leftShift(p2);
+            }
+        } else if (p2 != 0) {
+            if (bitcount == 0) {
+                return new FDBigInteger(new int[]{v0, v1}, wordcount);
+            } else {
+                return new FDBigInteger(new int[]{
+                         v0 << bitcount,
+                        (v1 << bitcount) | (v0 >>> (32 - bitcount)),
+                        v1 >>> (32 - bitcount)
+                }, wordcount);
+            }
+        }
+        return new FDBigInteger(new int[]{v0, v1}, 0);
+    }
+
+    /**
+     * Returns an <code>FDBigInteger</code> with the numerical value
+     * <code>2<sup>p2</sup></code>.
+     *
+     * @param p2 The exponent of 2.
+     * @return <code>2<sup>p2</sup></code>
+     */
+    /*@
+     @ requires p2 >= 0;
+     @ assignable \nothing;
+     @ ensures \result.value() == pow52(0, p2);
+     @*/
+    private static FDBigInteger valueOfPow2(int p2) {
+        int wordcount = p2 >> 5;
+        int bitcount = p2 & 0x1f;
+        return new FDBigInteger(new int[]{1 << bitcount}, wordcount);
+    }
+
+    /**
+     * Removes all leading zeros from this <code>FDBigInteger</code> adjusting
+     * the offset and number of non-zero leading words accordingly.
+     */
+    /*@
+     @ requires data != null;
+     @ requires 0 <= nWords && nWords <= data.length && offset >= 0;
+     @ requires nWords == 0 ==> offset == 0;
+     @ ensures nWords == 0 ==> offset == 0;
+     @ ensures nWords > 0 ==> data[nWords - 1] != 0;
+     @*/
+    private /*@ helper @*/ void trimLeadingZeros() {
+        int i = nWords;
+        if (i > 0 && (data[--i] == 0)) {
+            //for (; i > 0 && data[i - 1] == 0; i--) ;
+            while(i > 0 && data[i - 1] == 0) {
+                i--;
+            }
+            this.nWords = i;
+            if (i == 0) { // all words are zero
+                this.offset = 0;
+            }
+        }
+    }
+
+    /**
+     * Retrieves the normalization bias of the <code>FDBigIntger</code>. The
+     * normalization bias is a left shift such that after it the highest word
+     * of the value will have the 4 highest bits equal to zero:
+     * {@code (highestWord & 0xf0000000) == 0}, but the next bit should be 1
+     * {@code (highestWord & 0x08000000) != 0}.
+     *
+     * @return The normalization bias.
+     */
+    /*@
+     @ requires this.value() > 0;
+     @*/
+    public /*@ pure @*/ int getNormalizationBias() {
+        if (nWords == 0) {
+            throw new IllegalArgumentException("Zero value cannot be normalized");
+        }
+        int zeros = Integer.numberOfLeadingZeros(data[nWords - 1]);
+        return (zeros < 4) ? 28 + zeros : zeros - 4;
+    }
+
+    // TODO: Why is anticount param needed if it is always 32 - bitcount?
+    /**
+     * Left shifts the contents of one int array into another.
+     *
+     * @param src The source array.
+     * @param idx The initial index of the source array.
+     * @param result The destination array.
+     * @param bitcount The left shift.
+     * @param anticount The left anti-shift, e.g., <code>32-bitcount</code>.
+     * @param prev The prior source value.
+     */
+    /*@
+     @ requires 0 < bitcount && bitcount < 32 && anticount == 32 - bitcount;
+     @ requires src.length >= idx && result.length > idx;
+     @ assignable result[*];
+     @ ensures AP(result, \old(idx + 1)) == \old((AP(src, idx) + UNSIGNED(prev) << (idx*32)) << bitcount);
+     @*/
+    private static void leftShift(int[] src, int idx, int result[], int bitcount, int anticount, int prev){
+        for (; idx > 0; idx--) {
+            int v = (prev << bitcount);
+            prev = src[idx - 1];
+            v |= (prev >>> anticount);
+            result[idx] = v;
+        }
+        int v = prev << bitcount;
+        result[0] = v;
+    }
+
+    /**
+     * Shifts this <code>FDBigInteger</code> to the left. The shift is performed
+     * in-place unless the <code>FDBigInteger</code> is immutable in which case
+     * a new instance of <code>FDBigInteger</code> is returned.
+     *
+     * @param shift The number of bits to shift left.
+     * @return The shifted <code>FDBigInteger</code>.
+     */
+    /*@
+     @ requires this.value() == 0 || shift == 0;
+     @ assignable \nothing;
+     @ ensures \result == this;
+     @
+     @  also
+     @
+     @ requires this.value() > 0 && shift > 0 && this.isImmutable;
+     @ assignable \nothing;
+     @ ensures \result.value() == \old(this.value() << shift);
+     @
+     @  also
+     @
+     @ requires this.value() > 0 && shift > 0 && this.isImmutable;
+     @ assignable \nothing;
+     @ ensures \result == this;
+     @ ensures \result.value() == \old(this.value() << shift);
+     @*/
+    public FDBigInteger leftShift(int shift) {
+        if (shift == 0 || nWords == 0) {
+            return this;
+        }
+        int wordcount = shift >> 5;
+        int bitcount = shift & 0x1f;
+        if (this.isImmutable) {
+            if (bitcount == 0) {
+                return new FDBigInteger(Arrays.copyOf(data, nWords), offset + wordcount);
+            } else {
+                int anticount = 32 - bitcount;
+                int idx = nWords - 1;
+                int prev = data[idx];
+                int hi = prev >>> anticount;
+                int[] result;
+                if (hi != 0) {
+                    result = new int[nWords + 1];
+                    result[nWords] = hi;
+                } else {
+                    result = new int[nWords];
+                }
+                leftShift(data,idx,result,bitcount,anticount,prev);
+                return new FDBigInteger(result, offset + wordcount);
+            }
+        } else {
+            if (bitcount != 0) {
+                int anticount = 32 - bitcount;
+                if ((data[0] << bitcount) == 0) {
+                    int idx = 0;
+                    int prev = data[idx];
+                    for (; idx < nWords - 1; idx++) {
+                        int v = (prev >>> anticount);
+                        prev = data[idx + 1];
+                        v |= (prev << bitcount);
+                        data[idx] = v;
+                    }
+                    int v = prev >>> anticount;
+                    data[idx] = v;
+                    if(v==0) {
+                        nWords--;
+                    }
+                    offset++;
+                } else {
+                    int idx = nWords - 1;
+                    int prev = data[idx];
+                    int hi = prev >>> anticount;
+                    int[] result = data;
+                    int[] src = data;
+                    if (hi != 0) {
+                        if(nWords == data.length) {
+                            data = result = new int[nWords + 1];
+                        }
+                        result[nWords++] = hi;
+                    }
+                    leftShift(src,idx,result,bitcount,anticount,prev);
+                }
+            }
+            offset += wordcount;
+            return this;
+        }
+    }
+
+    /**
+     * Returns the number of <code>int</code>s this <code>FDBigInteger</code> represents.
+     *
+     * @return Number of <code>int</code>s required to represent this <code>FDBigInteger</code>.
+     */
+    /*@
+     @ requires this.value() == 0;
+     @ ensures \result == 0;
+     @
+     @  also
+     @
+     @ requires this.value() > 0;
+     @ ensures ((\bigint)1) << (\result - 1) <= this.value() && this.value() <= ((\bigint)1) << \result;
+     @*/
+    private /*@ pure @*/ int size() {
+        return nWords + offset;
+    }
+
+
+    /**
+     * Computes
+     * <pre>
+     * q = (int)( this / S )
+     * this = 10 * ( this mod S )
+     * Return q.
+     * </pre>
+     * This is the iteration step of digit development for output.
+     * We assume that S has been normalized, as above, and that
+     * "this" has been left-shifted accordingly.
+     * Also assumed, of course, is that the result, q, can be expressed
+     * as an integer, {@code 0 <= q < 10}.
+     *
+     * @param S The divisor of this <code>FDBigInteger</code>.
+     * @return <code>q = (int)(this / S)</code>.
+     */
+    /*@
+     @ requires !this.isImmutable;
+     @ requires this.size() <= S.size();
+     @ requires this.data.length + this.offset >= S.size();
+     @ requires S.value() >= ((\bigint)1) << (S.size()*32 - 4);
+     @ assignable this.nWords, this.offset, this.data, this.data[*];
+     @ ensures \result == \old(this.value() / S.value());
+     @ ensures this.value() == \old(10 * (this.value() % S.value()));
+     @*/
+    public int quoRemIteration(FDBigInteger S) throws IllegalArgumentException {
+        assert !this.isImmutable : "cannot modify immutable value";
+        // ensure that this and S have the same number of
+        // digits. If S is properly normalized and q < 10 then
+        // this must be so.
+        int thSize = this.size();
+        int sSize = S.size();
+        if (thSize < sSize) {
+            // this value is significantly less than S, result of division is zero.
+            // just mult this by 10.
+            int p = multAndCarryBy10(this.data, this.nWords, this.data);
+            if(p!=0) {
+                this.data[nWords++] = p;
+            } else {
+                trimLeadingZeros();
+            }
+            return 0;
+        } else if (thSize > sSize) {
+            throw new IllegalArgumentException("disparate values");
+        }
+        // estimate q the obvious way. We will usually be
+        // right. If not, then we're only off by a little and
+        // will re-add.
+        long q = (this.data[this.nWords - 1] & LONG_MASK) / (S.data[S.nWords - 1] & LONG_MASK);
+        long diff = multDiffMe(q, S);
+        if (diff != 0L) {
+            //@ assert q != 0;
+            //@ assert this.offset == \old(Math.min(this.offset, S.offset));
+            //@ assert this.offset <= S.offset;
+
+            // q is too big.
+            // add S back in until this turns +. This should
+            // not be very many times!
+            long sum = 0L;
+            int tStart = S.offset - this.offset;
+            //@ assert tStart >= 0;
+            int[] sd = S.data;
+            int[] td = this.data;
+            while (sum == 0L) {
+                for (int sIndex = 0, tIndex = tStart; tIndex < this.nWords; sIndex++, tIndex++) {
+                    sum += (td[tIndex] & LONG_MASK) + (sd[sIndex] & LONG_MASK);
+                    td[tIndex] = (int) sum;
+                    sum >>>= 32; // Signed or unsigned, answer is 0 or 1
+                }
+                //
+                // Originally the following line read
+                // "if ( sum !=0 && sum != -1 )"
+                // but that would be wrong, because of the
+                // treatment of the two values as entirely unsigned,
+                // it would be impossible for a carry-out to be interpreted
+                // as -1 -- it would have to be a single-bit carry-out, or +1.
+                //
+                assert sum == 0 || sum == 1 : sum; // carry out of division correction
+                q -= 1;
+            }
+        }
+        // finally, we can multiply this by 10.
+        // it cannot overflow, right, as the high-order word has
+        // at least 4 high-order zeros!
+        int p = multAndCarryBy10(this.data, this.nWords, this.data);
+        assert p == 0 : p; // Carry out of *10
+        trimLeadingZeros();
+        return (int) q;
+    }
+
+    /**
+     * Multiplies this <code>FDBigInteger</code> by 10. The operation will be
+     * performed in place unless the <code>FDBigInteger</code> is immutable in
+     * which case a new <code>FDBigInteger</code> will be returned.
+     *
+     * @return The <code>FDBigInteger</code> multiplied by 10.
+     */
+    /*@
+     @ requires this.value() == 0;
+     @ assignable \nothing;
+     @ ensures \result == this;
+     @
+     @  also
+     @
+     @ requires this.value() > 0 && this.isImmutable;
+     @ assignable \nothing;
+     @ ensures \result.value() == \old(this.value() * 10);
+     @
+     @  also
+     @
+     @ requires this.value() > 0 && !this.isImmutable;
+     @ assignable this.nWords, this.data, this.data[*];
+     @ ensures \result == this;
+     @ ensures \result.value() == \old(this.value() * 10);
+     @*/
+    public FDBigInteger multBy10() {
+        if (nWords == 0) {
+            return this;
+        }
+        if (isImmutable) {
+            int[] res = new int[nWords + 1];
+            res[nWords] = multAndCarryBy10(data, nWords, res);
+            return new FDBigInteger(res, offset);
+        } else {
+            int p = multAndCarryBy10(this.data, this.nWords, this.data);
+            if (p != 0) {
+                if (nWords == data.length) {
+                    if (data[0] == 0) {
+                        System.arraycopy(data, 1, data, 0, --nWords);
+                        offset++;
+                    } else {
+                        data = Arrays.copyOf(data, data.length + 1);
+                    }
+                }
+                data[nWords++] = p;
+            } else {
+                trimLeadingZeros();
+            }
+            return this;
+        }
+    }
+
+    /**
+     * Multiplies this <code>FDBigInteger</code> by
+     * <code>5<sup>p5</sup> * 2<sup>p2</sup></code>. The operation will be
+     * performed in place if possible, otherwise a new <code>FDBigInteger</code>
+     * will be returned.
+     *
+     * @param p5 The exponent of the power-of-five factor.
+     * @param p2 The exponent of the power-of-two factor.
+     * @return The multiplication result.
+     */
+    /*@
+     @ requires this.value() == 0 || p5 == 0 && p2 == 0;
+     @ assignable \nothing;
+     @ ensures \result == this;
+     @
+     @  also
+     @
+     @ requires this.value() > 0 && (p5 > 0 && p2 >= 0 || p5 == 0 && p2 > 0 && this.isImmutable);
+     @ assignable \nothing;
+     @ ensures \result.value() == \old(this.value() * pow52(p5, p2));
+     @
+     @  also
+     @
+     @ requires this.value() > 0 && p5 == 0 && p2 > 0 && !this.isImmutable;
+     @ assignable this.nWords, this.data, this.data[*];
+     @ ensures \result == this;
+     @ ensures \result.value() == \old(this.value() * pow52(p5, p2));
+     @*/
+    public FDBigInteger multByPow52(int p5, int p2) {
+        if (this.nWords == 0) {
+            return this;
+        }
+        FDBigInteger res = this;
+        if (p5 != 0) {
+            int[] r;
+            int extraSize = (p2 != 0) ? 1 : 0;
+            if (p5 < SMALL_5_POW.length) {
+                r = new int[this.nWords + 1 + extraSize];
+                mult(this.data, this.nWords, SMALL_5_POW[p5], r);
+                res = new FDBigInteger(r, this.offset);
+            } else {
+                FDBigInteger pow5 = big5pow(p5);
+                r = new int[this.nWords + pow5.size() + extraSize];
+                mult(this.data, this.nWords, pow5.data, pow5.nWords, r);
+                res = new FDBigInteger(r, this.offset + pow5.offset);
+            }
+        }
+        return res.leftShift(p2);
+    }
+
+    /**
+     * Multiplies two big integers represented as int arrays.
+     *
+     * @param s1 The first array factor.
+     * @param s1Len The number of elements of <code>s1</code> to use.
+     * @param s2 The second array factor.
+     * @param s2Len The number of elements of <code>s2</code> to use.
+     * @param dst The product array.
+     */
+    /*@
+     @ requires s1 != dst && s2 != dst;
+     @ requires s1.length >= s1Len && s2.length >= s2Len && dst.length >= s1Len + s2Len;
+     @ assignable dst[0 .. s1Len + s2Len - 1];
+     @ ensures AP(dst, s1Len + s2Len) == \old(AP(s1, s1Len) * AP(s2, s2Len));
+     @*/
+    private static void mult(int[] s1, int s1Len, int[] s2, int s2Len, int[] dst) {
+        for (int i = 0; i < s1Len; i++) {
+            long v = s1[i] & LONG_MASK;
+            long p = 0L;
+            for (int j = 0; j < s2Len; j++) {
+                p += (dst[i + j] & LONG_MASK) + v * (s2[j] & LONG_MASK);
+                dst[i + j] = (int) p;
+                p >>>= 32;
+            }
+            dst[i + s2Len] = (int) p;
+        }
+    }
+
+    /**
+     * Subtracts the supplied <code>FDBigInteger</code> subtrahend from this
+     * <code>FDBigInteger</code>. Assert that the result is positive.
+     * If the subtrahend is immutable, store the result in this(minuend).
+     * If this(minuend) is immutable a new <code>FDBigInteger</code> is created.
+     *
+     * @param subtrahend The <code>FDBigInteger</code> to be subtracted.
+     * @return This <code>FDBigInteger</code> less the subtrahend.
+     */
+    /*@
+     @ requires this.isImmutable;
+     @ requires this.value() >= subtrahend.value();
+     @ assignable \nothing;
+     @ ensures \result.value() == \old(this.value() - subtrahend.value());
+     @
+     @  also
+     @
+     @ requires !subtrahend.isImmutable;
+     @ requires this.value() >= subtrahend.value();
+     @ assignable this.nWords, this.offset, this.data, this.data[*];
+     @ ensures \result == this;
+     @ ensures \result.value() == \old(this.value() - subtrahend.value());
+     @*/
+    public FDBigInteger leftInplaceSub(FDBigInteger subtrahend) {
+        assert this.size() >= subtrahend.size() : "result should be positive";
+        FDBigInteger minuend;
+        if (this.isImmutable) {
+            minuend = new FDBigInteger(this.data.clone(), this.offset);
+        } else {
+            minuend = this;
+        }
+        int offsetDiff = subtrahend.offset - minuend.offset;
+        int[] sData = subtrahend.data;
+        int[] mData = minuend.data;
+        int subLen = subtrahend.nWords;
+        int minLen = minuend.nWords;
+        if (offsetDiff < 0) {
+            // need to expand minuend
+            int rLen = minLen - offsetDiff;
+            if (rLen < mData.length) {
+                System.arraycopy(mData, 0, mData, -offsetDiff, minLen);
+                Arrays.fill(mData, 0, -offsetDiff, 0);
+            } else {
+                int[] r = new int[rLen];
+                System.arraycopy(mData, 0, r, -offsetDiff, minLen);
+                minuend.data = mData = r;
+            }
+            minuend.offset = subtrahend.offset;
+            minuend.nWords = minLen = rLen;
+            offsetDiff = 0;
+        }
+        long borrow = 0L;
+        int mIndex = offsetDiff;
+        for (int sIndex = 0; sIndex < subLen && mIndex < minLen; sIndex++, mIndex++) {
+            long diff = (mData[mIndex] & LONG_MASK) - (sData[sIndex] & LONG_MASK) + borrow;
+            mData[mIndex] = (int) diff;
+            borrow = diff >> 32; // signed shift
+        }
+        for (; borrow != 0 && mIndex < minLen; mIndex++) {
+            long diff = (mData[mIndex] & LONG_MASK) + borrow;
+            mData[mIndex] = (int) diff;
+            borrow = diff >> 32; // signed shift
+        }
+        assert borrow == 0L : borrow; // borrow out of subtract,
+        // result should be positive
+        minuend.trimLeadingZeros();
+        return minuend;
+    }
+
+    /**
+     * Subtracts the supplied <code>FDBigInteger</code> subtrahend from this
+     * <code>FDBigInteger</code>. Assert that the result is positive.
+     * If the this(minuend) is immutable, store the result in subtrahend.
+     * If subtrahend is immutable a new <code>FDBigInteger</code> is created.
+     *
+     * @param subtrahend The <code>FDBigInteger</code> to be subtracted.
+     * @return This <code>FDBigInteger</code> less the subtrahend.
+     */
+    /*@
+     @ requires subtrahend.isImmutable;
+     @ requires this.value() >= subtrahend.value();
+     @ assignable \nothing;
+     @ ensures \result.value() == \old(this.value() - subtrahend.value());
+     @
+     @  also
+     @
+     @ requires !subtrahend.isImmutable;
+     @ requires this.value() >= subtrahend.value();
+     @ assignable subtrahend.nWords, subtrahend.offset, subtrahend.data, subtrahend.data[*];
+     @ ensures \result == subtrahend;
+     @ ensures \result.value() == \old(this.value() - subtrahend.value());
+     @*/
+    public FDBigInteger rightInplaceSub(FDBigInteger subtrahend) {
+        assert this.size() >= subtrahend.size() : "result should be positive";
+        FDBigInteger minuend = this;
+        if (subtrahend.isImmutable) {
+            subtrahend = new FDBigInteger(subtrahend.data.clone(), subtrahend.offset);
+        }
+        int offsetDiff = minuend.offset - subtrahend.offset;
+        int[] sData = subtrahend.data;
+        int[] mData = minuend.data;
+        int subLen = subtrahend.nWords;
+        int minLen = minuend.nWords;
+        if (offsetDiff < 0) {
+            int rLen = minLen;
+            if (rLen < sData.length) {
+                System.arraycopy(sData, 0, sData, -offsetDiff, subLen);
+                Arrays.fill(sData, 0, -offsetDiff, 0);
+            } else {
+                int[] r = new int[rLen];
+                System.arraycopy(sData, 0, r, -offsetDiff, subLen);
+                subtrahend.data = sData = r;
+            }
+            subtrahend.offset = minuend.offset;
+            subLen -= offsetDiff;
+            offsetDiff = 0;
+        } else {
+            int rLen = minLen + offsetDiff;
+            if (rLen >= sData.length) {
+                subtrahend.data = sData = Arrays.copyOf(sData, rLen);
+            }
+        }
+        //@ assert minuend == this && minuend.value() == \old(this.value());
+        //@ assert mData == minuend.data && minLen == minuend.nWords;
+        //@ assert subtrahend.offset + subtrahend.data.length >= minuend.size();
+        //@ assert sData == subtrahend.data;
+        //@ assert AP(subtrahend.data, subtrahend.data.length) << subtrahend.offset == \old(subtrahend.value());
+        //@ assert subtrahend.offset == Math.min(\old(this.offset), minuend.offset);
+        //@ assert offsetDiff == minuend.offset - subtrahend.offset;
+        //@ assert 0 <= offsetDiff && offsetDiff + minLen <= sData.length;
+        int sIndex = 0;
+        long borrow = 0L;
+        for (; sIndex < offsetDiff; sIndex++) {
+            long diff = 0L - (sData[sIndex] & LONG_MASK) + borrow;
+            sData[sIndex] = (int) diff;
+            borrow = diff >> 32; // signed shift
+        }
+        //@ assert sIndex == offsetDiff;
+        for (int mIndex = 0; mIndex < minLen; sIndex++, mIndex++) {
+            //@ assert sIndex == offsetDiff + mIndex;
+            long diff = (mData[mIndex] & LONG_MASK) - (sData[sIndex] & LONG_MASK) + borrow;
+            sData[sIndex] = (int) diff;
+            borrow = diff >> 32; // signed shift
+        }
+        assert borrow == 0L : borrow; // borrow out of subtract,
+        // result should be positive
+        subtrahend.nWords = sIndex;
+        subtrahend.trimLeadingZeros();
+        return subtrahend;
+
+    }
+
+    /**
+     * Determines whether all elements of an array are zero for all indices less
+     * than a given index.
+     *
+     * @param a The array to be examined.
+     * @param from The index strictly below which elements are to be examined.
+     * @return Zero if all elements in range are zero, 1 otherwise.
+     */
+    /*@
+     @ requires 0 <= from && from <= a.length;
+     @ ensures \result == (AP(a, from) == 0 ? 0 : 1);
+     @*/
+    private /*@ pure @*/ static int checkZeroTail(int[] a, int from) {
+        while (from > 0) {
+            if (a[--from] != 0) {
+                return 1;
+            }
+        }
+        return 0;
+    }
+
+    /**
+     * Compares the parameter with this <code>FDBigInteger</code>. Returns an
+     * integer accordingly as:
+     * <pre>{@code
+     * > 0: this > other
+     *   0: this == other
+     * < 0: this < other
+     * }</pre>
+     *
+     * @param other The <code>FDBigInteger</code> to compare.
+     * @return A negative value, zero, or a positive value according to the
+     * result of the comparison.
+     */
+    /*@
+     @ ensures \result == (this.value() < other.value() ? -1 : this.value() > other.value() ? +1 : 0);
+     @*/
+    public /*@ pure @*/ int cmp(FDBigInteger other) {
+        int aSize = nWords + offset;
+        int bSize = other.nWords + other.offset;
+        if (aSize > bSize) {
+            return 1;
+        } else if (aSize < bSize) {
+            return -1;
+        }
+        int aLen = nWords;
+        int bLen = other.nWords;
+        while (aLen > 0 && bLen > 0) {
+            int a = data[--aLen];
+            int b = other.data[--bLen];
+            if (a != b) {
+                return ((a & LONG_MASK) < (b & LONG_MASK)) ? -1 : 1;
+            }
+        }
+        if (aLen > 0) {
+            return checkZeroTail(data, aLen);
+        }
+        if (bLen > 0) {
+            return -checkZeroTail(other.data, bLen);
+        }
+        return 0;
+    }
+
+    /**
+     * Compares this <code>FDBigInteger</code> with
+     * <code>5<sup>p5</sup> * 2<sup>p2</sup></code>.
+     * Returns an integer accordingly as:
+     * <pre>{@code
+     * > 0: this > other
+     *   0: this == other
+     * < 0: this < other
+     * }</pre>
+     * @param p5 The exponent of the power-of-five factor.
+     * @param p2 The exponent of the power-of-two factor.
+     * @return A negative value, zero, or a positive value according to the
+     * result of the comparison.
+     */
+    /*@
+     @ requires p5 >= 0 && p2 >= 0;
+     @ ensures \result == (this.value() < pow52(p5, p2) ? -1 : this.value() >  pow52(p5, p2) ? +1 : 0);
+     @*/
+    public /*@ pure @*/ int cmpPow52(int p5, int p2) {
+        if (p5 == 0) {
+            int wordcount = p2 >> 5;
+            int bitcount = p2 & 0x1f;
+            int size = this.nWords + this.offset;
+            if (size > wordcount + 1) {
+                return 1;
+            } else if (size < wordcount + 1) {
+                return -1;
+            }
+            int a = this.data[this.nWords -1];
+            int b = 1 << bitcount;
+            if (a != b) {
+                return ( (a & LONG_MASK) < (b & LONG_MASK)) ? -1 : 1;
+            }
+            return checkZeroTail(this.data, this.nWords - 1);
+        }
+        return this.cmp(big5pow(p5).leftShift(p2));
+    }
+
+    /**
+     * Compares this <code>FDBigInteger</code> with <code>x + y</code>. Returns a
+     * value according to the comparison as:
+     * <pre>{@code
+     * -1: this <  x + y
+     *  0: this == x + y
+     *  1: this >  x + y
+     * }</pre>
+     * @param x The first addend of the sum to compare.
+     * @param y The second addend of the sum to compare.
+     * @return -1, 0, or 1 according to the result of the comparison.
+     */
+    /*@
+     @ ensures \result == (this.value() < x.value() + y.value() ? -1 : this.value() > x.value() + y.value() ? +1 : 0);
+     @*/
+    public /*@ pure @*/ int addAndCmp(FDBigInteger x, FDBigInteger y) {
+        FDBigInteger big;
+        FDBigInteger small;
+        int xSize = x.size();
+        int ySize = y.size();
+        int bSize;
+        int sSize;
+        if (xSize >= ySize) {
+            big = x;
+            small = y;
+            bSize = xSize;
+            sSize = ySize;
+        } else {
+            big = y;
+            small = x;
+            bSize = ySize;
+            sSize = xSize;
+        }
+        int thSize = this.size();
+        if (bSize == 0) {
+            return thSize == 0 ? 0 : 1;
+        }
+        if (sSize == 0) {
+            return this.cmp(big);
+        }
+        if (bSize > thSize) {
+            return -1;
+        }
+        if (bSize + 1 < thSize) {
+            return 1;
+        }
+        long top = (big.data[big.nWords - 1] & LONG_MASK);
+        if (sSize == bSize) {
+            top += (small.data[small.nWords - 1] & LONG_MASK);
+        }
+        if ((top >>> 32) == 0) {
+            if (((top + 1) >>> 32) == 0) {
+                // good case - no carry extension
+                if (bSize < thSize) {
+                    return 1;
+                }
+                // here sum.nWords == this.nWords
+                long v = (this.data[this.nWords - 1] & LONG_MASK);
+                if (v < top) {
+                    return -1;
+                }
+                if (v > top + 1) {
+                    return 1;
+                }
+            }
+        } else { // (top>>>32)!=0 guaranteed carry extension
+            if (bSize + 1 > thSize) {
+                return -1;
+            }
+            // here sum.nWords == this.nWords
+            top >>>= 32;
+            long v = (this.data[this.nWords - 1] & LONG_MASK);
+            if (v < top) {
+                return -1;
+            }
+            if (v > top + 1) {
+                return 1;
+            }
+        }
+        return this.cmp(big.add(small));
+    }
+
+    /**
+     * Makes this <code>FDBigInteger</code> immutable.
+     */
+    /*@
+     @ assignable this.isImmutable;
+     @ ensures this.isImmutable;
+     @*/
+    public void makeImmutable() {
+        this.isImmutable = true;
+    }
+
+    /**
+     * Multiplies this <code>FDBigInteger</code> by an integer.
+     *
+     * @param i The factor by which to multiply this <code>FDBigInteger</code>.
+     * @return This <code>FDBigInteger</code> multiplied by an integer.
+     */
+    /*@
+     @ requires this.value() == 0;
+     @ assignable \nothing;
+     @ ensures \result == this;
+     @
+     @  also
+     @
+     @ requires this.value() != 0;
+     @ assignable \nothing;
+     @ ensures \result.value() == \old(this.value() * UNSIGNED(i));
+     @*/
+    private FDBigInteger mult(int i) {
+        if (this.nWords == 0) {
+            return this;
+        }
+        int[] r = new int[nWords + 1];
+        mult(data, nWords, i, r);
+        return new FDBigInteger(r, offset);
+    }
+
+    /**
+     * Multiplies this <code>FDBigInteger</code> by another <code>FDBigInteger</code>.
+     *
+     * @param other The <code>FDBigInteger</code> factor by which to multiply.
+     * @return The product of this and the parameter <code>FDBigInteger</code>s.
+     */
+    /*@
+     @ requires this.value() == 0;
+     @ assignable \nothing;
+     @ ensures \result == this;
+     @
+     @  also
+     @
+     @ requires this.value() != 0 && other.value() == 0;
+     @ assignable \nothing;
+     @ ensures \result == other;
+     @
+     @  also
+     @
+     @ requires this.value() != 0 && other.value() != 0;
+     @ assignable \nothing;
+     @ ensures \result.value() == \old(this.value() * other.value());
+     @*/
+    private FDBigInteger mult(FDBigInteger other) {
+        if (this.nWords == 0) {
+            return this;
+        }
+        if (this.size() == 1) {
+            return other.mult(data[0]);
+        }
+        if (other.nWords == 0) {
+            return other;
+        }
+        if (other.size() == 1) {
+            return this.mult(other.data[0]);
+        }
+        int[] r = new int[nWords + other.nWords];
+        mult(this.data, this.nWords, other.data, other.nWords, r);
+        return new FDBigInteger(r, this.offset + other.offset);
+    }
+
+    /**
+     * Adds another <code>FDBigInteger</code> to this <code>FDBigInteger</code>.
+     *
+     * @param other The <code>FDBigInteger</code> to add.
+     * @return The sum of the <code>FDBigInteger</code>s.
+     */
+    /*@
+     @ assignable \nothing;
+     @ ensures \result.value() == \old(this.value() + other.value());
+     @*/
+    private FDBigInteger add(FDBigInteger other) {
+        FDBigInteger big, small;
+        int bigLen, smallLen;
+        int tSize = this.size();
+        int oSize = other.size();
+        if (tSize >= oSize) {
+            big = this;
+            bigLen = tSize;
+            small = other;
+            smallLen = oSize;
+        } else {
+            big = other;
+            bigLen = oSize;
+            small = this;
+            smallLen = tSize;
+        }
+        int[] r = new int[bigLen + 1];
+        int i = 0;
+        long carry = 0L;
+        for (; i < smallLen; i++) {
+            carry += (i < big.offset   ? 0L : (big.data[i - big.offset] & LONG_MASK) )
+                   + ((i < small.offset ? 0L : (small.data[i - small.offset] & LONG_MASK)));
+            r[i] = (int) carry;
+            carry >>= 32; // signed shift.
+        }
+        for (; i < bigLen; i++) {
+            carry += (i < big.offset ? 0L : (big.data[i - big.offset] & LONG_MASK) );
+            r[i] = (int) carry;
+            carry >>= 32; // signed shift.
+        }
+        r[bigLen] = (int) carry;
+        return new FDBigInteger(r, 0);
+    }
+
+
+    /**
+     * Multiplies a <code>FDBigInteger</code> by an int and adds another int. The
+     * result is computed in place. This method is intended only to be invoked
+     * from
+     * <code>
+     * FDBigInteger(long lValue, char[] digits, int kDigits, int nDigits)
+     * </code>.
+     *
+     * @param iv The factor by which to multiply this <code>FDBigInteger</code>.
+     * @param addend The value to add to the product of this
+     * <code>FDBigInteger</code> and <code>iv</code>.
+     */
+    /*@
+     @ requires this.value()*UNSIGNED(iv) + UNSIGNED(addend) < ((\bigint)1) << ((this.data.length + this.offset)*32);
+     @ assignable this.data[*];
+     @ ensures this.value() == \old(this.value()*UNSIGNED(iv) + UNSIGNED(addend));
+     @*/
+    private /*@ helper @*/ void multAddMe(int iv, int addend) {
+        long v = iv & LONG_MASK;
+        // unroll 0th iteration, doing addition.
+        long p = v * (data[0] & LONG_MASK) + (addend & LONG_MASK);
+        data[0] = (int) p;
+        p >>>= 32;
+        for (int i = 1; i < nWords; i++) {
+            p += v * (data[i] & LONG_MASK);
+            data[i] = (int) p;
+            p >>>= 32;
+        }
+        if (p != 0L) {
+            data[nWords++] = (int) p; // will fail noisily if illegal!
+        }
+    }
+
+    //
+    // original doc:
+    //
+    // do this -=q*S
+    // returns borrow
+    //
+    /**
+     * Multiplies the parameters and subtracts them from this
+     * <code>FDBigInteger</code>.
+     *
+     * @param q The integer parameter.
+     * @param S The <code>FDBigInteger</code> parameter.
+     * @return <code>this - q*S</code>.
+     */
+    /*@
+     @ ensures nWords == 0 ==> offset == 0;
+     @ ensures nWords > 0 ==> data[nWords - 1] != 0;
+     @*/
+    /*@
+     @ requires 0 < q && q <= (1L << 31);
+     @ requires data != null;
+     @ requires 0 <= nWords && nWords <= data.length && offset >= 0;
+     @ requires !this.isImmutable;
+     @ requires this.size() == S.size();
+     @ requires this != S;
+     @ assignable this.nWords, this.offset, this.data, this.data[*];
+     @ ensures -q <= \result && \result <= 0;
+     @ ensures this.size() == \old(this.size());
+     @ ensures this.value() + (\result << (this.size()*32)) == \old(this.value() - q*S.value());
+     @ ensures this.offset == \old(Math.min(this.offset, S.offset));
+     @ ensures \old(this.offset <= S.offset) ==> this.nWords == \old(this.nWords);
+     @ ensures \old(this.offset <= S.offset) ==> this.offset == \old(this.offset);
+     @ ensures \old(this.offset <= S.offset) ==> this.data == \old(this.data);
+     @
+     @  also
+     @
+     @ requires q == 0;
+     @ assignable \nothing;
+     @ ensures \result == 0;
+     @*/
+    private /*@ helper @*/ long multDiffMe(long q, FDBigInteger S) {
+        long diff = 0L;
+        if (q != 0) {
+            int deltaSize = S.offset - this.offset;
+            if (deltaSize >= 0) {
+                int[] sd = S.data;
+                int[] td = this.data;
+                for (int sIndex = 0, tIndex = deltaSize; sIndex < S.nWords; sIndex++, tIndex++) {
+                    diff += (td[tIndex] & LONG_MASK) - q * (sd[sIndex] & LONG_MASK);
+                    td[tIndex] = (int) diff;
+                    diff >>= 32; // N.B. SIGNED shift.
+                }
+            } else {
+                deltaSize = -deltaSize;
+                int[] rd = new int[nWords + deltaSize];
+                int sIndex = 0;
+                int rIndex = 0;
+                int[] sd = S.data;
+                for (; rIndex < deltaSize && sIndex < S.nWords; sIndex++, rIndex++) {
+                    diff -= q * (sd[sIndex] & LONG_MASK);
+                    rd[rIndex] = (int) diff;
+                    diff >>= 32; // N.B. SIGNED shift.
+                }
+                int tIndex = 0;
+                int[] td = this.data;
+                for (; sIndex < S.nWords; sIndex++, tIndex++, rIndex++) {
+                    diff += (td[tIndex] & LONG_MASK) - q * (sd[sIndex] & LONG_MASK);
+                    rd[rIndex] = (int) diff;
+                    diff >>= 32; // N.B. SIGNED shift.
+                }
+                this.nWords += deltaSize;
+                this.offset -= deltaSize;
+                this.data = rd;
+            }
+        }
+        return diff;
+    }
+
+
+    /**
+     * Multiplies by 10 a big integer represented as an array. The final carry
+     * is returned.
+     *
+     * @param src The array representation of the big integer.
+     * @param srcLen The number of elements of <code>src</code> to use.
+     * @param dst The product array.
+     * @return The final carry of the multiplication.
+     */
+    /*@
+     @ requires src.length >= srcLen && dst.length >= srcLen;
+     @ assignable dst[0 .. srcLen - 1];
+     @ ensures 0 <= \result && \result < 10;
+     @ ensures AP(dst, srcLen) + (\result << (srcLen*32)) == \old(AP(src, srcLen) * 10);
+     @*/
+    private static int multAndCarryBy10(int[] src, int srcLen, int[] dst) {
+        long carry = 0;
+        for (int i = 0; i < srcLen; i++) {
+            long product = (src[i] & LONG_MASK) * 10L + carry;
+            dst[i] = (int) product;
+            carry = product >>> 32;
+        }
+        return (int) carry;
+    }
+
+    /**
+     * Multiplies by a constant value a big integer represented as an array.
+     * The constant factor is an <code>int</code>.
+     *
+     * @param src The array representation of the big integer.
+     * @param srcLen The number of elements of <code>src</code> to use.
+     * @param value The constant factor by which to multiply.
+     * @param dst The product array.
+     */
+    /*@
+     @ requires src.length >= srcLen && dst.length >= srcLen + 1;
+     @ assignable dst[0 .. srcLen];
+     @ ensures AP(dst, srcLen + 1) == \old(AP(src, srcLen) * UNSIGNED(value));
+     @*/
+    private static void mult(int[] src, int srcLen, int value, int[] dst) {
+        long val = value & LONG_MASK;
+        long carry = 0;
+        for (int i = 0; i < srcLen; i++) {
+            long product = (src[i] & LONG_MASK) * val + carry;
+            dst[i] = (int) product;
+            carry = product >>> 32;
+        }
+        dst[srcLen] = (int) carry;
+    }
+
+    /**
+     * Multiplies by a constant value a big integer represented as an array.
+     * The constant factor is a long represent as two <code>int</code>s.
+     *
+     * @param src The array representation of the big integer.
+     * @param srcLen The number of elements of <code>src</code> to use.
+     * @param v0 The lower 32 bits of the long factor.
+     * @param v1 The upper 32 bits of the long factor.
+     * @param dst The product array.
+     */
+    /*@
+     @ requires src != dst;
+     @ requires src.length >= srcLen && dst.length >= srcLen + 2;
+     @ assignable dst[0 .. srcLen + 1];
+     @ ensures AP(dst, srcLen + 2) == \old(AP(src, srcLen) * (UNSIGNED(v0) + (UNSIGNED(v1) << 32)));
+     @*/
+    private static void mult(int[] src, int srcLen, int v0, int v1, int[] dst) {
+        long v = v0 & LONG_MASK;
+        long carry = 0;
+        for (int j = 0; j < srcLen; j++) {
+            long product = v * (src[j] & LONG_MASK) + carry;
+            dst[j] = (int) product;
+            carry = product >>> 32;
+        }
+        dst[srcLen] = (int) carry;
+        v = v1 & LONG_MASK;
+        carry = 0;
+        for (int j = 0; j < srcLen; j++) {
+            long product = (dst[j + 1] & LONG_MASK) + v * (src[j] & LONG_MASK) + carry;
+            dst[j + 1] = (int) product;
+            carry = product >>> 32;
+        }
+        dst[srcLen + 1] = (int) carry;
+    }
+
+    // Fails assertion for negative exponent.
+    /**
+     * Computes <code>5</code> raised to a given power.
+     *
+     * @param p The exponent of 5.
+     * @return <code>5<sup>p</sup></code>.
+     */
+    private static FDBigInteger big5pow(int p) {
+        assert p >= 0 : p; // negative power of 5
+        if (p < MAX_FIVE_POW) {
+            return POW_5_CACHE[p];
+        }
+        return big5powRec(p);
+    }
+
+    // slow path
+    /**
+     * Computes <code>5</code> raised to a given power.
+     *
+     * @param p The exponent of 5.
+     * @return <code>5<sup>p</sup></code>.
+     */
+    private static FDBigInteger big5powRec(int p) {
+        if (p < MAX_FIVE_POW) {
+            return POW_5_CACHE[p];
+        }
+        // construct the value.
+        // recursively.
+        int q, r;
+        // in order to compute 5^p,
+        // compute its square root, 5^(p/2) and square.
+        // or, let q = p / 2, r = p -q, then
+        // 5^p = 5^(q+r) = 5^q * 5^r
+        q = p >> 1;
+        r = p - q;
+        FDBigInteger bigq = big5powRec(q);
+        if (r < SMALL_5_POW.length) {
+            return bigq.mult(SMALL_5_POW[r]);
+        } else {
+            return bigq.mult(big5powRec(r));
+        }
+    }
+
+    // for debugging ...
+    /**
+     * Converts this <code>FDBigInteger</code> to a hexadecimal string.
+     *
+     * @return The hexadecimal string representation.
+     */
+    public String toHexString(){
+        if(nWords ==0) {
+            return "0";
+        }
+        StringBuilder sb = new StringBuilder((nWords +offset)*8);
+        for(int i= nWords -1; i>=0; i--) {
+            String subStr = Integer.toHexString(data[i]);
+            for(int j = subStr.length(); j<8; j++) {
+                sb.append('0');
+            }
+            sb.append(subStr);
+        }
+        for(int i=offset; i>0; i--) {
+            sb.append("00000000");
+        }
+        return sb.toString();
+    }
+
+    // for debugging ...
+    /**
+     * Converts this <code>FDBigInteger</code> to a <code>BigInteger</code>.
+     *
+     * @return The <code>BigInteger</code> representation.
+     */
+    public BigInteger toBigInteger() {
+        byte[] magnitude = new byte[nWords * 4 + 1];
+        for (int i = 0; i < nWords; i++) {
+            int w = data[i];
+            magnitude[magnitude.length - 4 * i - 1] = (byte) w;
+            magnitude[magnitude.length - 4 * i - 2] = (byte) (w >> 8);
+            magnitude[magnitude.length - 4 * i - 3] = (byte) (w >> 16);
+            magnitude[magnitude.length - 4 * i - 4] = (byte) (w >> 24);
+        }
+        return new BigInteger(magnitude).shiftLeft(offset * 32);
+    }
+
+    // for debugging ...
+    /**
+     * Converts this <code>FDBigInteger</code> to a string.
+     *
+     * @return The string representation.
+     */
+    @Override
+    public String toString(){
+        return toBigInteger().toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/math/FloatConsts.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.math;
+
+/**
+ * This class contains additional constants documenting limits of the
+ * <code>float</code> type.
+ *
+ * @author Joseph D. Darcy
+ */
+
+public class FloatConsts {
+    /**
+     * Don't let anyone instantiate this class.
+     */
+    private FloatConsts() {}
+
+    public static final float POSITIVE_INFINITY = java.lang.Float.POSITIVE_INFINITY;
+    public static final float NEGATIVE_INFINITY = java.lang.Float.NEGATIVE_INFINITY;
+    public static final float NaN = java.lang.Float.NaN;
+    public static final float MAX_VALUE = java.lang.Float.MAX_VALUE;
+    public static final float MIN_VALUE = java.lang.Float.MIN_VALUE;
+
+    /**
+     * A constant holding the smallest positive normal value of type
+     * <code>float</code>, 2<sup>-126</sup>.  It is equal to the value
+     * returned by <code>Float.intBitsToFloat(0x00800000)</code>.
+     */
+    public static final float   MIN_NORMAL      = 1.17549435E-38f;
+
+    /**
+     * The number of logical bits in the significand of a
+     * <code>float</code> number, including the implicit bit.
+     */
+    public static final int SIGNIFICAND_WIDTH   = 24;
+
+    /**
+     * Maximum exponent a finite <code>float</code> number may have.
+     * It is equal to the value returned by
+     * <code>Math.ilogb(Float.MAX_VALUE)</code>.
+     */
+    public static final int     MAX_EXPONENT    = 127;
+
+    /**
+     * Minimum exponent a normalized <code>float</code> number may
+     * have.  It is equal to the value returned by
+     * <code>Math.ilogb(Float.MIN_NORMAL)</code>.
+     */
+    public static final int     MIN_EXPONENT    = -126;
+
+    /**
+     * The exponent the smallest positive <code>float</code> subnormal
+     * value would have if it could be normalized.
+     */
+    public static final int     MIN_SUB_EXPONENT = MIN_EXPONENT -
+                                                   (SIGNIFICAND_WIDTH - 1);
+
+    /**
+     * Bias used in representing a <code>float</code> exponent.
+     */
+    public static final int     EXP_BIAS        = 127;
+
+    /**
+     * Bit mask to isolate the sign bit of a <code>float</code>.
+     */
+    public static final int     SIGN_BIT_MASK   = 0x80000000;
+
+    /**
+     * Bit mask to isolate the exponent field of a
+     * <code>float</code>.
+     */
+    public static final int     EXP_BIT_MASK    = 0x7F800000;
+
+    /**
+     * Bit mask to isolate the significand field of a
+     * <code>float</code>.
+     */
+    public static final int     SIGNIF_BIT_MASK = 0x007FFFFF;
+
+    static {
+        // verify bit masks cover all bit positions and that the bit
+        // masks are non-overlapping
+        assert(((SIGN_BIT_MASK | EXP_BIT_MASK | SIGNIF_BIT_MASK) == ~0) &&
+               (((SIGN_BIT_MASK & EXP_BIT_MASK) == 0) &&
+                ((SIGN_BIT_MASK & SIGNIF_BIT_MASK) == 0) &&
+                ((EXP_BIT_MASK & SIGNIF_BIT_MASK) == 0)));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/math/FloatingDecimal.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,2552 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.math;
+
+import java.util.Arrays;
+import java.util.regex.*;
+
+/**
+ * A class for converting between ASCII and decimal representations of a single
+ * or double precision floating point number. Most conversions are provided via
+ * static convenience methods, although a <code>BinaryToASCIIConverter</code>
+ * instance may be obtained and reused.
+ */
+public class FloatingDecimal{
+    //
+    // Constants of the implementation;
+    // most are IEEE-754 related.
+    // (There are more really boring constants at the end.)
+    //
+    static final int    EXP_SHIFT = DoubleConsts.SIGNIFICAND_WIDTH - 1;
+    static final long   FRACT_HOB = ( 1L<<EXP_SHIFT ); // assumed High-Order bit
+    static final long   EXP_ONE   = ((long)DoubleConsts.EXP_BIAS)<<EXP_SHIFT; // exponent of 1.0
+    static final int    MAX_SMALL_BIN_EXP = 62;
+    static final int    MIN_SMALL_BIN_EXP = -( 63 / 3 );
+    static final int    MAX_DECIMAL_DIGITS = 15;
+    static final int    MAX_DECIMAL_EXPONENT = 308;
+    static final int    MIN_DECIMAL_EXPONENT = -324;
+    static final int    BIG_DECIMAL_EXPONENT = 324; // i.e. abs(MIN_DECIMAL_EXPONENT)
+    static final int    MAX_NDIGITS = 1100;
+
+    static final int    SINGLE_EXP_SHIFT  =   FloatConsts.SIGNIFICAND_WIDTH - 1;
+    static final int    SINGLE_FRACT_HOB  =   1<<SINGLE_EXP_SHIFT;
+    static final int    SINGLE_MAX_DECIMAL_DIGITS = 7;
+    static final int    SINGLE_MAX_DECIMAL_EXPONENT = 38;
+    static final int    SINGLE_MIN_DECIMAL_EXPONENT = -45;
+    static final int    SINGLE_MAX_NDIGITS = 200;
+
+    static final int    INT_DECIMAL_DIGITS = 9;
+
+    /**
+     * Converts a double precision floating point value to a <code>String</code>.
+     *
+     * @param d The double precision value.
+     * @return The value converted to a <code>String</code>.
+     */
+    public static String toJavaFormatString(double d) {
+        return getBinaryToASCIIConverter(d).toJavaFormatString();
+    }
+
+    /**
+     * Converts a single precision floating point value to a <code>String</code>.
+     *
+     * @param f The single precision value.
+     * @return The value converted to a <code>String</code>.
+     */
+    public static String toJavaFormatString(float f) {
+        return getBinaryToASCIIConverter(f).toJavaFormatString();
+    }
+
+    /**
+     * Appends a double precision floating point value to an <code>Appendable</code>.
+     * @param d The double precision value.
+     * @param buf The <code>Appendable</code> with the value appended.
+     */
+    public static void appendTo(double d, Appendable buf) {
+        getBinaryToASCIIConverter(d).appendTo(buf);
+    }
+
+    /**
+     * Appends a single precision floating point value to an <code>Appendable</code>.
+     * @param f The single precision value.
+     * @param buf The <code>Appendable</code> with the value appended.
+     */
+    public static void appendTo(float f, Appendable buf) {
+        getBinaryToASCIIConverter(f).appendTo(buf);
+    }
+
+    /**
+     * Converts a <code>String</code> to a double precision floating point value.
+     *
+     * @param s The <code>String</code> to convert.
+     * @return The double precision value.
+     * @throws NumberFormatException If the <code>String</code> does not
+     * represent a properly formatted double precision value.
+     */
+    public static double parseDouble(String s) throws NumberFormatException {
+        return readJavaFormatString(s).doubleValue();
+    }
+
+    /**
+     * Converts a <code>String</code> to a single precision floating point value.
+     *
+     * @param s The <code>String</code> to convert.
+     * @return The single precision value.
+     * @throws NumberFormatException If the <code>String</code> does not
+     * represent a properly formatted single precision value.
+     */
+    public static float parseFloat(String s) throws NumberFormatException {
+        return readJavaFormatString(s).floatValue();
+    }
+
+    /**
+     * A converter which can process single or double precision floating point
+     * values into an ASCII <code>String</code> representation.
+     */
+    public interface BinaryToASCIIConverter {
+        /**
+         * Converts a floating point value into an ASCII <code>String</code>.
+         * @return The value converted to a <code>String</code>.
+         */
+        public String toJavaFormatString();
+
+        /**
+         * Appends a floating point value to an <code>Appendable</code>.
+         * @param buf The <code>Appendable</code> to receive the value.
+         */
+        public void appendTo(Appendable buf);
+
+        /**
+         * Retrieves the decimal exponent most closely corresponding to this value.
+         * @return The decimal exponent.
+         */
+        public int getDecimalExponent();
+
+        /**
+         * Retrieves the value as an array of digits.
+         * @param digits The digit array.
+         * @return The number of valid digits copied into the array.
+         */
+        public int getDigits(char[] digits);
+
+        /**
+         * Indicates the sign of the value.
+         * @return {@code value < 0.0}.
+         */
+        public boolean isNegative();
+
+        /**
+         * Indicates whether the value is either infinite or not a number.
+         *
+         * @return <code>true</code> if and only if the value is <code>NaN</code>
+         * or infinite.
+         */
+        public boolean isExceptional();
+
+        /**
+         * Indicates whether the value was rounded up during the binary to ASCII
+         * conversion.
+         *
+         * @return <code>true</code> if and only if the value was rounded up.
+         */
+        public boolean digitsRoundedUp();
+
+        /**
+         * Indicates whether the binary to ASCII conversion was exact.
+         *
+         * @return <code>true</code> if any only if the conversion was exact.
+         */
+        public boolean decimalDigitsExact();
+    }
+
+    /**
+     * A <code>BinaryToASCIIConverter</code> which represents <code>NaN</code>
+     * and infinite values.
+     */
+    private static class ExceptionalBinaryToASCIIBuffer implements BinaryToASCIIConverter {
+        private final String image;
+        private boolean isNegative;
+
+        public ExceptionalBinaryToASCIIBuffer(String image, boolean isNegative) {
+            this.image = image;
+            this.isNegative = isNegative;
+        }
+
+        @Override
+        public String toJavaFormatString() {
+            return image;
+        }
+
+        @Override
+        public void appendTo(Appendable buf) {
+            if (buf instanceof StringBuilder) {
+                ((StringBuilder) buf).append(image);
+            } else if (buf instanceof StringBuffer) {
+                ((StringBuffer) buf).append(image);
+            } else {
+                assert false;
+            }
+        }
+
+        @Override
+        public int getDecimalExponent() {
+            throw new IllegalArgumentException("Exceptional value does not have an exponent");
+        }
+
+        @Override
+        public int getDigits(char[] digits) {
+            throw new IllegalArgumentException("Exceptional value does not have digits");
+        }
+
+        @Override
+        public boolean isNegative() {
+            return isNegative;
+        }
+
+        @Override
+        public boolean isExceptional() {
+            return true;
+        }
+
+        @Override
+        public boolean digitsRoundedUp() {
+            throw new IllegalArgumentException("Exceptional value is not rounded");
+        }
+
+        @Override
+        public boolean decimalDigitsExact() {
+            throw new IllegalArgumentException("Exceptional value is not exact");
+        }
+    }
+
+    private static final String INFINITY_REP = "Infinity";
+    private static final int INFINITY_LENGTH = INFINITY_REP.length();
+    private static final String NAN_REP = "NaN";
+    private static final int NAN_LENGTH = NAN_REP.length();
+
+    private static final BinaryToASCIIConverter B2AC_POSITIVE_INFINITY = new ExceptionalBinaryToASCIIBuffer(INFINITY_REP, false);
+    private static final BinaryToASCIIConverter B2AC_NEGATIVE_INFINITY = new ExceptionalBinaryToASCIIBuffer("-" + INFINITY_REP, true);
+    private static final BinaryToASCIIConverter B2AC_NOT_A_NUMBER = new ExceptionalBinaryToASCIIBuffer(NAN_REP, false);
+    private static final BinaryToASCIIConverter B2AC_POSITIVE_ZERO = new BinaryToASCIIBuffer(false, new char[]{'0'});
+    private static final BinaryToASCIIConverter B2AC_NEGATIVE_ZERO = new BinaryToASCIIBuffer(true,  new char[]{'0'});
+
+    /**
+     * A buffered implementation of <code>BinaryToASCIIConverter</code>.
+     */
+    static class BinaryToASCIIBuffer implements BinaryToASCIIConverter {
+        private boolean isNegative;
+        private int decExponent;
+        private int firstDigitIndex;
+        private int nDigits;
+        private final char[] digits;
+        private final char[] buffer = new char[26];
+
+        //
+        // The fields below provide additional information about the result of
+        // the binary to decimal digits conversion done in dtoa() and roundup()
+        // methods. They are changed if needed by those two methods.
+        //
+
+        // True if the dtoa() binary to decimal conversion was exact.
+        private boolean exactDecimalConversion = false;
+
+        // True if the result of the binary to decimal conversion was rounded-up
+        // at the end of the conversion process, i.e. roundUp() method was called.
+        private boolean decimalDigitsRoundedUp = false;
+
+        /**
+         * Default constructor; used for non-zero values,
+         * <code>BinaryToASCIIBuffer</code> may be thread-local and reused
+         */
+        BinaryToASCIIBuffer(){
+            this.digits = new char[20];
+        }
+
+        /**
+         * Creates a specialized value (positive and negative zeros).
+         */
+        BinaryToASCIIBuffer(boolean isNegative, char[] digits){
+            this.isNegative = isNegative;
+            this.decExponent  = 0;
+            this.digits = digits;
+            this.firstDigitIndex = 0;
+            this.nDigits = digits.length;
+        }
+
+        @Override
+        public String toJavaFormatString() {
+            int len = getChars(buffer);
+            return new String(buffer, 0, len);
+        }
+
+        @Override
+        public void appendTo(Appendable buf) {
+            int len = getChars(buffer);
+            if (buf instanceof StringBuilder) {
+                ((StringBuilder) buf).append(buffer, 0, len);
+            } else if (buf instanceof StringBuffer) {
+                ((StringBuffer) buf).append(buffer, 0, len);
+            } else {
+                assert false;
+            }
+        }
+
+        @Override
+        public int getDecimalExponent() {
+            return decExponent;
+        }
+
+        @Override
+        public int getDigits(char[] digits) {
+            System.arraycopy(this.digits,firstDigitIndex,digits,0,this.nDigits);
+            return this.nDigits;
+        }
+
+        @Override
+        public boolean isNegative() {
+            return isNegative;
+        }
+
+        @Override
+        public boolean isExceptional() {
+            return false;
+        }
+
+        @Override
+        public boolean digitsRoundedUp() {
+            return decimalDigitsRoundedUp;
+        }
+
+        @Override
+        public boolean decimalDigitsExact() {
+            return exactDecimalConversion;
+        }
+
+        private void setSign(boolean isNegative) {
+            this.isNegative = isNegative;
+        }
+
+        /**
+         * This is the easy subcase --
+         * all the significant bits, after scaling, are held in lvalue.
+         * negSign and decExponent tell us what processing and scaling
+         * has already been done. Exceptional cases have already been
+         * stripped out.
+         * In particular:
+         * lvalue is a finite number (not Inf, nor NaN)
+         * lvalue > 0L (not zero, nor negative).
+         *
+         * The only reason that we develop the digits here, rather than
+         * calling on Long.toString() is that we can do it a little faster,
+         * and besides want to treat trailing 0s specially. If Long.toString
+         * changes, we should re-evaluate this strategy!
+         */
+        private void developLongDigits( int decExponent, long lvalue, int insignificantDigits ){
+            if ( insignificantDigits != 0 ){
+                // Discard non-significant low-order bits, while rounding,
+                // up to insignificant value.
+                long pow10 = FDBigInteger.LONG_5_POW[insignificantDigits] << insignificantDigits; // 10^i == 5^i * 2^i;
+                long residue = lvalue % pow10;
+                lvalue /= pow10;
+                decExponent += insignificantDigits;
+                if ( residue >= (pow10>>1) ){
+                    // round up based on the low-order bits we're discarding
+                    lvalue++;
+                }
+            }
+            int  digitno = digits.length -1;
+            int  c;
+            if ( lvalue <= Integer.MAX_VALUE ){
+                assert lvalue > 0L : lvalue; // lvalue <= 0
+                // even easier subcase!
+                // can do int arithmetic rather than long!
+                int  ivalue = (int)lvalue;
+                c = ivalue%10;
+                ivalue /= 10;
+                while ( c == 0 ){
+                    decExponent++;
+                    c = ivalue%10;
+                    ivalue /= 10;
+                }
+                while ( ivalue != 0){
+                    digits[digitno--] = (char)(c+'0');
+                    decExponent++;
+                    c = ivalue%10;
+                    ivalue /= 10;
+                }
+                digits[digitno] = (char)(c+'0');
+            } else {
+                // same algorithm as above (same bugs, too )
+                // but using long arithmetic.
+                c = (int)(lvalue%10L);
+                lvalue /= 10L;
+                while ( c == 0 ){
+                    decExponent++;
+                    c = (int)(lvalue%10L);
+                    lvalue /= 10L;
+                }
+                while ( lvalue != 0L ){
+                    digits[digitno--] = (char)(c+'0');
+                    decExponent++;
+                    c = (int)(lvalue%10L);
+                    lvalue /= 10;
+                }
+                digits[digitno] = (char)(c+'0');
+            }
+            this.decExponent = decExponent+1;
+            this.firstDigitIndex = digitno;
+            this.nDigits = this.digits.length - digitno;
+        }
+
+        private void dtoa( int binExp, long fractBits, int nSignificantBits, boolean isCompatibleFormat)
+        {
+            assert fractBits > 0 ; // fractBits here can't be zero or negative
+            assert (fractBits & FRACT_HOB)!=0  ; // Hi-order bit should be set
+            // Examine number. Determine if it is an easy case,
+            // which we can do pretty trivially using float/long conversion,
+            // or whether we must do real work.
+            final int tailZeros = Long.numberOfTrailingZeros(fractBits);
+
+            // number of significant bits of fractBits;
+            final int nFractBits = EXP_SHIFT+1-tailZeros;
+
+            // reset flags to default values as dtoa() does not always set these
+            // flags and a prior call to dtoa() might have set them to incorrect
+            // values with respect to the current state.
+            decimalDigitsRoundedUp = false;
+            exactDecimalConversion = false;
+
+            // number of significant bits to the right of the point.
+            int nTinyBits = Math.max( 0, nFractBits - binExp - 1 );
+            if ( binExp <= MAX_SMALL_BIN_EXP && binExp >= MIN_SMALL_BIN_EXP ){
+                // Look more closely at the number to decide if,
+                // with scaling by 10^nTinyBits, the result will fit in
+                // a long.
+                if ( (nTinyBits < FDBigInteger.LONG_5_POW.length) && ((nFractBits + N_5_BITS[nTinyBits]) < 64 ) ){
+                    //
+                    // We can do this:
+                    // take the fraction bits, which are normalized.
+                    // (a) nTinyBits == 0: Shift left or right appropriately
+                    //     to align the binary point at the extreme right, i.e.
+                    //     where a long int point is expected to be. The integer
+                    //     result is easily converted to a string.
+                    // (b) nTinyBits > 0: Shift right by EXP_SHIFT-nFractBits,
+                    //     which effectively converts to long and scales by
+                    //     2^nTinyBits. Then multiply by 5^nTinyBits to
+                    //     complete the scaling. We know this won't overflow
+                    //     because we just counted the number of bits necessary
+                    //     in the result. The integer you get from this can
+                    //     then be converted to a string pretty easily.
+                    //
+                    if ( nTinyBits == 0 ) {
+                        int insignificant;
+                        if ( binExp > nSignificantBits ){
+                            insignificant = insignificantDigitsForPow2(binExp-nSignificantBits-1);
+                        } else {
+                            insignificant = 0;
+                        }
+                        if ( binExp >= EXP_SHIFT ){
+                            fractBits <<= (binExp-EXP_SHIFT);
+                        } else {
+                            fractBits >>>= (EXP_SHIFT-binExp) ;
+                        }
+                        developLongDigits( 0, fractBits, insignificant );
+                        return;
+                    }
+                    //
+                    // The following causes excess digits to be printed
+                    // out in the single-float case. Our manipulation of
+                    // halfULP here is apparently not correct. If we
+                    // better understand how this works, perhaps we can
+                    // use this special case again. But for the time being,
+                    // we do not.
+                    // else {
+                    //     fractBits >>>= EXP_SHIFT+1-nFractBits;
+                    //     fractBits//= long5pow[ nTinyBits ];
+                    //     halfULP = long5pow[ nTinyBits ] >> (1+nSignificantBits-nFractBits);
+                    //     developLongDigits( -nTinyBits, fractBits, insignificantDigits(halfULP) );
+                    //     return;
+                    // }
+                    //
+                }
+            }
+            //
+            // This is the hard case. We are going to compute large positive
+            // integers B and S and integer decExp, s.t.
+            //      d = ( B / S )// 10^decExp
+            //      1 <= B / S < 10
+            // Obvious choices are:
+            //      decExp = floor( log10(d) )
+            //      B      = d// 2^nTinyBits// 10^max( 0, -decExp )
+            //      S      = 10^max( 0, decExp)// 2^nTinyBits
+            // (noting that nTinyBits has already been forced to non-negative)
+            // I am also going to compute a large positive integer
+            //      M      = (1/2^nSignificantBits)// 2^nTinyBits// 10^max( 0, -decExp )
+            // i.e. M is (1/2) of the ULP of d, scaled like B.
+            // When we iterate through dividing B/S and picking off the
+            // quotient bits, we will know when to stop when the remainder
+            // is <= M.
+            //
+            // We keep track of powers of 2 and powers of 5.
+            //
+            int decExp = estimateDecExp(fractBits,binExp);
+            int B2, B5; // powers of 2 and powers of 5, respectively, in B
+            int S2, S5; // powers of 2 and powers of 5, respectively, in S
+            int M2, M5; // powers of 2 and powers of 5, respectively, in M
+
+            B5 = Math.max( 0, -decExp );
+            B2 = B5 + nTinyBits + binExp;
+
+            S5 = Math.max( 0, decExp );
+            S2 = S5 + nTinyBits;
+
+            M5 = B5;
+            M2 = B2 - nSignificantBits;
+
+            //
+            // the long integer fractBits contains the (nFractBits) interesting
+            // bits from the mantissa of d ( hidden 1 added if necessary) followed
+            // by (EXP_SHIFT+1-nFractBits) zeros. In the interest of compactness,
+            // I will shift out those zeros before turning fractBits into a
+            // FDBigInteger. The resulting whole number will be
+            //      d * 2^(nFractBits-1-binExp).
+            //
+            fractBits >>>= tailZeros;
+            B2 -= nFractBits-1;
+            int common2factor = Math.min( B2, S2 );
+            B2 -= common2factor;
+            S2 -= common2factor;
+            M2 -= common2factor;
+
+            //
+            // HACK!! For exact powers of two, the next smallest number
+            // is only half as far away as we think (because the meaning of
+            // ULP changes at power-of-two bounds) for this reason, we
+            // hack M2. Hope this works.
+            //
+            if ( nFractBits == 1 ) {
+                M2 -= 1;
+            }
+
+            if ( M2 < 0 ){
+                // oops.
+                // since we cannot scale M down far enough,
+                // we must scale the other values up.
+                B2 -= M2;
+                S2 -= M2;
+                M2 =  0;
+            }
+            //
+            // Construct, Scale, iterate.
+            // Some day, we'll write a stopping test that takes
+            // account of the asymmetry of the spacing of floating-point
+            // numbers below perfect powers of 2
+            // 26 Sept 96 is not that day.
+            // So we use a symmetric test.
+            //
+            int ndigit = 0;
+            boolean low, high;
+            long lowDigitDifference;
+            int  q;
+
+            //
+            // Detect the special cases where all the numbers we are about
+            // to compute will fit in int or long integers.
+            // In these cases, we will avoid doing FDBigInteger arithmetic.
+            // We use the same algorithms, except that we "normalize"
+            // our FDBigIntegers before iterating. This is to make division easier,
+            // as it makes our fist guess (quotient of high-order words)
+            // more accurate!
+            //
+            // Some day, we'll write a stopping test that takes
+            // account of the asymmetry of the spacing of floating-point
+            // numbers below perfect powers of 2
+            // 26 Sept 96 is not that day.
+            // So we use a symmetric test.
+            //
+            // binary digits needed to represent B, approx.
+            int Bbits = nFractBits + B2 + (( B5 < N_5_BITS.length )? N_5_BITS[B5] : ( B5*3 ));
+
+            // binary digits needed to represent 10*S, approx.
+            int tenSbits = S2+1 + (( (S5+1) < N_5_BITS.length )? N_5_BITS[(S5+1)] : ( (S5+1)*3 ));
+            if ( Bbits < 64 && tenSbits < 64){
+                if ( Bbits < 32 && tenSbits < 32){
+                    // wa-hoo! They're all ints!
+                    int b = ((int)fractBits * FDBigInteger.SMALL_5_POW[B5] ) << B2;
+                    int s = FDBigInteger.SMALL_5_POW[S5] << S2;
+                    int m = FDBigInteger.SMALL_5_POW[M5] << M2;
+                    int tens = s * 10;
+                    //
+                    // Unroll the first iteration. If our decExp estimate
+                    // was too high, our first quotient will be zero. In this
+                    // case, we discard it and decrement decExp.
+                    //
+                    ndigit = 0;
+                    q = b / s;
+                    b = 10 * ( b % s );
+                    m *= 10;
+                    low  = (b <  m );
+                    high = (b+m > tens );
+                    assert q < 10 : q; // excessively large digit
+                    if ( (q == 0) && ! high ){
+                        // oops. Usually ignore leading zero.
+                        decExp--;
+                    } else {
+                        digits[ndigit++] = (char)('0' + q);
+                    }
+                    //
+                    // HACK! Java spec sez that we always have at least
+                    // one digit after the . in either F- or E-form output.
+                    // Thus we will need more than one digit if we're using
+                    // E-form
+                    //
+                    if ( !isCompatibleFormat ||decExp < -3 || decExp >= 8 ){
+                        high = low = false;
+                    }
+                    while( ! low && ! high ){
+                        q = b / s;
+                        b = 10 * ( b % s );
+                        m *= 10;
+                        assert q < 10 : q; // excessively large digit
+                        if ( m > 0L ){
+                            low  = (b <  m );
+                            high = (b+m > tens );
+                        } else {
+                            // hack -- m might overflow!
+                            // in this case, it is certainly > b,
+                            // which won't
+                            // and b+m > tens, too, since that has overflowed
+                            // either!
+                            low = true;
+                            high = true;
+                        }
+                        digits[ndigit++] = (char)('0' + q);
+                    }
+                    lowDigitDifference = (b<<1) - tens;
+                    exactDecimalConversion  = (b == 0);
+                } else {
+                    // still good! they're all longs!
+                    long b = (fractBits * FDBigInteger.LONG_5_POW[B5] ) << B2;
+                    long s = FDBigInteger.LONG_5_POW[S5] << S2;
+                    long m = FDBigInteger.LONG_5_POW[M5] << M2;
+                    long tens = s * 10L;
+                    //
+                    // Unroll the first iteration. If our decExp estimate
+                    // was too high, our first quotient will be zero. In this
+                    // case, we discard it and decrement decExp.
+                    //
+                    ndigit = 0;
+                    q = (int) ( b / s );
+                    b = 10L * ( b % s );
+                    m *= 10L;
+                    low  = (b <  m );
+                    high = (b+m > tens );
+                    assert q < 10 : q; // excessively large digit
+                    if ( (q == 0) && ! high ){
+                        // oops. Usually ignore leading zero.
+                        decExp--;
+                    } else {
+                        digits[ndigit++] = (char)('0' + q);
+                    }
+                    //
+                    // HACK! Java spec sez that we always have at least
+                    // one digit after the . in either F- or E-form output.
+                    // Thus we will need more than one digit if we're using
+                    // E-form
+                    //
+                    if ( !isCompatibleFormat || decExp < -3 || decExp >= 8 ){
+                        high = low = false;
+                    }
+                    while( ! low && ! high ){
+                        q = (int) ( b / s );
+                        b = 10 * ( b % s );
+                        m *= 10;
+                        assert q < 10 : q;  // excessively large digit
+                        if ( m > 0L ){
+                            low  = (b <  m );
+                            high = (b+m > tens );
+                        } else {
+                            // hack -- m might overflow!
+                            // in this case, it is certainly > b,
+                            // which won't
+                            // and b+m > tens, too, since that has overflowed
+                            // either!
+                            low = true;
+                            high = true;
+                        }
+                        digits[ndigit++] = (char)('0' + q);
+                    }
+                    lowDigitDifference = (b<<1) - tens;
+                    exactDecimalConversion  = (b == 0);
+                }
+            } else {
+                //
+                // We really must do FDBigInteger arithmetic.
+                // Fist, construct our FDBigInteger initial values.
+                //
+                FDBigInteger Sval = FDBigInteger.valueOfPow52(S5, S2);
+                int shiftBias = Sval.getNormalizationBias();
+                Sval = Sval.leftShift(shiftBias); // normalize so that division works better
+
+                FDBigInteger Bval = FDBigInteger.valueOfMulPow52(fractBits, B5, B2 + shiftBias);
+                FDBigInteger Mval = FDBigInteger.valueOfPow52(M5 + 1, M2 + shiftBias + 1);
+
+                FDBigInteger tenSval = FDBigInteger.valueOfPow52(S5 + 1, S2 + shiftBias + 1); //Sval.mult( 10 );
+                //
+                // Unroll the first iteration. If our decExp estimate
+                // was too high, our first quotient will be zero. In this
+                // case, we discard it and decrement decExp.
+                //
+                ndigit = 0;
+                q = Bval.quoRemIteration( Sval );
+                low  = (Bval.cmp( Mval ) < 0);
+                high = tenSval.addAndCmp(Bval,Mval)<=0;
+
+                assert q < 10 : q; // excessively large digit
+                if ( (q == 0) && ! high ){
+                    // oops. Usually ignore leading zero.
+                    decExp--;
+                } else {
+                    digits[ndigit++] = (char)('0' + q);
+                }
+                //
+                // HACK! Java spec sez that we always have at least
+                // one digit after the . in either F- or E-form output.
+                // Thus we will need more than one digit if we're using
+                // E-form
+                //
+                if (!isCompatibleFormat || decExp < -3 || decExp >= 8 ){
+                    high = low = false;
+                }
+                while( ! low && ! high ){
+                    q = Bval.quoRemIteration( Sval );
+                    assert q < 10 : q;  // excessively large digit
+                    Mval = Mval.multBy10(); //Mval = Mval.mult( 10 );
+                    low  = (Bval.cmp( Mval ) < 0);
+                    high = tenSval.addAndCmp(Bval,Mval)<=0;
+                    digits[ndigit++] = (char)('0' + q);
+                }
+                if ( high && low ){
+                    Bval = Bval.leftShift(1);
+                    lowDigitDifference = Bval.cmp(tenSval);
+                } else {
+                    lowDigitDifference = 0L; // this here only for flow analysis!
+                }
+                exactDecimalConversion  = (Bval.cmp( FDBigInteger.ZERO ) == 0);
+            }
+            this.decExponent = decExp+1;
+            this.firstDigitIndex = 0;
+            this.nDigits = ndigit;
+            //
+            // Last digit gets rounded based on stopping condition.
+            //
+            if ( high ){
+                if ( low ){
+                    if ( lowDigitDifference == 0L ){
+                        // it's a tie!
+                        // choose based on which digits we like.
+                        if ( (digits[firstDigitIndex+nDigits-1]&1) != 0 ) {
+                            roundup();
+                        }
+                    } else if ( lowDigitDifference > 0 ){
+                        roundup();
+                    }
+                } else {
+                    roundup();
+                }
+            }
+        }
+
+        // add one to the least significant digit.
+        // in the unlikely event there is a carry out, deal with it.
+        // assert that this will only happen where there
+        // is only one digit, e.g. (float)1e-44 seems to do it.
+        //
+        private void roundup() {
+            int i = (firstDigitIndex + nDigits - 1);
+            int q = digits[i];
+            if (q == '9') {
+                while (q == '9' && i > firstDigitIndex) {
+                    digits[i] = '0';
+                    q = digits[--i];
+                }
+                if (q == '9') {
+                    // carryout! High-order 1, rest 0s, larger exp.
+                    decExponent += 1;
+                    digits[firstDigitIndex] = '1';
+                    return;
+                }
+                // else fall through.
+            }
+            digits[i] = (char) (q + 1);
+            decimalDigitsRoundedUp = true;
+        }
+
+        /**
+         * Estimate decimal exponent. (If it is small-ish,
+         * we could double-check.)
+         *
+         * First, scale the mantissa bits such that 1 <= d2 < 2.
+         * We are then going to estimate
+         *          log10(d2) ~=~  (d2-1.5)/1.5 + log(1.5)
+         * and so we can estimate
+         *      log10(d) ~=~ log10(d2) + binExp * log10(2)
+         * take the floor and call it decExp.
+         */
+        static int estimateDecExp(long fractBits, int binExp) {
+            double d2 = Double.longBitsToDouble( EXP_ONE | ( fractBits & DoubleConsts.SIGNIF_BIT_MASK ) );
+            double d = (d2-1.5D)*0.289529654D + 0.176091259 + (double)binExp * 0.301029995663981;
+            long dBits = Double.doubleToRawLongBits(d);  //can't be NaN here so use raw
+            int exponent = (int)((dBits & DoubleConsts.EXP_BIT_MASK) >> EXP_SHIFT) - DoubleConsts.EXP_BIAS;
+            boolean isNegative = (dBits & DoubleConsts.SIGN_BIT_MASK) != 0; // discover sign
+            if(exponent>=0 && exponent<52) { // hot path
+                long mask   = DoubleConsts.SIGNIF_BIT_MASK >> exponent;
+                int r = (int)(( (dBits&DoubleConsts.SIGNIF_BIT_MASK) | FRACT_HOB )>>(EXP_SHIFT-exponent));
+                return isNegative ? (((mask & dBits) == 0L ) ? -r : -r-1 ) : r;
+            } else if (exponent < 0) {
+                return (((dBits&~DoubleConsts.SIGN_BIT_MASK) == 0) ? 0 :
+                        ( (isNegative) ? -1 : 0) );
+            } else { //if (exponent >= 52)
+                return (int)d;
+            }
+        }
+
+        private static int insignificantDigits(int insignificant) {
+            int i;
+            for ( i = 0; insignificant >= 10L; i++ ) {
+                insignificant /= 10L;
+            }
+            return i;
+        }
+
+        /**
+         * Calculates
+         * <pre>
+         * insignificantDigitsForPow2(v) == insignificantDigits(1L<<v)
+         * </pre>
+         */
+        private static int insignificantDigitsForPow2(int p2) {
+            if(p2>1 && p2 < insignificantDigitsNumber.length) {
+                return insignificantDigitsNumber[p2];
+            }
+            return 0;
+        }
+
+        /**
+         *  If insignificant==(1L << ixd)
+         *  i = insignificantDigitsNumber[idx] is the same as:
+         *  int i;
+         *  for ( i = 0; insignificant >= 10L; i++ )
+         *         insignificant /= 10L;
+         */
+        private static int[] insignificantDigitsNumber = {
+            0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3,
+            4, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7,
+            8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 11, 11, 11,
+            12, 12, 12, 12, 13, 13, 13, 14, 14, 14,
+            15, 15, 15, 15, 16, 16, 16, 17, 17, 17,
+            18, 18, 18, 19
+        };
+
+        // approximately ceil( log2( long5pow[i] ) )
+        private static final int[] N_5_BITS = {
+                0,
+                3,
+                5,
+                7,
+                10,
+                12,
+                14,
+                17,
+                19,
+                21,
+                24,
+                26,
+                28,
+                31,
+                33,
+                35,
+                38,
+                40,
+                42,
+                45,
+                47,
+                49,
+                52,
+                54,
+                56,
+                59,
+                61,
+        };
+
+        private int getChars(char[] result) {
+            assert nDigits <= 19 : nDigits; // generous bound on size of nDigits
+            int i = 0;
+            if (isNegative) {
+                result[0] = '-';
+                i = 1;
+            }
+            if (decExponent > 0 && decExponent < 8) {
+                // print digits.digits.
+                int charLength = Math.min(nDigits, decExponent);
+                System.arraycopy(digits, firstDigitIndex, result, i, charLength);
+                i += charLength;
+                if (charLength < decExponent) {
+                    charLength = decExponent - charLength;
+                    Arrays.fill(result,i,i+charLength,'0');
+                    i += charLength;
+                    result[i++] = '.';
+                    result[i++] = '0';
+                } else {
+                    result[i++] = '.';
+                    if (charLength < nDigits) {
+                        int t = nDigits - charLength;
+                        System.arraycopy(digits, firstDigitIndex+charLength, result, i, t);
+                        i += t;
+                    } else {
+                        result[i++] = '0';
+                    }
+                }
+            } else if (decExponent <= 0 && decExponent > -3) {
+                result[i++] = '0';
+                result[i++] = '.';
+                if (decExponent != 0) {
+                    Arrays.fill(result, i, i-decExponent, '0');
+                    i -= decExponent;
+                }
+                System.arraycopy(digits, firstDigitIndex, result, i, nDigits);
+                i += nDigits;
+            } else {
+                result[i++] = digits[firstDigitIndex];
+                result[i++] = '.';
+                if (nDigits > 1) {
+                    System.arraycopy(digits, firstDigitIndex+1, result, i, nDigits - 1);
+                    i += nDigits - 1;
+                } else {
+                    result[i++] = '0';
+                }
+                result[i++] = 'E';
+                int e;
+                if (decExponent <= 0) {
+                    result[i++] = '-';
+                    e = -decExponent + 1;
+                } else {
+                    e = decExponent - 1;
+                }
+                // decExponent has 1, 2, or 3, digits
+                if (e <= 9) {
+                    result[i++] = (char) (e + '0');
+                } else if (e <= 99) {
+                    result[i++] = (char) (e / 10 + '0');
+                    result[i++] = (char) (e % 10 + '0');
+                } else {
+                    result[i++] = (char) (e / 100 + '0');
+                    e %= 100;
+                    result[i++] = (char) (e / 10 + '0');
+                    result[i++] = (char) (e % 10 + '0');
+                }
+            }
+            return i;
+        }
+
+    }
+
+    private static final ThreadLocal<BinaryToASCIIBuffer> threadLocalBinaryToASCIIBuffer =
+            new ThreadLocal<BinaryToASCIIBuffer>() {
+                @Override
+                protected BinaryToASCIIBuffer initialValue() {
+                    return new BinaryToASCIIBuffer();
+                }
+            };
+
+    private static BinaryToASCIIBuffer getBinaryToASCIIBuffer() {
+        return threadLocalBinaryToASCIIBuffer.get();
+    }
+
+    /**
+     * A converter which can process an ASCII <code>String</code> representation
+     * of a single or double precision floating point value into a
+     * <code>float</code> or a <code>double</code>.
+     */
+    interface ASCIIToBinaryConverter {
+
+        double doubleValue();
+
+        float floatValue();
+
+    }
+
+    /**
+     * A <code>ASCIIToBinaryConverter</code> container for a <code>double</code>.
+     */
+    static class PreparedASCIIToBinaryBuffer implements ASCIIToBinaryConverter {
+        private final double doubleVal;
+        private final float floatVal;
+
+        public PreparedASCIIToBinaryBuffer(double doubleVal, float floatVal) {
+            this.doubleVal = doubleVal;
+            this.floatVal = floatVal;
+        }
+
+        @Override
+        public double doubleValue() {
+            return doubleVal;
+        }
+
+        @Override
+        public float floatValue() {
+            return floatVal;
+        }
+    }
+
+    static final ASCIIToBinaryConverter A2BC_POSITIVE_INFINITY = new PreparedASCIIToBinaryBuffer(Double.POSITIVE_INFINITY, Float.POSITIVE_INFINITY);
+    static final ASCIIToBinaryConverter A2BC_NEGATIVE_INFINITY = new PreparedASCIIToBinaryBuffer(Double.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY);
+    static final ASCIIToBinaryConverter A2BC_NOT_A_NUMBER  = new PreparedASCIIToBinaryBuffer(Double.NaN, Float.NaN);
+    static final ASCIIToBinaryConverter A2BC_POSITIVE_ZERO = new PreparedASCIIToBinaryBuffer(0.0d, 0.0f);
+    static final ASCIIToBinaryConverter A2BC_NEGATIVE_ZERO = new PreparedASCIIToBinaryBuffer(-0.0d, -0.0f);
+
+    /**
+     * A buffered implementation of <code>ASCIIToBinaryConverter</code>.
+     */
+    static class ASCIIToBinaryBuffer implements ASCIIToBinaryConverter {
+        boolean     isNegative;
+        int         decExponent;
+        char        digits[];
+        int         nDigits;
+
+        ASCIIToBinaryBuffer( boolean negSign, int decExponent, char[] digits, int n)
+        {
+            this.isNegative = negSign;
+            this.decExponent = decExponent;
+            this.digits = digits;
+            this.nDigits = n;
+        }
+
+        /**
+         * Takes a FloatingDecimal, which we presumably just scanned in,
+         * and finds out what its value is, as a double.
+         *
+         * AS A SIDE EFFECT, SET roundDir TO INDICATE PREFERRED
+         * ROUNDING DIRECTION in case the result is really destined
+         * for a single-precision float.
+         */
+        @Override
+        public double doubleValue() {
+            int kDigits = Math.min(nDigits, MAX_DECIMAL_DIGITS + 1);
+            //
+            // convert the lead kDigits to a long integer.
+            //
+            // (special performance hack: start to do it using int)
+            int iValue = (int) digits[0] - (int) '0';
+            int iDigits = Math.min(kDigits, INT_DECIMAL_DIGITS);
+            for (int i = 1; i < iDigits; i++) {
+                iValue = iValue * 10 + (int) digits[i] - (int) '0';
+            }
+            long lValue = (long) iValue;
+            for (int i = iDigits; i < kDigits; i++) {
+                lValue = lValue * 10L + (long) ((int) digits[i] - (int) '0');
+            }
+            double dValue = (double) lValue;
+            int exp = decExponent - kDigits;
+            //
+            // lValue now contains a long integer with the value of
+            // the first kDigits digits of the number.
+            // dValue contains the (double) of the same.
+            //
+
+            if (nDigits <= MAX_DECIMAL_DIGITS) {
+                //
+                // possibly an easy case.
+                // We know that the digits can be represented
+                // exactly. And if the exponent isn't too outrageous,
+                // the whole thing can be done with one operation,
+                // thus one rounding error.
+                // Note that all our constructors trim all leading and
+                // trailing zeros, so simple values (including zero)
+                // will always end up here
+                //
+                if (exp == 0 || dValue == 0.0) {
+                    return (isNegative) ? -dValue : dValue; // small floating integer
+                }
+                else if (exp >= 0) {
+                    if (exp <= MAX_SMALL_TEN) {
+                        //
+                        // Can get the answer with one operation,
+                        // thus one roundoff.
+                        //
+                        double rValue = dValue * SMALL_10_POW[exp];
+                        return (isNegative) ? -rValue : rValue;
+                    }
+                    int slop = MAX_DECIMAL_DIGITS - kDigits;
+                    if (exp <= MAX_SMALL_TEN + slop) {
+                        //
+                        // We can multiply dValue by 10^(slop)
+                        // and it is still "small" and exact.
+                        // Then we can multiply by 10^(exp-slop)
+                        // with one rounding.
+                        //
+                        dValue *= SMALL_10_POW[slop];
+                        double rValue = dValue * SMALL_10_POW[exp - slop];
+                        return (isNegative) ? -rValue : rValue;
+                    }
+                    //
+                    // Else we have a hard case with a positive exp.
+                    //
+                } else {
+                    if (exp >= -MAX_SMALL_TEN) {
+                        //
+                        // Can get the answer in one division.
+                        //
+                        double rValue = dValue / SMALL_10_POW[-exp];
+                        return (isNegative) ? -rValue : rValue;
+                    }
+                    //
+                    // Else we have a hard case with a negative exp.
+                    //
+                }
+            }
+
+            //
+            // Harder cases:
+            // The sum of digits plus exponent is greater than
+            // what we think we can do with one error.
+            //
+            // Start by approximating the right answer by,
+            // naively, scaling by powers of 10.
+            //
+            if (exp > 0) {
+                if (decExponent > MAX_DECIMAL_EXPONENT + 1) {
+                    //
+                    // Lets face it. This is going to be
+                    // Infinity. Cut to the chase.
+                    //
+                    return (isNegative) ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
+                }
+                if ((exp & 15) != 0) {
+                    dValue *= SMALL_10_POW[exp & 15];
+                }
+                if ((exp >>= 4) != 0) {
+                    int j;
+                    for (j = 0; exp > 1; j++, exp >>= 1) {
+                        if ((exp & 1) != 0) {
+                            dValue *= BIG_10_POW[j];
+                        }
+                    }
+                    //
+                    // The reason for the weird exp > 1 condition
+                    // in the above loop was so that the last multiply
+                    // would get unrolled. We handle it here.
+                    // It could overflow.
+                    //
+                    double t = dValue * BIG_10_POW[j];
+                    if (Double.isInfinite(t)) {
+                        //
+                        // It did overflow.
+                        // Look more closely at the result.
+                        // If the exponent is just one too large,
+                        // then use the maximum finite as our estimate
+                        // value. Else call the result infinity
+                        // and punt it.
+                        // ( I presume this could happen because
+                        // rounding forces the result here to be
+                        // an ULP or two larger than
+                        // Double.MAX_VALUE ).
+                        //
+                        t = dValue / 2.0;
+                        t *= BIG_10_POW[j];
+                        if (Double.isInfinite(t)) {
+                            return (isNegative) ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
+                        }
+                        t = Double.MAX_VALUE;
+                    }
+                    dValue = t;
+                }
+            } else if (exp < 0) {
+                exp = -exp;
+                if (decExponent < MIN_DECIMAL_EXPONENT - 1) {
+                    //
+                    // Lets face it. This is going to be
+                    // zero. Cut to the chase.
+                    //
+                    return (isNegative) ? -0.0 : 0.0;
+                }
+                if ((exp & 15) != 0) {
+                    dValue /= SMALL_10_POW[exp & 15];
+                }
+                if ((exp >>= 4) != 0) {
+                    int j;
+                    for (j = 0; exp > 1; j++, exp >>= 1) {
+                        if ((exp & 1) != 0) {
+                            dValue *= TINY_10_POW[j];
+                        }
+                    }
+                    //
+                    // The reason for the weird exp > 1 condition
+                    // in the above loop was so that the last multiply
+                    // would get unrolled. We handle it here.
+                    // It could underflow.
+                    //
+                    double t = dValue * TINY_10_POW[j];
+                    if (t == 0.0) {
+                        //
+                        // It did underflow.
+                        // Look more closely at the result.
+                        // If the exponent is just one too small,
+                        // then use the minimum finite as our estimate
+                        // value. Else call the result 0.0
+                        // and punt it.
+                        // ( I presume this could happen because
+                        // rounding forces the result here to be
+                        // an ULP or two less than
+                        // Double.MIN_VALUE ).
+                        //
+                        t = dValue * 2.0;
+                        t *= TINY_10_POW[j];
+                        if (t == 0.0) {
+                            return (isNegative) ? -0.0 : 0.0;
+                        }
+                        t = Double.MIN_VALUE;
+                    }
+                    dValue = t;
+                }
+            }
+
+            //
+            // dValue is now approximately the result.
+            // The hard part is adjusting it, by comparison
+            // with FDBigInteger arithmetic.
+            // Formulate the EXACT big-number result as
+            // bigD0 * 10^exp
+            //
+            if (nDigits > MAX_NDIGITS) {
+                nDigits = MAX_NDIGITS + 1;
+                digits[MAX_NDIGITS] = '1';
+            }
+            FDBigInteger bigD0 = new FDBigInteger(lValue, digits, kDigits, nDigits);
+            exp = decExponent - nDigits;
+
+            long ieeeBits = Double.doubleToRawLongBits(dValue); // IEEE-754 bits of double candidate
+            final int B5 = Math.max(0, -exp); // powers of 5 in bigB, value is not modified inside correctionLoop
+            final int D5 = Math.max(0, exp); // powers of 5 in bigD, value is not modified inside correctionLoop
+            bigD0 = bigD0.multByPow52(D5, 0);
+            bigD0.makeImmutable();   // prevent bigD0 modification inside correctionLoop
+            FDBigInteger bigD = null;
+            int prevD2 = 0;
+
+            correctionLoop:
+            while (true) {
+                // here ieeeBits can't be NaN, Infinity or zero
+                int binexp = (int) (ieeeBits >>> EXP_SHIFT);
+                long bigBbits = ieeeBits & DoubleConsts.SIGNIF_BIT_MASK;
+                if (binexp > 0) {
+                    bigBbits |= FRACT_HOB;
+                } else { // Normalize denormalized numbers.
+                    assert bigBbits != 0L : bigBbits; // doubleToBigInt(0.0)
+                    int leadingZeros = Long.numberOfLeadingZeros(bigBbits);
+                    int shift = leadingZeros - (63 - EXP_SHIFT);
+                    bigBbits <<= shift;
+                    binexp = 1 - shift;
+                }
+                binexp -= DoubleConsts.EXP_BIAS;
+                int lowOrderZeros = Long.numberOfTrailingZeros(bigBbits);
+                bigBbits >>>= lowOrderZeros;
+                final int bigIntExp = binexp - EXP_SHIFT + lowOrderZeros;
+                final int bigIntNBits = EXP_SHIFT + 1 - lowOrderZeros;
+
+                //
+                // Scale bigD, bigB appropriately for
+                // big-integer operations.
+                // Naively, we multiply by powers of ten
+                // and powers of two. What we actually do
+                // is keep track of the powers of 5 and
+                // powers of 2 we would use, then factor out
+                // common divisors before doing the work.
+                //
+                int B2 = B5; // powers of 2 in bigB
+                int D2 = D5; // powers of 2 in bigD
+                int Ulp2;   // powers of 2 in halfUlp.
+                if (bigIntExp >= 0) {
+                    B2 += bigIntExp;
+                } else {
+                    D2 -= bigIntExp;
+                }
+                Ulp2 = B2;
+                // shift bigB and bigD left by a number s. t.
+                // halfUlp is still an integer.
+                int hulpbias;
+                if (binexp <= -DoubleConsts.EXP_BIAS) {
+                    // This is going to be a denormalized number
+                    // (if not actually zero).
+                    // half an ULP is at 2^-(DoubleConsts.EXP_BIAS+EXP_SHIFT+1)
+                    hulpbias = binexp + lowOrderZeros + DoubleConsts.EXP_BIAS;
+                } else {
+                    hulpbias = 1 + lowOrderZeros;
+                }
+                B2 += hulpbias;
+                D2 += hulpbias;
+                // if there are common factors of 2, we might just as well
+                // factor them out, as they add nothing useful.
+                int common2 = Math.min(B2, Math.min(D2, Ulp2));
+                B2 -= common2;
+                D2 -= common2;
+                Ulp2 -= common2;
+                // do multiplications by powers of 5 and 2
+                FDBigInteger bigB = FDBigInteger.valueOfMulPow52(bigBbits, B5, B2);
+                if (bigD == null || prevD2 != D2) {
+                    bigD = bigD0.leftShift(D2);
+                    prevD2 = D2;
+                }
+                //
+                // to recap:
+                // bigB is the scaled-big-int version of our floating-point
+                // candidate.
+                // bigD is the scaled-big-int version of the exact value
+                // as we understand it.
+                // halfUlp is 1/2 an ulp of bigB, except for special cases
+                // of exact powers of 2
+                //
+                // the plan is to compare bigB with bigD, and if the difference
+                // is less than halfUlp, then we're satisfied. Otherwise,
+                // use the ratio of difference to halfUlp to calculate a fudge
+                // factor to add to the floating value, then go 'round again.
+                //
+                FDBigInteger diff;
+                int cmpResult;
+                boolean overvalue;
+                if ((cmpResult = bigB.cmp(bigD)) > 0) {
+                    overvalue = true; // our candidate is too big.
+                    diff = bigB.leftInplaceSub(bigD); // bigB is not user further - reuse
+                    if ((bigIntNBits == 1) && (bigIntExp > -DoubleConsts.EXP_BIAS + 1)) {
+                        // candidate is a normalized exact power of 2 and
+                        // is too big (larger than Double.MIN_NORMAL). We will be subtracting.
+                        // For our purposes, ulp is the ulp of the
+                        // next smaller range.
+                        Ulp2 -= 1;
+                        if (Ulp2 < 0) {
+                            // rats. Cannot de-scale ulp this far.
+                            // must scale diff in other direction.
+                            Ulp2 = 0;
+                            diff = diff.leftShift(1);
+                        }
+                    }
+                } else if (cmpResult < 0) {
+                    overvalue = false; // our candidate is too small.
+                    diff = bigD.rightInplaceSub(bigB); // bigB is not user further - reuse
+                } else {
+                    // the candidate is exactly right!
+                    // this happens with surprising frequency
+                    break correctionLoop;
+                }
+                cmpResult = diff.cmpPow52(B5, Ulp2);
+                if ((cmpResult) < 0) {
+                    // difference is small.
+                    // this is close enough
+                    break correctionLoop;
+                } else if (cmpResult == 0) {
+                    // difference is exactly half an ULP
+                    // round to some other value maybe, then finish
+                    if ((ieeeBits & 1) != 0) { // half ties to even
+                        ieeeBits += overvalue ? -1 : 1; // nextDown or nextUp
+                    }
+                    break correctionLoop;
+                } else {
+                    // difference is non-trivial.
+                    // could scale addend by ratio of difference to
+                    // halfUlp here, if we bothered to compute that difference.
+                    // Most of the time ( I hope ) it is about 1 anyway.
+                    ieeeBits += overvalue ? -1 : 1; // nextDown or nextUp
+                    if (ieeeBits == 0 || ieeeBits == DoubleConsts.EXP_BIT_MASK) { // 0.0 or Double.POSITIVE_INFINITY
+                        break correctionLoop; // oops. Fell off end of range.
+                    }
+                    continue; // try again.
+                }
+
+            }
+            if (isNegative) {
+                ieeeBits |= DoubleConsts.SIGN_BIT_MASK;
+            }
+            return Double.longBitsToDouble(ieeeBits);
+        }
+
+        /**
+         * Takes a FloatingDecimal, which we presumably just scanned in,
+         * and finds out what its value is, as a float.
+         * This is distinct from doubleValue() to avoid the extremely
+         * unlikely case of a double rounding error, wherein the conversion
+         * to double has one rounding error, and the conversion of that double
+         * to a float has another rounding error, IN THE WRONG DIRECTION,
+         * ( because of the preference to a zero low-order bit ).
+         */
+        @Override
+        public float floatValue() {
+            int kDigits = Math.min(nDigits, SINGLE_MAX_DECIMAL_DIGITS + 1);
+            //
+            // convert the lead kDigits to an integer.
+            //
+            int iValue = (int) digits[0] - (int) '0';
+            for (int i = 1; i < kDigits; i++) {
+                iValue = iValue * 10 + (int) digits[i] - (int) '0';
+            }
+            float fValue = (float) iValue;
+            int exp = decExponent - kDigits;
+            //
+            // iValue now contains an integer with the value of
+            // the first kDigits digits of the number.
+            // fValue contains the (float) of the same.
+            //
+
+            if (nDigits <= SINGLE_MAX_DECIMAL_DIGITS) {
+                //
+                // possibly an easy case.
+                // We know that the digits can be represented
+                // exactly. And if the exponent isn't too outrageous,
+                // the whole thing can be done with one operation,
+                // thus one rounding error.
+                // Note that all our constructors trim all leading and
+                // trailing zeros, so simple values (including zero)
+                // will always end up here.
+                //
+                if (exp == 0 || fValue == 0.0f) {
+                    return (isNegative) ? -fValue : fValue; // small floating integer
+                } else if (exp >= 0) {
+                    if (exp <= SINGLE_MAX_SMALL_TEN) {
+                        //
+                        // Can get the answer with one operation,
+                        // thus one roundoff.
+                        //
+                        fValue *= SINGLE_SMALL_10_POW[exp];
+                        return (isNegative) ? -fValue : fValue;
+                    }
+                    int slop = SINGLE_MAX_DECIMAL_DIGITS - kDigits;
+                    if (exp <= SINGLE_MAX_SMALL_TEN + slop) {
+                        //
+                        // We can multiply fValue by 10^(slop)
+                        // and it is still "small" and exact.
+                        // Then we can multiply by 10^(exp-slop)
+                        // with one rounding.
+                        //
+                        fValue *= SINGLE_SMALL_10_POW[slop];
+                        fValue *= SINGLE_SMALL_10_POW[exp - slop];
+                        return (isNegative) ? -fValue : fValue;
+                    }
+                    //
+                    // Else we have a hard case with a positive exp.
+                    //
+                } else {
+                    if (exp >= -SINGLE_MAX_SMALL_TEN) {
+                        //
+                        // Can get the answer in one division.
+                        //
+                        fValue /= SINGLE_SMALL_10_POW[-exp];
+                        return (isNegative) ? -fValue : fValue;
+                    }
+                    //
+                    // Else we have a hard case with a negative exp.
+                    //
+                }
+            } else if ((decExponent >= nDigits) && (nDigits + decExponent <= MAX_DECIMAL_DIGITS)) {
+                //
+                // In double-precision, this is an exact floating integer.
+                // So we can compute to double, then shorten to float
+                // with one round, and get the right answer.
+                //
+                // First, finish accumulating digits.
+                // Then convert that integer to a double, multiply
+                // by the appropriate power of ten, and convert to float.
+                //
+                long lValue = (long) iValue;
+                for (int i = kDigits; i < nDigits; i++) {
+                    lValue = lValue * 10L + (long) ((int) digits[i] - (int) '0');
+                }
+                double dValue = (double) lValue;
+                exp = decExponent - nDigits;
+                dValue *= SMALL_10_POW[exp];
+                fValue = (float) dValue;
+                return (isNegative) ? -fValue : fValue;
+
+            }
+            //
+            // Harder cases:
+            // The sum of digits plus exponent is greater than
+            // what we think we can do with one error.
+            //
+            // Start by approximating the right answer by,
+            // naively, scaling by powers of 10.
+            // Scaling uses doubles to avoid overflow/underflow.
+            //
+            double dValue = fValue;
+            if (exp > 0) {
+                if (decExponent > SINGLE_MAX_DECIMAL_EXPONENT + 1) {
+                    //
+                    // Lets face it. This is going to be
+                    // Infinity. Cut to the chase.
+                    //
+                    return (isNegative) ? Float.NEGATIVE_INFINITY : Float.POSITIVE_INFINITY;
+                }
+                if ((exp & 15) != 0) {
+                    dValue *= SMALL_10_POW[exp & 15];
+                }
+                if ((exp >>= 4) != 0) {
+                    int j;
+                    for (j = 0; exp > 0; j++, exp >>= 1) {
+                        if ((exp & 1) != 0) {
+                            dValue *= BIG_10_POW[j];
+                        }
+                    }
+                }
+            } else if (exp < 0) {
+                exp = -exp;
+                if (decExponent < SINGLE_MIN_DECIMAL_EXPONENT - 1) {
+                    //
+                    // Lets face it. This is going to be
+                    // zero. Cut to the chase.
+                    //
+                    return (isNegative) ? -0.0f : 0.0f;
+                }
+                if ((exp & 15) != 0) {
+                    dValue /= SMALL_10_POW[exp & 15];
+                }
+                if ((exp >>= 4) != 0) {
+                    int j;
+                    for (j = 0; exp > 0; j++, exp >>= 1) {
+                        if ((exp & 1) != 0) {
+                            dValue *= TINY_10_POW[j];
+                        }
+                    }
+                }
+            }
+            fValue = Math.max(Float.MIN_VALUE, Math.min(Float.MAX_VALUE, (float) dValue));
+
+            //
+            // fValue is now approximately the result.
+            // The hard part is adjusting it, by comparison
+            // with FDBigInteger arithmetic.
+            // Formulate the EXACT big-number result as
+            // bigD0 * 10^exp
+            //
+            if (nDigits > SINGLE_MAX_NDIGITS) {
+                nDigits = SINGLE_MAX_NDIGITS + 1;
+                digits[SINGLE_MAX_NDIGITS] = '1';
+            }
+            FDBigInteger bigD0 = new FDBigInteger(iValue, digits, kDigits, nDigits);
+            exp = decExponent - nDigits;
+
+            int ieeeBits = Float.floatToRawIntBits(fValue); // IEEE-754 bits of float candidate
+            final int B5 = Math.max(0, -exp); // powers of 5 in bigB, value is not modified inside correctionLoop
+            final int D5 = Math.max(0, exp); // powers of 5 in bigD, value is not modified inside correctionLoop
+            bigD0 = bigD0.multByPow52(D5, 0);
+            bigD0.makeImmutable();   // prevent bigD0 modification inside correctionLoop
+            FDBigInteger bigD = null;
+            int prevD2 = 0;
+
+            correctionLoop:
+            while (true) {
+                // here ieeeBits can't be NaN, Infinity or zero
+                int binexp = ieeeBits >>> SINGLE_EXP_SHIFT;
+                int bigBbits = ieeeBits & FloatConsts.SIGNIF_BIT_MASK;
+                if (binexp > 0) {
+                    bigBbits |= SINGLE_FRACT_HOB;
+                } else { // Normalize denormalized numbers.
+                    assert bigBbits != 0 : bigBbits; // floatToBigInt(0.0)
+                    int leadingZeros = Integer.numberOfLeadingZeros(bigBbits);
+                    int shift = leadingZeros - (31 - SINGLE_EXP_SHIFT);
+                    bigBbits <<= shift;
+                    binexp = 1 - shift;
+                }
+                binexp -= FloatConsts.EXP_BIAS;
+                int lowOrderZeros = Integer.numberOfTrailingZeros(bigBbits);
+                bigBbits >>>= lowOrderZeros;
+                final int bigIntExp = binexp - SINGLE_EXP_SHIFT + lowOrderZeros;
+                final int bigIntNBits = SINGLE_EXP_SHIFT + 1 - lowOrderZeros;
+
+                //
+                // Scale bigD, bigB appropriately for
+                // big-integer operations.
+                // Naively, we multiply by powers of ten
+                // and powers of two. What we actually do
+                // is keep track of the powers of 5 and
+                // powers of 2 we would use, then factor out
+                // common divisors before doing the work.
+                //
+                int B2 = B5; // powers of 2 in bigB
+                int D2 = D5; // powers of 2 in bigD
+                int Ulp2;   // powers of 2 in halfUlp.
+                if (bigIntExp >= 0) {
+                    B2 += bigIntExp;
+                } else {
+                    D2 -= bigIntExp;
+                }
+                Ulp2 = B2;
+                // shift bigB and bigD left by a number s. t.
+                // halfUlp is still an integer.
+                int hulpbias;
+                if (binexp <= -FloatConsts.EXP_BIAS) {
+                    // This is going to be a denormalized number
+                    // (if not actually zero).
+                    // half an ULP is at 2^-(FloatConsts.EXP_BIAS+SINGLE_EXP_SHIFT+1)
+                    hulpbias = binexp + lowOrderZeros + FloatConsts.EXP_BIAS;
+                } else {
+                    hulpbias = 1 + lowOrderZeros;
+                }
+                B2 += hulpbias;
+                D2 += hulpbias;
+                // if there are common factors of 2, we might just as well
+                // factor them out, as they add nothing useful.
+                int common2 = Math.min(B2, Math.min(D2, Ulp2));
+                B2 -= common2;
+                D2 -= common2;
+                Ulp2 -= common2;
+                // do multiplications by powers of 5 and 2
+                FDBigInteger bigB = FDBigInteger.valueOfMulPow52(bigBbits, B5, B2);
+                if (bigD == null || prevD2 != D2) {
+                    bigD = bigD0.leftShift(D2);
+                    prevD2 = D2;
+                }
+                //
+                // to recap:
+                // bigB is the scaled-big-int version of our floating-point
+                // candidate.
+                // bigD is the scaled-big-int version of the exact value
+                // as we understand it.
+                // halfUlp is 1/2 an ulp of bigB, except for special cases
+                // of exact powers of 2
+                //
+                // the plan is to compare bigB with bigD, and if the difference
+                // is less than halfUlp, then we're satisfied. Otherwise,
+                // use the ratio of difference to halfUlp to calculate a fudge
+                // factor to add to the floating value, then go 'round again.
+                //
+                FDBigInteger diff;
+                int cmpResult;
+                boolean overvalue;
+                if ((cmpResult = bigB.cmp(bigD)) > 0) {
+                    overvalue = true; // our candidate is too big.
+                    diff = bigB.leftInplaceSub(bigD); // bigB is not user further - reuse
+                    if ((bigIntNBits == 1) && (bigIntExp > -FloatConsts.EXP_BIAS + 1)) {
+                        // candidate is a normalized exact power of 2 and
+                        // is too big (larger than Float.MIN_NORMAL). We will be subtracting.
+                        // For our purposes, ulp is the ulp of the
+                        // next smaller range.
+                        Ulp2 -= 1;
+                        if (Ulp2 < 0) {
+                            // rats. Cannot de-scale ulp this far.
+                            // must scale diff in other direction.
+                            Ulp2 = 0;
+                            diff = diff.leftShift(1);
+                        }
+                    }
+                } else if (cmpResult < 0) {
+                    overvalue = false; // our candidate is too small.
+                    diff = bigD.rightInplaceSub(bigB); // bigB is not user further - reuse
+                } else {
+                    // the candidate is exactly right!
+                    // this happens with surprising frequency
+                    break correctionLoop;
+                }
+                cmpResult = diff.cmpPow52(B5, Ulp2);
+                if ((cmpResult) < 0) {
+                    // difference is small.
+                    // this is close enough
+                    break correctionLoop;
+                } else if (cmpResult == 0) {
+                    // difference is exactly half an ULP
+                    // round to some other value maybe, then finish
+                    if ((ieeeBits & 1) != 0) { // half ties to even
+                        ieeeBits += overvalue ? -1 : 1; // nextDown or nextUp
+                    }
+                    break correctionLoop;
+                } else {
+                    // difference is non-trivial.
+                    // could scale addend by ratio of difference to
+                    // halfUlp here, if we bothered to compute that difference.
+                    // Most of the time ( I hope ) it is about 1 anyway.
+                    ieeeBits += overvalue ? -1 : 1; // nextDown or nextUp
+                    if (ieeeBits == 0 || ieeeBits == FloatConsts.EXP_BIT_MASK) { // 0.0 or Float.POSITIVE_INFINITY
+                        break correctionLoop; // oops. Fell off end of range.
+                    }
+                    continue; // try again.
+                }
+
+            }
+            if (isNegative) {
+                ieeeBits |= FloatConsts.SIGN_BIT_MASK;
+            }
+            return Float.intBitsToFloat(ieeeBits);
+        }
+
+
+        /**
+         * All the positive powers of 10 that can be
+         * represented exactly in double/float.
+         */
+        private static final double[] SMALL_10_POW = {
+            1.0e0,
+            1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5,
+            1.0e6, 1.0e7, 1.0e8, 1.0e9, 1.0e10,
+            1.0e11, 1.0e12, 1.0e13, 1.0e14, 1.0e15,
+            1.0e16, 1.0e17, 1.0e18, 1.0e19, 1.0e20,
+            1.0e21, 1.0e22
+        };
+
+        private static final float[] SINGLE_SMALL_10_POW = {
+            1.0e0f,
+            1.0e1f, 1.0e2f, 1.0e3f, 1.0e4f, 1.0e5f,
+            1.0e6f, 1.0e7f, 1.0e8f, 1.0e9f, 1.0e10f
+        };
+
+        private static final double[] BIG_10_POW = {
+            1e16, 1e32, 1e64, 1e128, 1e256 };
+        private static final double[] TINY_10_POW = {
+            1e-16, 1e-32, 1e-64, 1e-128, 1e-256 };
+
+        private static final int MAX_SMALL_TEN = SMALL_10_POW.length-1;
+        private static final int SINGLE_MAX_SMALL_TEN = SINGLE_SMALL_10_POW.length-1;
+
+    }
+
+    /**
+     * Returns a <code>BinaryToASCIIConverter</code> for a <code>double</code>.
+     * The returned object is a <code>ThreadLocal</code> variable of this class.
+     *
+     * @param d The double precision value to convert.
+     * @return The converter.
+     */
+    public static BinaryToASCIIConverter getBinaryToASCIIConverter(double d) {
+        return getBinaryToASCIIConverter(d, true);
+    }
+
+    /**
+     * Returns a <code>BinaryToASCIIConverter</code> for a <code>double</code>.
+     * The returned object is a <code>ThreadLocal</code> variable of this class.
+     *
+     * @param d The double precision value to convert.
+     * @param isCompatibleFormat
+     * @return The converter.
+     */
+    static BinaryToASCIIConverter getBinaryToASCIIConverter(double d, boolean isCompatibleFormat) {
+        long dBits = Double.doubleToRawLongBits(d);
+        boolean isNegative = (dBits&DoubleConsts.SIGN_BIT_MASK) != 0; // discover sign
+        long fractBits = dBits & DoubleConsts.SIGNIF_BIT_MASK;
+        int  binExp = (int)( (dBits&DoubleConsts.EXP_BIT_MASK) >> EXP_SHIFT );
+        // Discover obvious special cases of NaN and Infinity.
+        if ( binExp == (int)(DoubleConsts.EXP_BIT_MASK>>EXP_SHIFT) ) {
+            if ( fractBits == 0L ){
+                return isNegative ? B2AC_NEGATIVE_INFINITY : B2AC_POSITIVE_INFINITY;
+            } else {
+                return B2AC_NOT_A_NUMBER;
+            }
+        }
+        // Finish unpacking
+        // Normalize denormalized numbers.
+        // Insert assumed high-order bit for normalized numbers.
+        // Subtract exponent bias.
+        int  nSignificantBits;
+        if ( binExp == 0 ){
+            if ( fractBits == 0L ){
+                // not a denorm, just a 0!
+                return isNegative ? B2AC_NEGATIVE_ZERO : B2AC_POSITIVE_ZERO;
+            }
+            int leadingZeros = Long.numberOfLeadingZeros(fractBits);
+            int shift = leadingZeros-(63-EXP_SHIFT);
+            fractBits <<= shift;
+            binExp = 1 - shift;
+            nSignificantBits =  64-leadingZeros; // recall binExp is  - shift count.
+        } else {
+            fractBits |= FRACT_HOB;
+            nSignificantBits = EXP_SHIFT+1;
+        }
+        binExp -= DoubleConsts.EXP_BIAS;
+        BinaryToASCIIBuffer buf = getBinaryToASCIIBuffer();
+        buf.setSign(isNegative);
+        // call the routine that actually does all the hard work.
+        buf.dtoa(binExp, fractBits, nSignificantBits, isCompatibleFormat);
+        return buf;
+    }
+
+    private static BinaryToASCIIConverter getBinaryToASCIIConverter(float f) {
+        int fBits = Float.floatToRawIntBits( f );
+        boolean isNegative = (fBits&FloatConsts.SIGN_BIT_MASK) != 0;
+        int fractBits = fBits&FloatConsts.SIGNIF_BIT_MASK;
+        int binExp = (fBits&FloatConsts.EXP_BIT_MASK) >> SINGLE_EXP_SHIFT;
+        // Discover obvious special cases of NaN and Infinity.
+        if ( binExp == (FloatConsts.EXP_BIT_MASK>>SINGLE_EXP_SHIFT) ) {
+            if ( fractBits == 0L ){
+                return isNegative ? B2AC_NEGATIVE_INFINITY : B2AC_POSITIVE_INFINITY;
+            } else {
+                return B2AC_NOT_A_NUMBER;
+            }
+        }
+        // Finish unpacking
+        // Normalize denormalized numbers.
+        // Insert assumed high-order bit for normalized numbers.
+        // Subtract exponent bias.
+        int  nSignificantBits;
+        if ( binExp == 0 ){
+            if ( fractBits == 0 ){
+                // not a denorm, just a 0!
+                return isNegative ? B2AC_NEGATIVE_ZERO : B2AC_POSITIVE_ZERO;
+            }
+            int leadingZeros = Integer.numberOfLeadingZeros(fractBits);
+            int shift = leadingZeros-(31-SINGLE_EXP_SHIFT);
+            fractBits <<= shift;
+            binExp = 1 - shift;
+            nSignificantBits =  32 - leadingZeros; // recall binExp is  - shift count.
+        } else {
+            fractBits |= SINGLE_FRACT_HOB;
+            nSignificantBits = SINGLE_EXP_SHIFT+1;
+        }
+        binExp -= FloatConsts.EXP_BIAS;
+        BinaryToASCIIBuffer buf = getBinaryToASCIIBuffer();
+        buf.setSign(isNegative);
+        // call the routine that actually does all the hard work.
+        buf.dtoa(binExp, ((long)fractBits)<<(EXP_SHIFT-SINGLE_EXP_SHIFT), nSignificantBits, true);
+        return buf;
+    }
+
+    @SuppressWarnings("fallthrough")
+    static ASCIIToBinaryConverter readJavaFormatString( String in ) throws NumberFormatException {
+        boolean isNegative = false;
+        boolean signSeen   = false;
+        int     decExp;
+        char    c;
+
+    parseNumber:
+        try{
+            in = in.trim(); // don't fool around with white space.
+                            // throws NullPointerException if null
+            int len = in.length();
+            if ( len == 0 ) {
+                throw new NumberFormatException("empty String");
+            }
+            int i = 0;
+            switch (in.charAt(i)){
+            case '-':
+                isNegative = true;
+                //FALLTHROUGH
+            case '+':
+                i++;
+                signSeen = true;
+            }
+            c = in.charAt(i);
+            if(c == 'N') { // Check for NaN
+                if((len-i)==NAN_LENGTH && in.indexOf(NAN_REP,i)==i) {
+                    return A2BC_NOT_A_NUMBER;
+                }
+                // something went wrong, throw exception
+                break parseNumber;
+            } else if(c == 'I') { // Check for Infinity strings
+                if((len-i)==INFINITY_LENGTH && in.indexOf(INFINITY_REP,i)==i) {
+                    return isNegative? A2BC_NEGATIVE_INFINITY : A2BC_POSITIVE_INFINITY;
+                }
+                // something went wrong, throw exception
+                break parseNumber;
+            } else if (c == '0')  { // check for hexadecimal floating-point number
+                if (len > i+1 ) {
+                    char ch = in.charAt(i+1);
+                    if (ch == 'x' || ch == 'X' ) { // possible hex string
+                        return parseHexString(in);
+                    }
+                }
+            }  // look for and process decimal floating-point string
+
+            char[] digits = new char[ len ];
+            int    nDigits= 0;
+            boolean decSeen = false;
+            int decPt = 0;
+            int nLeadZero = 0;
+            int nTrailZero= 0;
+
+        skipLeadingZerosLoop:
+            while (i < len) {
+                c = in.charAt(i);
+                if (c == '0') {
+                    nLeadZero++;
+                } else if (c == '.') {
+                    if (decSeen) {
+                        // already saw one ., this is the 2nd.
+                        throw new NumberFormatException("multiple points");
+                    }
+                    decPt = i;
+                    if (signSeen) {
+                        decPt -= 1;
+                    }
+                    decSeen = true;
+                } else {
+                    break skipLeadingZerosLoop;
+                }
+                i++;
+            }
+        digitLoop:
+            while (i < len) {
+                c = in.charAt(i);
+                if (c >= '1' && c <= '9') {
+                    digits[nDigits++] = c;
+                    nTrailZero = 0;
+                } else if (c == '0') {
+                    digits[nDigits++] = c;
+                    nTrailZero++;
+                } else if (c == '.') {
+                    if (decSeen) {
+                        // already saw one ., this is the 2nd.
+                        throw new NumberFormatException("multiple points");
+                    }
+                    decPt = i;
+                    if (signSeen) {
+                        decPt -= 1;
+                    }
+                    decSeen = true;
+                } else {
+                    break digitLoop;
+                }
+                i++;
+            }
+            nDigits -=nTrailZero;
+            //
+            // At this point, we've scanned all the digits and decimal
+            // point we're going to see. Trim off leading and trailing
+            // zeros, which will just confuse us later, and adjust
+            // our initial decimal exponent accordingly.
+            // To review:
+            // we have seen i total characters.
+            // nLeadZero of them were zeros before any other digits.
+            // nTrailZero of them were zeros after any other digits.
+            // if ( decSeen ), then a . was seen after decPt characters
+            // ( including leading zeros which have been discarded )
+            // nDigits characters were neither lead nor trailing
+            // zeros, nor point
+            //
+            //
+            // special hack: if we saw no non-zero digits, then the
+            // answer is zero!
+            // Unfortunately, we feel honor-bound to keep parsing!
+            //
+            boolean isZero = (nDigits == 0);
+            if ( isZero &&  nLeadZero == 0 ){
+                // we saw NO DIGITS AT ALL,
+                // not even a crummy 0!
+                // this is not allowed.
+                break parseNumber; // go throw exception
+            }
+            //
+            // Our initial exponent is decPt, adjusted by the number of
+            // discarded zeros. Or, if there was no decPt,
+            // then its just nDigits adjusted by discarded trailing zeros.
+            //
+            if ( decSeen ){
+                decExp = decPt - nLeadZero;
+            } else {
+                decExp = nDigits + nTrailZero;
+            }
+
+            //
+            // Look for 'e' or 'E' and an optionally signed integer.
+            //
+            if ( (i < len) &&  (((c = in.charAt(i) )=='e') || (c == 'E') ) ){
+                int expSign = 1;
+                int expVal  = 0;
+                int reallyBig = Integer.MAX_VALUE / 10;
+                boolean expOverflow = false;
+                switch( in.charAt(++i) ){
+                case '-':
+                    expSign = -1;
+                    //FALLTHROUGH
+                case '+':
+                    i++;
+                }
+                int expAt = i;
+            expLoop:
+                while ( i < len  ){
+                    if ( expVal >= reallyBig ){
+                        // the next character will cause integer
+                        // overflow.
+                        expOverflow = true;
+                    }
+                    c = in.charAt(i++);
+                    if(c>='0' && c<='9') {
+                        expVal = expVal*10 + ( (int)c - (int)'0' );
+                    } else {
+                        i--;           // back up.
+                        break expLoop; // stop parsing exponent.
+                    }
+                }
+                int expLimit = BIG_DECIMAL_EXPONENT + nDigits + nTrailZero;
+                if (expOverflow || (expVal > expLimit)) {
+                    // There is still a chance that the exponent will be safe to
+                    // use: if it would eventually decrease due to a negative
+                    // decExp, and that number is below the limit.  We check for
+                    // that here.
+                    if (!expOverflow && (expSign == 1 && decExp < 0)
+                            && (expVal + decExp) < expLimit) {
+                        // Cannot overflow: adding a positive and negative number.
+                        decExp += expVal;
+                    } else {
+                        //
+                        // The intent here is to end up with
+                        // infinity or zero, as appropriate.
+                        // The reason for yielding such a small decExponent,
+                        // rather than something intuitive such as
+                        // expSign*Integer.MAX_VALUE, is that this value
+                        // is subject to further manipulation in
+                        // doubleValue() and floatValue(), and I don't want
+                        // it to be able to cause overflow there!
+                        // (The only way we can get into trouble here is for
+                        // really outrageous nDigits+nTrailZero, such as 2
+                        // billion.)
+                        //
+                        decExp = expSign * expLimit;
+                    }
+                } else {
+                    // this should not overflow, since we tested
+                    // for expVal > (MAX+N), where N >= abs(decExp)
+                    decExp = decExp + expSign*expVal;
+                }
+
+                // if we saw something not a digit ( or end of string )
+                // after the [Ee][+-], without seeing any digits at all
+                // this is certainly an error. If we saw some digits,
+                // but then some trailing garbage, that might be ok.
+                // so we just fall through in that case.
+                // HUMBUG
+                if ( i == expAt ) {
+                    break parseNumber; // certainly bad
+                }
+            }
+            //
+            // We parsed everything we could.
+            // If there are leftovers, then this is not good input!
+            //
+            if ( i < len &&
+                ((i != len - 1) ||
+                (in.charAt(i) != 'f' &&
+                 in.charAt(i) != 'F' &&
+                 in.charAt(i) != 'd' &&
+                 in.charAt(i) != 'D'))) {
+                break parseNumber; // go throw exception
+            }
+            if(isZero) {
+                return isNegative ? A2BC_NEGATIVE_ZERO : A2BC_POSITIVE_ZERO;
+            }
+            return new ASCIIToBinaryBuffer(isNegative, decExp, digits, nDigits);
+        } catch ( StringIndexOutOfBoundsException e ){ }
+        throw new NumberFormatException("For input string: \"" + in + "\"");
+    }
+
+    private static class HexFloatPattern {
+        /**
+         * Grammar is compatible with hexadecimal floating-point constants
+         * described in section 6.4.4.2 of the C99 specification.
+         */
+        private static final Pattern VALUE = Pattern.compile(
+                   //1           234                   56                7                   8      9
+                    "([-+])?0[xX](((\\p{XDigit}+)\\.?)|((\\p{XDigit}*)\\.(\\p{XDigit}+)))[pP]([-+])?(\\p{Digit}+)[fFdD]?"
+                    );
+    }
+
+    /**
+     * Converts string s to a suitable floating decimal; uses the
+     * double constructor and sets the roundDir variable appropriately
+     * in case the value is later converted to a float.
+     *
+     * @param s The <code>String</code> to parse.
+     */
+   static ASCIIToBinaryConverter parseHexString(String s) {
+            // Verify string is a member of the hexadecimal floating-point
+            // string language.
+            Matcher m = HexFloatPattern.VALUE.matcher(s);
+            boolean validInput = m.matches();
+            if (!validInput) {
+                // Input does not match pattern
+                throw new NumberFormatException("For input string: \"" + s + "\"");
+            } else { // validInput
+                //
+                // We must isolate the sign, significand, and exponent
+                // fields.  The sign value is straightforward.  Since
+                // floating-point numbers are stored with a normalized
+                // representation, the significand and exponent are
+                // interrelated.
+                //
+                // After extracting the sign, we normalized the
+                // significand as a hexadecimal value, calculating an
+                // exponent adjust for any shifts made during
+                // normalization.  If the significand is zero, the
+                // exponent doesn't need to be examined since the output
+                // will be zero.
+                //
+                // Next the exponent in the input string is extracted.
+                // Afterwards, the significand is normalized as a *binary*
+                // value and the input value's normalized exponent can be
+                // computed.  The significand bits are copied into a
+                // double significand; if the string has more logical bits
+                // than can fit in a double, the extra bits affect the
+                // round and sticky bits which are used to round the final
+                // value.
+                //
+                //  Extract significand sign
+                String group1 = m.group(1);
+                boolean isNegative = ((group1 != null) && group1.equals("-"));
+
+                //  Extract Significand magnitude
+                //
+                // Based on the form of the significand, calculate how the
+                // binary exponent needs to be adjusted to create a
+                // normalized//hexadecimal* floating-point number; that
+                // is, a number where there is one nonzero hex digit to
+                // the left of the (hexa)decimal point.  Since we are
+                // adjusting a binary, not hexadecimal exponent, the
+                // exponent is adjusted by a multiple of 4.
+                //
+                // There are a number of significand scenarios to consider;
+                // letters are used in indicate nonzero digits:
+                //
+                // 1. 000xxxx       =>      x.xxx   normalized
+                //    increase exponent by (number of x's - 1)*4
+                //
+                // 2. 000xxx.yyyy =>        x.xxyyyy        normalized
+                //    increase exponent by (number of x's - 1)*4
+                //
+                // 3. .000yyy  =>   y.yy    normalized
+                //    decrease exponent by (number of zeros + 1)*4
+                //
+                // 4. 000.00000yyy => y.yy normalized
+                //    decrease exponent by (number of zeros to right of point + 1)*4
+                //
+                // If the significand is exactly zero, return a properly
+                // signed zero.
+                //
+
+                String significandString = null;
+                int signifLength = 0;
+                int exponentAdjust = 0;
+                {
+                    int leftDigits = 0; // number of meaningful digits to
+                    // left of "decimal" point
+                    // (leading zeros stripped)
+                    int rightDigits = 0; // number of digits to right of
+                    // "decimal" point; leading zeros
+                    // must always be accounted for
+                    //
+                    // The significand is made up of either
+                    //
+                    // 1. group 4 entirely (integer portion only)
+                    //
+                    // OR
+                    //
+                    // 2. the fractional portion from group 7 plus any
+                    // (optional) integer portions from group 6.
+                    //
+                    String group4;
+                    if ((group4 = m.group(4)) != null) {  // Integer-only significand
+                        // Leading zeros never matter on the integer portion
+                        significandString = stripLeadingZeros(group4);
+                        leftDigits = significandString.length();
+                    } else {
+                        // Group 6 is the optional integer; leading zeros
+                        // never matter on the integer portion
+                        String group6 = stripLeadingZeros(m.group(6));
+                        leftDigits = group6.length();
+
+                        // fraction
+                        String group7 = m.group(7);
+                        rightDigits = group7.length();
+
+                        // Turn "integer.fraction" into "integer"+"fraction"
+                        significandString =
+                                ((group6 == null) ? "" : group6) + // is the null
+                                        // check necessary?
+                                        group7;
+                    }
+
+                    significandString = stripLeadingZeros(significandString);
+                    signifLength = significandString.length();
+
+                    //
+                    // Adjust exponent as described above
+                    //
+                    if (leftDigits >= 1) {  // Cases 1 and 2
+                        exponentAdjust = 4 * (leftDigits - 1);
+                    } else {                // Cases 3 and 4
+                        exponentAdjust = -4 * (rightDigits - signifLength + 1);
+                    }
+
+                    // If the significand is zero, the exponent doesn't
+                    // matter; return a properly signed zero.
+
+                    if (signifLength == 0) { // Only zeros in input
+                        return isNegative ? A2BC_NEGATIVE_ZERO : A2BC_POSITIVE_ZERO;
+                    }
+                }
+
+                //  Extract Exponent
+                //
+                // Use an int to read in the exponent value; this should
+                // provide more than sufficient range for non-contrived
+                // inputs.  If reading the exponent in as an int does
+                // overflow, examine the sign of the exponent and
+                // significand to determine what to do.
+                //
+                String group8 = m.group(8);
+                boolean positiveExponent = (group8 == null) || group8.equals("+");
+                long unsignedRawExponent;
+                try {
+                    unsignedRawExponent = Integer.parseInt(m.group(9));
+                }
+                catch (NumberFormatException e) {
+                    // At this point, we know the exponent is
+                    // syntactically well-formed as a sequence of
+                    // digits.  Therefore, if an NumberFormatException
+                    // is thrown, it must be due to overflowing int's
+                    // range.  Also, at this point, we have already
+                    // checked for a zero significand.  Thus the signs
+                    // of the exponent and significand determine the
+                    // final result:
+                    //
+                    //                      significand
+                    //                      +               -
+                    // exponent     +       +infinity       -infinity
+                    //              -       +0.0            -0.0
+                    return isNegative ?
+                              (positiveExponent ? A2BC_NEGATIVE_INFINITY : A2BC_NEGATIVE_ZERO)
+                            : (positiveExponent ? A2BC_POSITIVE_INFINITY : A2BC_POSITIVE_ZERO);
+
+                }
+
+                long rawExponent =
+                        (positiveExponent ? 1L : -1L) * // exponent sign
+                                unsignedRawExponent;            // exponent magnitude
+
+                // Calculate partially adjusted exponent
+                long exponent = rawExponent + exponentAdjust;
+
+                // Starting copying non-zero bits into proper position in
+                // a long; copy explicit bit too; this will be masked
+                // later for normal values.
+
+                boolean round = false;
+                boolean sticky = false;
+                int nextShift = 0;
+                long significand = 0L;
+                // First iteration is different, since we only copy
+                // from the leading significand bit; one more exponent
+                // adjust will be needed...
+
+                // IMPORTANT: make leadingDigit a long to avoid
+                // surprising shift semantics!
+                long leadingDigit = getHexDigit(significandString, 0);
+
+                //
+                // Left shift the leading digit (53 - (bit position of
+                // leading 1 in digit)); this sets the top bit of the
+                // significand to 1.  The nextShift value is adjusted
+                // to take into account the number of bit positions of
+                // the leadingDigit actually used.  Finally, the
+                // exponent is adjusted to normalize the significand
+                // as a binary value, not just a hex value.
+                //
+                if (leadingDigit == 1) {
+                    significand |= leadingDigit << 52;
+                    nextShift = 52 - 4;
+                    // exponent += 0
+                } else if (leadingDigit <= 3) { // [2, 3]
+                    significand |= leadingDigit << 51;
+                    nextShift = 52 - 5;
+                    exponent += 1;
+                } else if (leadingDigit <= 7) { // [4, 7]
+                    significand |= leadingDigit << 50;
+                    nextShift = 52 - 6;
+                    exponent += 2;
+                } else if (leadingDigit <= 15) { // [8, f]
+                    significand |= leadingDigit << 49;
+                    nextShift = 52 - 7;
+                    exponent += 3;
+                } else {
+                    throw new AssertionError("Result from digit conversion too large!");
+                }
+                // The preceding if-else could be replaced by a single
+                // code block based on the high-order bit set in
+                // leadingDigit.  Given leadingOnePosition,
+
+                // significand |= leadingDigit << (SIGNIFICAND_WIDTH - leadingOnePosition);
+                // nextShift = 52 - (3 + leadingOnePosition);
+                // exponent += (leadingOnePosition-1);
+
+                //
+                // Now the exponent variable is equal to the normalized
+                // binary exponent.  Code below will make representation
+                // adjustments if the exponent is incremented after
+                // rounding (includes overflows to infinity) or if the
+                // result is subnormal.
+                //
+
+                // Copy digit into significand until the significand can't
+                // hold another full hex digit or there are no more input
+                // hex digits.
+                int i = 0;
+                for (i = 1;
+                     i < signifLength && nextShift >= 0;
+                     i++) {
+                    long currentDigit = getHexDigit(significandString, i);
+                    significand |= (currentDigit << nextShift);
+                    nextShift -= 4;
+                }
+
+                // After the above loop, the bulk of the string is copied.
+                // Now, we must copy any partial hex digits into the
+                // significand AND compute the round bit and start computing
+                // sticky bit.
+
+                if (i < signifLength) { // at least one hex input digit exists
+                    long currentDigit = getHexDigit(significandString, i);
+
+                    // from nextShift, figure out how many bits need
+                    // to be copied, if any
+                    switch (nextShift) { // must be negative
+                        case -1:
+                            // three bits need to be copied in; can
+                            // set round bit
+                            significand |= ((currentDigit & 0xEL) >> 1);
+                            round = (currentDigit & 0x1L) != 0L;
+                            break;
+
+                        case -2:
+                            // two bits need to be copied in; can
+                            // set round and start sticky
+                            significand |= ((currentDigit & 0xCL) >> 2);
+                            round = (currentDigit & 0x2L) != 0L;
+                            sticky = (currentDigit & 0x1L) != 0;
+                            break;
+
+                        case -3:
+                            // one bit needs to be copied in
+                            significand |= ((currentDigit & 0x8L) >> 3);
+                            // Now set round and start sticky, if possible
+                            round = (currentDigit & 0x4L) != 0L;
+                            sticky = (currentDigit & 0x3L) != 0;
+                            break;
+
+                        case -4:
+                            // all bits copied into significand; set
+                            // round and start sticky
+                            round = ((currentDigit & 0x8L) != 0);  // is top bit set?
+                            // nonzeros in three low order bits?
+                            sticky = (currentDigit & 0x7L) != 0;
+                            break;
+
+                        default:
+                            throw new AssertionError("Unexpected shift distance remainder.");
+                            // break;
+                    }
+
+                    // Round is set; sticky might be set.
+
+                    // For the sticky bit, it suffices to check the
+                    // current digit and test for any nonzero digits in
+                    // the remaining unprocessed input.
+                    i++;
+                    while (i < signifLength && !sticky) {
+                        currentDigit = getHexDigit(significandString, i);
+                        sticky = sticky || (currentDigit != 0);
+                        i++;
+                    }
+
+                }
+                // else all of string was seen, round and sticky are
+                // correct as false.
+
+                // Float calculations
+                int floatBits = isNegative ? FloatConsts.SIGN_BIT_MASK : 0;
+                if (exponent >= FloatConsts.MIN_EXPONENT) {
+                    if (exponent > FloatConsts.MAX_EXPONENT) {
+                        // Float.POSITIVE_INFINITY
+                        floatBits |= FloatConsts.EXP_BIT_MASK;
+                    } else {
+                        int threshShift = DoubleConsts.SIGNIFICAND_WIDTH - FloatConsts.SIGNIFICAND_WIDTH - 1;
+                        boolean floatSticky = (significand & ((1L << threshShift) - 1)) != 0 || round || sticky;
+                        int iValue = (int) (significand >>> threshShift);
+                        if ((iValue & 3) != 1 || floatSticky) {
+                            iValue++;
+                        }
+                        floatBits |= (((((int) exponent) + (FloatConsts.EXP_BIAS - 1))) << SINGLE_EXP_SHIFT) + (iValue >> 1);
+                    }
+                } else {
+                    if (exponent < FloatConsts.MIN_SUB_EXPONENT - 1) {
+                        // 0
+                    } else {
+                        // exponent == -127 ==> threshShift = 53 - 2 + (-149) - (-127) = 53 - 24
+                        int threshShift = (int) ((DoubleConsts.SIGNIFICAND_WIDTH - 2 + FloatConsts.MIN_SUB_EXPONENT) - exponent);
+                        assert threshShift >= DoubleConsts.SIGNIFICAND_WIDTH - FloatConsts.SIGNIFICAND_WIDTH;
+                        assert threshShift < DoubleConsts.SIGNIFICAND_WIDTH;
+                        boolean floatSticky = (significand & ((1L << threshShift) - 1)) != 0 || round || sticky;
+                        int iValue = (int) (significand >>> threshShift);
+                        if ((iValue & 3) != 1 || floatSticky) {
+                            iValue++;
+                        }
+                        floatBits |= iValue >> 1;
+                    }
+                }
+                float fValue = Float.intBitsToFloat(floatBits);
+
+                // Check for overflow and update exponent accordingly.
+                if (exponent > DoubleConsts.MAX_EXPONENT) {         // Infinite result
+                    // overflow to properly signed infinity
+                    return isNegative ? A2BC_NEGATIVE_INFINITY : A2BC_POSITIVE_INFINITY;
+                } else {  // Finite return value
+                    if (exponent <= DoubleConsts.MAX_EXPONENT && // (Usually) normal result
+                            exponent >= DoubleConsts.MIN_EXPONENT) {
+
+                        // The result returned in this block cannot be a
+                        // zero or subnormal; however after the
+                        // significand is adjusted from rounding, we could
+                        // still overflow in infinity.
+
+                        // AND exponent bits into significand; if the
+                        // significand is incremented and overflows from
+                        // rounding, this combination will update the
+                        // exponent correctly, even in the case of
+                        // Double.MAX_VALUE overflowing to infinity.
+
+                        significand = ((( exponent +
+                                (long) DoubleConsts.EXP_BIAS) <<
+                                (DoubleConsts.SIGNIFICAND_WIDTH - 1))
+                                & DoubleConsts.EXP_BIT_MASK) |
+                                (DoubleConsts.SIGNIF_BIT_MASK & significand);
+
+                    } else {  // Subnormal or zero
+                        // (exponent < DoubleConsts.MIN_EXPONENT)
+
+                        if (exponent < (DoubleConsts.MIN_SUB_EXPONENT - 1)) {
+                            // No way to round back to nonzero value
+                            // regardless of significand if the exponent is
+                            // less than -1075.
+                            return isNegative ? A2BC_NEGATIVE_ZERO : A2BC_POSITIVE_ZERO;
+                        } else { //  -1075 <= exponent <= MIN_EXPONENT -1 = -1023
+                            //
+                            // Find bit position to round to; recompute
+                            // round and sticky bits, and shift
+                            // significand right appropriately.
+                            //
+
+                            sticky = sticky || round;
+                            round = false;
+
+                            // Number of bits of significand to preserve is
+                            // exponent - abs_min_exp +1
+                            // check:
+                            // -1075 +1074 + 1 = 0
+                            // -1023 +1074 + 1 = 52
+
+                            int bitsDiscarded = 53 -
+                                    ((int) exponent - DoubleConsts.MIN_SUB_EXPONENT + 1);
+                            assert bitsDiscarded >= 1 && bitsDiscarded <= 53;
+
+                            // What to do here:
+                            // First, isolate the new round bit
+                            round = (significand & (1L << (bitsDiscarded - 1))) != 0L;
+                            if (bitsDiscarded > 1) {
+                                // create mask to update sticky bits; low
+                                // order bitsDiscarded bits should be 1
+                                long mask = ~((~0L) << (bitsDiscarded - 1));
+                                sticky = sticky || ((significand & mask) != 0L);
+                            }
+
+                            // Now, discard the bits
+                            significand = significand >> bitsDiscarded;
+
+                            significand = ((((long) (DoubleConsts.MIN_EXPONENT - 1) + // subnorm exp.
+                                    (long) DoubleConsts.EXP_BIAS) <<
+                                    (DoubleConsts.SIGNIFICAND_WIDTH - 1))
+                                    & DoubleConsts.EXP_BIT_MASK) |
+                                    (DoubleConsts.SIGNIF_BIT_MASK & significand);
+                        }
+                    }
+
+                    // The significand variable now contains the currently
+                    // appropriate exponent bits too.
+
+                    //
+                    // Determine if significand should be incremented;
+                    // making this determination depends on the least
+                    // significant bit and the round and sticky bits.
+                    //
+                    // Round to nearest even rounding table, adapted from
+                    // table 4.7 in "Computer Arithmetic" by IsraelKoren.
+                    // The digit to the left of the "decimal" point is the
+                    // least significant bit, the digits to the right of
+                    // the point are the round and sticky bits
+                    //
+                    // Number       Round(x)
+                    // x0.00        x0.
+                    // x0.01        x0.
+                    // x0.10        x0.
+                    // x0.11        x1. = x0. +1
+                    // x1.00        x1.
+                    // x1.01        x1.
+                    // x1.10        x1. + 1
+                    // x1.11        x1. + 1
+                    //
+                    boolean leastZero = ((significand & 1L) == 0L);
+                    if ((leastZero && round && sticky) ||
+                            ((!leastZero) && round)) {
+                        significand++;
+                    }
+
+                    double value = isNegative ?
+                            Double.longBitsToDouble(significand | DoubleConsts.SIGN_BIT_MASK) :
+                            Double.longBitsToDouble(significand );
+
+                    return new PreparedASCIIToBinaryBuffer(value, fValue);
+                }
+            }
+    }
+
+    /**
+     * Returns <code>s</code> with any leading zeros removed.
+     */
+    static String stripLeadingZeros(String s) {
+//        return  s.replaceFirst("^0+", "");
+        if(!s.isEmpty() && s.charAt(0)=='0') {
+            for(int i=1; i<s.length(); i++) {
+                if(s.charAt(i)!='0') {
+                    return s.substring(i);
+                }
+            }
+            return "";
+        }
+        return s;
+    }
+
+    /**
+     * Extracts a hexadecimal digit from position <code>position</code>
+     * of string <code>s</code>.
+     */
+    static int getHexDigit(String s, int position) {
+        int value = Character.digit(s.charAt(position), 16);
+        if (value <= -1 || value >= 16) {
+            throw new AssertionError("Unexpected failure of digit conversion of " +
+                                     s.charAt(position));
+        }
+        return value;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/math/FormattedFloatingDecimal.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,349 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.math;
+
+import java.util.Arrays;
+
+public class FormattedFloatingDecimal{
+
+    public enum Form { SCIENTIFIC, COMPATIBLE, DECIMAL_FLOAT, GENERAL };
+
+
+    public static FormattedFloatingDecimal valueOf(double d, int precision, Form form){
+        FloatingDecimal.BinaryToASCIIConverter fdConverter =
+                FloatingDecimal.getBinaryToASCIIConverter(d, form == Form.COMPATIBLE);
+        return new FormattedFloatingDecimal(precision,form, fdConverter);
+    }
+
+    private int decExponentRounded;
+    private char[] mantissa;
+    private char[] exponent;
+
+    private static final ThreadLocal<Object> threadLocalCharBuffer =
+            new ThreadLocal<Object>() {
+                @Override
+                protected Object initialValue() {
+                    return new char[20];
+                }
+            };
+
+    private static char[] getBuffer(){
+        return (char[]) threadLocalCharBuffer.get();
+    }
+
+    private FormattedFloatingDecimal(int precision, Form form, FloatingDecimal.BinaryToASCIIConverter fdConverter) {
+        if (fdConverter.isExceptional()) {
+            this.mantissa = fdConverter.toJavaFormatString().toCharArray();
+            this.exponent = null;
+            return;
+        }
+        char[] digits = getBuffer();
+        int nDigits = fdConverter.getDigits(digits);
+        int decExp = fdConverter.getDecimalExponent();
+        int exp;
+        boolean isNegative = fdConverter.isNegative();
+        switch (form) {
+            case COMPATIBLE:
+                exp = decExp;
+                this.decExponentRounded = exp;
+                fillCompatible(precision, digits, nDigits, exp, isNegative);
+                break;
+            case DECIMAL_FLOAT:
+                exp = applyPrecision(decExp, digits, nDigits, decExp + precision);
+                fillDecimal(precision, digits, nDigits, exp, isNegative);
+                this.decExponentRounded = exp;
+                break;
+            case SCIENTIFIC:
+                exp = applyPrecision(decExp, digits, nDigits, precision + 1);
+                fillScientific(precision, digits, nDigits, exp, isNegative);
+                this.decExponentRounded = exp;
+                break;
+            case GENERAL:
+                exp = applyPrecision(decExp, digits, nDigits, precision);
+                // adjust precision to be the number of digits to right of decimal
+                // the real exponent to be output is actually exp - 1, not exp
+                if (exp - 1 < -4 || exp - 1 >= precision) {
+                    // form = Form.SCIENTIFIC;
+                    precision--;
+                    fillScientific(precision, digits, nDigits, exp, isNegative);
+                } else {
+                    // form = Form.DECIMAL_FLOAT;
+                    precision = precision - exp;
+                    fillDecimal(precision, digits, nDigits, exp, isNegative);
+                }
+                this.decExponentRounded = exp;
+                break;
+            default:
+                assert false;
+        }
+    }
+
+    // returns the exponent after rounding has been done by applyPrecision
+    public int getExponentRounded() {
+        return decExponentRounded - 1;
+    }
+
+    public char[] getMantissa(){
+        return mantissa;
+    }
+
+    public char[] getExponent(){
+        return exponent;
+    }
+
+    /**
+     * Returns new decExp in case of overflow.
+     */
+    private static int applyPrecision(int decExp, char[] digits, int nDigits, int prec) {
+        if (prec >= nDigits || prec < 0) {
+            // no rounding necessary
+            return decExp;
+        }
+        if (prec == 0) {
+            // only one digit (0 or 1) is returned because the precision
+            // excludes all significant digits
+            if (digits[0] >= '5') {
+                digits[0] = '1';
+                Arrays.fill(digits, 1, nDigits, '0');
+                return decExp + 1;
+            } else {
+                Arrays.fill(digits, 0, nDigits, '0');
+                return decExp;
+            }
+        }
+        int q = digits[prec];
+        if (q >= '5') {
+            int i = prec;
+            q = digits[--i];
+            if ( q == '9' ) {
+                while ( q == '9' && i > 0 ){
+                    q = digits[--i];
+                }
+                if ( q == '9' ){
+                    // carryout! High-order 1, rest 0s, larger exp.
+                    digits[0] = '1';
+                    Arrays.fill(digits, 1, nDigits, '0');
+                    return decExp+1;
+                }
+            }
+            digits[i] = (char)(q + 1);
+            Arrays.fill(digits, i+1, nDigits, '0');
+        } else {
+            Arrays.fill(digits, prec, nDigits, '0');
+        }
+        return decExp;
+    }
+
+    /**
+     * Fills mantissa and exponent char arrays for compatible format.
+     */
+    private void fillCompatible(int precision, char[] digits, int nDigits, int exp, boolean isNegative) {
+        int startIndex = isNegative ? 1 : 0;
+        if (exp > 0 && exp < 8) {
+            // print digits.digits.
+            if (nDigits < exp) {
+                int extraZeros = exp - nDigits;
+                mantissa = create(isNegative, nDigits + extraZeros + 2);
+                System.arraycopy(digits, 0, mantissa, startIndex, nDigits);
+                Arrays.fill(mantissa, startIndex + nDigits, startIndex + nDigits + extraZeros, '0');
+                mantissa[startIndex + nDigits + extraZeros] = '.';
+                mantissa[startIndex + nDigits + extraZeros+1] = '0';
+            } else if (exp < nDigits) {
+                int t = Math.min(nDigits - exp, precision);
+                mantissa = create(isNegative, exp + 1 + t);
+                System.arraycopy(digits, 0, mantissa, startIndex, exp);
+                mantissa[startIndex + exp ] = '.';
+                System.arraycopy(digits, exp, mantissa, startIndex+exp+1, t);
+            } else { // exp == digits.length
+                mantissa = create(isNegative, nDigits + 2);
+                System.arraycopy(digits, 0, mantissa, startIndex, nDigits);
+                mantissa[startIndex + nDigits ] = '.';
+                mantissa[startIndex + nDigits +1] = '0';
+            }
+        } else if (exp <= 0 && exp > -3) {
+            int zeros = Math.max(0, Math.min(-exp, precision));
+            int t = Math.max(0, Math.min(nDigits, precision + exp));
+            // write '0' s before the significant digits
+            if (zeros > 0) {
+                mantissa = create(isNegative, zeros + 2 + t);
+                mantissa[startIndex] = '0';
+                mantissa[startIndex+1] = '.';
+                Arrays.fill(mantissa, startIndex + 2, startIndex + 2 + zeros, '0');
+                if (t > 0) {
+                    // copy only when significant digits are within the precision
+                    System.arraycopy(digits, 0, mantissa, startIndex + 2 + zeros, t);
+                }
+            } else if (t > 0) {
+                mantissa = create(isNegative, zeros + 2 + t);
+                mantissa[startIndex] = '0';
+                mantissa[startIndex + 1] = '.';
+                // copy only when significant digits are within the precision
+                System.arraycopy(digits, 0, mantissa, startIndex + 2, t);
+            } else {
+                this.mantissa = create(isNegative, 1);
+                this.mantissa[startIndex] = '0';
+            }
+        } else {
+            if (nDigits > 1) {
+                mantissa = create(isNegative, nDigits + 1);
+                mantissa[startIndex] = digits[0];
+                mantissa[startIndex + 1] = '.';
+                System.arraycopy(digits, 1, mantissa, startIndex + 2, nDigits - 1);
+            } else {
+                mantissa = create(isNegative, 3);
+                mantissa[startIndex] = digits[0];
+                mantissa[startIndex + 1] = '.';
+                mantissa[startIndex + 2] = '0';
+            }
+            int e, expStartIntex;
+            boolean isNegExp = (exp <= 0);
+            if (isNegExp) {
+                e = -exp + 1;
+                expStartIntex = 1;
+            } else {
+                e = exp - 1;
+                expStartIntex = 0;
+            }
+            // decExponent has 1, 2, or 3, digits
+            if (e <= 9) {
+                exponent = create(isNegExp,1);
+                exponent[expStartIntex] = (char) (e + '0');
+            } else if (e <= 99) {
+                exponent = create(isNegExp,2);
+                exponent[expStartIntex] = (char) (e / 10 + '0');
+                exponent[expStartIntex+1] = (char) (e % 10 + '0');
+            } else {
+                exponent = create(isNegExp,3);
+                exponent[expStartIntex] = (char) (e / 100 + '0');
+                e %= 100;
+                exponent[expStartIntex+1] = (char) (e / 10 + '0');
+                exponent[expStartIntex+2] = (char) (e % 10 + '0');
+            }
+        }
+    }
+
+    private static char[] create(boolean isNegative, int size) {
+        if(isNegative) {
+            char[] r = new char[size +1];
+            r[0] = '-';
+            return r;
+        } else {
+            return new char[size];
+        }
+    }
+
+    /*
+     * Fills mantissa char arrays for DECIMAL_FLOAT format.
+     * Exponent should be equal to null.
+     */
+    private void fillDecimal(int precision, char[] digits, int nDigits, int exp, boolean isNegative) {
+        int startIndex = isNegative ? 1 : 0;
+        if (exp > 0) {
+            // print digits.digits.
+            if (nDigits < exp) {
+                mantissa = create(isNegative,exp);
+                System.arraycopy(digits, 0, mantissa, startIndex, nDigits);
+                Arrays.fill(mantissa, startIndex + nDigits, startIndex + exp, '0');
+                // Do not append ".0" for formatted floats since the user
+                // may request that it be omitted. It is added as necessary
+                // by the Formatter.
+            } else {
+                int t = Math.min(nDigits - exp, precision);
+                mantissa = create(isNegative, exp + (t > 0 ? (t + 1) : 0));
+                System.arraycopy(digits, 0, mantissa, startIndex, exp);
+                // Do not append ".0" for formatted floats since the user
+                // may request that it be omitted. It is added as necessary
+                // by the Formatter.
+                if (t > 0) {
+                    mantissa[startIndex + exp] = '.';
+                    System.arraycopy(digits, exp, mantissa, startIndex + exp + 1, t);
+                }
+            }
+        } else if (exp <= 0) {
+            int zeros = Math.max(0, Math.min(-exp, precision));
+            int t = Math.max(0, Math.min(nDigits, precision + exp));
+            // write '0' s before the significant digits
+            if (zeros > 0) {
+                mantissa = create(isNegative, zeros + 2 + t);
+                mantissa[startIndex] = '0';
+                mantissa[startIndex+1] = '.';
+                Arrays.fill(mantissa, startIndex + 2, startIndex + 2 + zeros, '0');
+                if (t > 0) {
+                    // copy only when significant digits are within the precision
+                    System.arraycopy(digits, 0, mantissa, startIndex + 2 + zeros, t);
+                }
+            } else if (t > 0) {
+                mantissa = create(isNegative, zeros + 2 + t);
+                mantissa[startIndex] = '0';
+                mantissa[startIndex + 1] = '.';
+                // copy only when significant digits are within the precision
+                System.arraycopy(digits, 0, mantissa, startIndex + 2, t);
+            } else {
+                this.mantissa = create(isNegative, 1);
+                this.mantissa[startIndex] = '0';
+            }
+        }
+    }
+
+    /**
+     * Fills mantissa and exponent char arrays for SCIENTIFIC format.
+     */
+    private void fillScientific(int precision, char[] digits, int nDigits, int exp, boolean isNegative) {
+        int startIndex = isNegative ? 1 : 0;
+        int t = Math.max(0, Math.min(nDigits - 1, precision));
+        if (t > 0) {
+            mantissa = create(isNegative, t + 2);
+            mantissa[startIndex] = digits[0];
+            mantissa[startIndex + 1] = '.';
+            System.arraycopy(digits, 1, mantissa, startIndex + 2, t);
+        } else {
+            mantissa = create(isNegative, 1);
+            mantissa[startIndex] = digits[0];
+        }
+        char expSign;
+        int e;
+        if (exp <= 0) {
+            expSign = '-';
+            e = -exp + 1;
+        } else {
+            expSign = '+' ;
+            e = exp - 1;
+        }
+        // decExponent has 1, 2, or 3, digits
+        if (e <= 9) {
+            exponent = new char[] { expSign,
+                    '0', (char) (e + '0') };
+        } else if (e <= 99) {
+            exponent = new char[] { expSign,
+                    (char) (e / 10 + '0'), (char) (e % 10 + '0') };
+        } else {
+            char hiExpChar = (char) (e / 100 + '0');
+            e %= 100;
+            exponent = new char[] { expSign,
+                    hiExpChar, (char) (e / 10 + '0'), (char) (e % 10 + '0') };
+        }
+    }
+}
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/CleanerImpl.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/CleanerImpl.java	Wed Jul 05 21:10:50 2017 +0200
@@ -39,7 +39,6 @@
 import java.util.function.Function;
 
 import sun.misc.InnocuousThread;
-import sun.misc.ManagedLocalsThread;
 
 /**
  * CleanerImpl manages a set of object references and corresponding cleaning actions.
@@ -130,8 +129,8 @@
      */
     public void run() {
         Thread t = Thread.currentThread();
-        ManagedLocalsThread mlThread = (t instanceof ManagedLocalsThread)
-                ? (ManagedLocalsThread) t
+        InnocuousThread mlThread = (t instanceof InnocuousThread)
+                ? (InnocuousThread) t
                 : null;
         while (!phantomCleanableList.isListEmpty() ||
                 !weakCleanableList.isListEmpty() ||
@@ -787,4 +786,3 @@
     }
 
 }
-
--- a/jdk/src/java.base/share/classes/sun/misc/CompoundEnumeration.java	Thu Dec 24 10:33:21 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.misc;
-
-import java.util.Enumeration;
-import java.util.NoSuchElementException;
-
-/*
- * A useful utility class that will enumerate over an array of
- * enumerations.
- */
-public class CompoundEnumeration<E> implements Enumeration<E> {
-    private Enumeration<E>[] enums;
-    private int index = 0;
-
-    public CompoundEnumeration(Enumeration<E>[] enums) {
-        this.enums = enums;
-    }
-
-    private boolean next() {
-        while (index < enums.length) {
-            if (enums[index] != null && enums[index].hasMoreElements()) {
-                return true;
-            }
-            index++;
-        }
-        return false;
-    }
-
-    public boolean hasMoreElements() {
-        return next();
-    }
-
-    public E nextElement() {
-        if (!next()) {
-            throw new NoSuchElementException();
-        }
-        return enums[index].nextElement();
-    }
-}
--- a/jdk/src/java.base/share/classes/sun/misc/DoubleConsts.java	Thu Dec 24 10:33:21 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,115 +0,0 @@
-/*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.misc;
-
-/**
- * This class contains additional constants documenting limits of the
- * <code>double</code> type.
- *
- * @author Joseph D. Darcy
- */
-
-public class DoubleConsts {
-    /**
-     * Don't let anyone instantiate this class.
-     */
-    private DoubleConsts() {}
-
-    public static final double POSITIVE_INFINITY = java.lang.Double.POSITIVE_INFINITY;
-    public static final double NEGATIVE_INFINITY = java.lang.Double.NEGATIVE_INFINITY;
-    public static final double NaN = java.lang.Double.NaN;
-    public static final double MAX_VALUE = java.lang.Double.MAX_VALUE;
-    public static final double MIN_VALUE = java.lang.Double.MIN_VALUE;
-
-    /**
-     * A constant holding the smallest positive normal value of type
-     * <code>double</code>, 2<sup>-1022</sup>.  It is equal to the
-     * value returned by
-     * <code>Double.longBitsToDouble(0x0010000000000000L)</code>.
-     *
-     * @since 1.5
-     */
-    public static final double  MIN_NORMAL      = 2.2250738585072014E-308;
-
-
-    /**
-     * The number of logical bits in the significand of a
-     * <code>double</code> number, including the implicit bit.
-     */
-    public static final int SIGNIFICAND_WIDTH   = 53;
-
-    /**
-     * Maximum exponent a finite <code>double</code> number may have.
-     * It is equal to the value returned by
-     * <code>Math.ilogb(Double.MAX_VALUE)</code>.
-     */
-    public static final int     MAX_EXPONENT    = 1023;
-
-    /**
-     * Minimum exponent a normalized <code>double</code> number may
-     * have.  It is equal to the value returned by
-     * <code>Math.ilogb(Double.MIN_NORMAL)</code>.
-     */
-    public static final int     MIN_EXPONENT    = -1022;
-
-    /**
-     * The exponent the smallest positive <code>double</code>
-     * subnormal value would have if it could be normalized..
-     */
-    public static final int     MIN_SUB_EXPONENT = MIN_EXPONENT -
-                                                   (SIGNIFICAND_WIDTH - 1);
-
-    /**
-     * Bias used in representing a <code>double</code> exponent.
-     */
-    public static final int     EXP_BIAS        = 1023;
-
-    /**
-     * Bit mask to isolate the sign bit of a <code>double</code>.
-     */
-    public static final long    SIGN_BIT_MASK   = 0x8000000000000000L;
-
-    /**
-     * Bit mask to isolate the exponent field of a
-     * <code>double</code>.
-     */
-    public static final long    EXP_BIT_MASK    = 0x7FF0000000000000L;
-
-    /**
-     * Bit mask to isolate the significand field of a
-     * <code>double</code>.
-     */
-    public static final long    SIGNIF_BIT_MASK = 0x000FFFFFFFFFFFFFL;
-
-    static {
-        // verify bit masks cover all bit positions and that the bit
-        // masks are non-overlapping
-        assert(((SIGN_BIT_MASK | EXP_BIT_MASK | SIGNIF_BIT_MASK) == ~0L) &&
-               (((SIGN_BIT_MASK & EXP_BIT_MASK) == 0L) &&
-                ((SIGN_BIT_MASK & SIGNIF_BIT_MASK) == 0L) &&
-                ((EXP_BIT_MASK & SIGNIF_BIT_MASK) == 0L)));
-    }
-}
--- a/jdk/src/java.base/share/classes/sun/misc/FDBigInteger.java	Thu Dec 24 10:33:21 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1508 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package sun.misc;
-
-import java.math.BigInteger;
-import java.util.Arrays;
-//@ model import org.jmlspecs.models.JMLMath;
-
-/**
- * A simple big integer package specifically for floating point base conversion.
- */
-public /*@ spec_bigint_math @*/ class FDBigInteger {
-
-    //
-    // This class contains many comments that start with "/*@" mark.
-    // They are behavourial specification in
-    // the Java Modelling Language (JML):
-    // http://www.eecs.ucf.edu/~leavens/JML//index.shtml
-    //
-
-    /*@
-    @ public pure model static \bigint UNSIGNED(int v) {
-    @     return v >= 0 ? v : v + (((\bigint)1) << 32);
-    @ }
-    @
-    @ public pure model static \bigint UNSIGNED(long v) {
-    @     return v >= 0 ? v : v + (((\bigint)1) << 64);
-    @ }
-    @
-    @ public pure model static \bigint AP(int[] data, int len) {
-    @     return (\sum int i; 0 <= 0 && i < len; UNSIGNED(data[i]) << (i*32));
-    @ }
-    @
-    @ public pure model static \bigint pow52(int p5, int p2) {
-    @     ghost \bigint v = 1;
-    @     for (int i = 0; i < p5; i++) v *= 5;
-    @     return v << p2;
-    @ }
-    @
-    @ public pure model static \bigint pow10(int p10) {
-    @     return pow52(p10, p10);
-    @ }
-    @*/
-
-    static final int[] SMALL_5_POW = {
-            1,
-            5,
-            5 * 5,
-            5 * 5 * 5,
-            5 * 5 * 5 * 5,
-            5 * 5 * 5 * 5 * 5,
-            5 * 5 * 5 * 5 * 5 * 5,
-            5 * 5 * 5 * 5 * 5 * 5 * 5,
-            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5
-    };
-
-    static final long[] LONG_5_POW = {
-            1L,
-            5L,
-            5L * 5,
-            5L * 5 * 5,
-            5L * 5 * 5 * 5,
-            5L * 5 * 5 * 5 * 5,
-            5L * 5 * 5 * 5 * 5 * 5,
-            5L * 5 * 5 * 5 * 5 * 5 * 5,
-            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
-    };
-
-    // Maximum size of cache of powers of 5 as FDBigIntegers.
-    private static final int MAX_FIVE_POW = 340;
-
-    // Cache of big powers of 5 as FDBigIntegers.
-    private static final FDBigInteger POW_5_CACHE[];
-
-    // Initialize FDBigInteger cache of powers of 5.
-    static {
-        POW_5_CACHE = new FDBigInteger[MAX_FIVE_POW];
-        int i = 0;
-        while (i < SMALL_5_POW.length) {
-            FDBigInteger pow5 = new FDBigInteger(new int[]{SMALL_5_POW[i]}, 0);
-            pow5.makeImmutable();
-            POW_5_CACHE[i] = pow5;
-            i++;
-        }
-        FDBigInteger prev = POW_5_CACHE[i - 1];
-        while (i < MAX_FIVE_POW) {
-            POW_5_CACHE[i] = prev = prev.mult(5);
-            prev.makeImmutable();
-            i++;
-        }
-    }
-
-    // Zero as an FDBigInteger.
-    public static final FDBigInteger ZERO = new FDBigInteger(new int[0], 0);
-
-    // Ensure ZERO is immutable.
-    static {
-        ZERO.makeImmutable();
-    }
-
-    // Constant for casting an int to a long via bitwise AND.
-    private static final long LONG_MASK = 0xffffffffL;
-
-    //@ spec_public non_null;
-    private int data[];  // value: data[0] is least significant
-    //@ spec_public;
-    private int offset;  // number of least significant zero padding ints
-    //@ spec_public;
-    private int nWords;  // data[nWords-1]!=0, all values above are zero
-                 // if nWords==0 -> this FDBigInteger is zero
-    //@ spec_public;
-    private boolean isImmutable = false;
-
-    /*@
-     @ public invariant 0 <= nWords && nWords <= data.length && offset >= 0;
-     @ public invariant nWords == 0 ==> offset == 0;
-     @ public invariant nWords > 0 ==> data[nWords - 1] != 0;
-     @ public invariant (\forall int i; nWords <= i && i < data.length; data[i] == 0);
-     @ public pure model \bigint value() {
-     @     return AP(data, nWords) << (offset*32);
-     @ }
-     @*/
-
-    /**
-     * Constructs an <code>FDBigInteger</code> from data and padding. The
-     * <code>data</code> parameter has the least significant <code>int</code> at
-     * the zeroth index. The <code>offset</code> parameter gives the number of
-     * zero <code>int</code>s to be inferred below the least significant element
-     * of <code>data</code>.
-     *
-     * @param data An array containing all non-zero <code>int</code>s of the value.
-     * @param offset An offset indicating the number of zero <code>int</code>s to pad
-     * below the least significant element of <code>data</code>.
-     */
-    /*@
-     @ requires data != null && offset >= 0;
-     @ ensures this.value() == \old(AP(data, data.length) << (offset*32));
-     @ ensures this.data == \old(data);
-     @*/
-    private FDBigInteger(int[] data, int offset) {
-        this.data = data;
-        this.offset = offset;
-        this.nWords = data.length;
-        trimLeadingZeros();
-    }
-
-    /**
-     * Constructs an <code>FDBigInteger</code> from a starting value and some
-     * decimal digits.
-     *
-     * @param lValue The starting value.
-     * @param digits The decimal digits.
-     * @param kDigits The initial index into <code>digits</code>.
-     * @param nDigits The final index into <code>digits</code>.
-     */
-    /*@
-     @ requires digits != null;
-     @ requires 0 <= kDigits && kDigits <= nDigits && nDigits <= digits.length;
-     @ requires (\forall int i; 0 <= i && i < nDigits; '0' <= digits[i] && digits[i] <= '9');
-     @ ensures this.value() == \old(lValue * pow10(nDigits - kDigits) + (\sum int i; kDigits <= i && i < nDigits; (digits[i] - '0') * pow10(nDigits - i - 1)));
-     @*/
-    public FDBigInteger(long lValue, char[] digits, int kDigits, int nDigits) {
-        int n = Math.max((nDigits + 8) / 9, 2);        // estimate size needed.
-        data = new int[n];      // allocate enough space
-        data[0] = (int) lValue;    // starting value
-        data[1] = (int) (lValue >>> 32);
-        offset = 0;
-        nWords = 2;
-        int i = kDigits;
-        int limit = nDigits - 5;       // slurp digits 5 at a time.
-        int v;
-        while (i < limit) {
-            int ilim = i + 5;
-            v = (int) digits[i++] - (int) '0';
-            while (i < ilim) {
-                v = 10 * v + (int) digits[i++] - (int) '0';
-            }
-            multAddMe(100000, v); // ... where 100000 is 10^5.
-        }
-        int factor = 1;
-        v = 0;
-        while (i < nDigits) {
-            v = 10 * v + (int) digits[i++] - (int) '0';
-            factor *= 10;
-        }
-        if (factor != 1) {
-            multAddMe(factor, v);
-        }
-        trimLeadingZeros();
-    }
-
-    /**
-     * Returns an <code>FDBigInteger</code> with the numerical value
-     * <code>5<sup>p5</sup> * 2<sup>p2</sup></code>.
-     *
-     * @param p5 The exponent of the power-of-five factor.
-     * @param p2 The exponent of the power-of-two factor.
-     * @return <code>5<sup>p5</sup> * 2<sup>p2</sup></code>
-     */
-    /*@
-     @ requires p5 >= 0 && p2 >= 0;
-     @ assignable \nothing;
-     @ ensures \result.value() == \old(pow52(p5, p2));
-     @*/
-    public static FDBigInteger valueOfPow52(int p5, int p2) {
-        if (p5 != 0) {
-            if (p2 == 0) {
-                return big5pow(p5);
-            } else if (p5 < SMALL_5_POW.length) {
-                int pow5 = SMALL_5_POW[p5];
-                int wordcount = p2 >> 5;
-                int bitcount = p2 & 0x1f;
-                if (bitcount == 0) {
-                    return new FDBigInteger(new int[]{pow5}, wordcount);
-                } else {
-                    return new FDBigInteger(new int[]{
-                            pow5 << bitcount,
-                            pow5 >>> (32 - bitcount)
-                    }, wordcount);
-                }
-            } else {
-                return big5pow(p5).leftShift(p2);
-            }
-        } else {
-            return valueOfPow2(p2);
-        }
-    }
-
-    /**
-     * Returns an <code>FDBigInteger</code> with the numerical value
-     * <code>value * 5<sup>p5</sup> * 2<sup>p2</sup></code>.
-     *
-     * @param value The constant factor.
-     * @param p5 The exponent of the power-of-five factor.
-     * @param p2 The exponent of the power-of-two factor.
-     * @return <code>value * 5<sup>p5</sup> * 2<sup>p2</sup></code>
-     */
-    /*@
-     @ requires p5 >= 0 && p2 >= 0;
-     @ assignable \nothing;
-     @ ensures \result.value() == \old(UNSIGNED(value) * pow52(p5, p2));
-     @*/
-    public static FDBigInteger valueOfMulPow52(long value, int p5, int p2) {
-        assert p5 >= 0 : p5;
-        assert p2 >= 0 : p2;
-        int v0 = (int) value;
-        int v1 = (int) (value >>> 32);
-        int wordcount = p2 >> 5;
-        int bitcount = p2 & 0x1f;
-        if (p5 != 0) {
-            if (p5 < SMALL_5_POW.length) {
-                long pow5 = SMALL_5_POW[p5] & LONG_MASK;
-                long carry = (v0 & LONG_MASK) * pow5;
-                v0 = (int) carry;
-                carry >>>= 32;
-                carry = (v1 & LONG_MASK) * pow5 + carry;
-                v1 = (int) carry;
-                int v2 = (int) (carry >>> 32);
-                if (bitcount == 0) {
-                    return new FDBigInteger(new int[]{v0, v1, v2}, wordcount);
-                } else {
-                    return new FDBigInteger(new int[]{
-                            v0 << bitcount,
-                            (v1 << bitcount) | (v0 >>> (32 - bitcount)),
-                            (v2 << bitcount) | (v1 >>> (32 - bitcount)),
-                            v2 >>> (32 - bitcount)
-                    }, wordcount);
-                }
-            } else {
-                FDBigInteger pow5 = big5pow(p5);
-                int[] r;
-                if (v1 == 0) {
-                    r = new int[pow5.nWords + 1 + ((p2 != 0) ? 1 : 0)];
-                    mult(pow5.data, pow5.nWords, v0, r);
-                } else {
-                    r = new int[pow5.nWords + 2 + ((p2 != 0) ? 1 : 0)];
-                    mult(pow5.data, pow5.nWords, v0, v1, r);
-                }
-                return (new FDBigInteger(r, pow5.offset)).leftShift(p2);
-            }
-        } else if (p2 != 0) {
-            if (bitcount == 0) {
-                return new FDBigInteger(new int[]{v0, v1}, wordcount);
-            } else {
-                return new FDBigInteger(new int[]{
-                         v0 << bitcount,
-                        (v1 << bitcount) | (v0 >>> (32 - bitcount)),
-                        v1 >>> (32 - bitcount)
-                }, wordcount);
-            }
-        }
-        return new FDBigInteger(new int[]{v0, v1}, 0);
-    }
-
-    /**
-     * Returns an <code>FDBigInteger</code> with the numerical value
-     * <code>2<sup>p2</sup></code>.
-     *
-     * @param p2 The exponent of 2.
-     * @return <code>2<sup>p2</sup></code>
-     */
-    /*@
-     @ requires p2 >= 0;
-     @ assignable \nothing;
-     @ ensures \result.value() == pow52(0, p2);
-     @*/
-    private static FDBigInteger valueOfPow2(int p2) {
-        int wordcount = p2 >> 5;
-        int bitcount = p2 & 0x1f;
-        return new FDBigInteger(new int[]{1 << bitcount}, wordcount);
-    }
-
-    /**
-     * Removes all leading zeros from this <code>FDBigInteger</code> adjusting
-     * the offset and number of non-zero leading words accordingly.
-     */
-    /*@
-     @ requires data != null;
-     @ requires 0 <= nWords && nWords <= data.length && offset >= 0;
-     @ requires nWords == 0 ==> offset == 0;
-     @ ensures nWords == 0 ==> offset == 0;
-     @ ensures nWords > 0 ==> data[nWords - 1] != 0;
-     @*/
-    private /*@ helper @*/ void trimLeadingZeros() {
-        int i = nWords;
-        if (i > 0 && (data[--i] == 0)) {
-            //for (; i > 0 && data[i - 1] == 0; i--) ;
-            while(i > 0 && data[i - 1] == 0) {
-                i--;
-            }
-            this.nWords = i;
-            if (i == 0) { // all words are zero
-                this.offset = 0;
-            }
-        }
-    }
-
-    /**
-     * Retrieves the normalization bias of the <code>FDBigIntger</code>. The
-     * normalization bias is a left shift such that after it the highest word
-     * of the value will have the 4 highest bits equal to zero:
-     * {@code (highestWord & 0xf0000000) == 0}, but the next bit should be 1
-     * {@code (highestWord & 0x08000000) != 0}.
-     *
-     * @return The normalization bias.
-     */
-    /*@
-     @ requires this.value() > 0;
-     @*/
-    public /*@ pure @*/ int getNormalizationBias() {
-        if (nWords == 0) {
-            throw new IllegalArgumentException("Zero value cannot be normalized");
-        }
-        int zeros = Integer.numberOfLeadingZeros(data[nWords - 1]);
-        return (zeros < 4) ? 28 + zeros : zeros - 4;
-    }
-
-    // TODO: Why is anticount param needed if it is always 32 - bitcount?
-    /**
-     * Left shifts the contents of one int array into another.
-     *
-     * @param src The source array.
-     * @param idx The initial index of the source array.
-     * @param result The destination array.
-     * @param bitcount The left shift.
-     * @param anticount The left anti-shift, e.g., <code>32-bitcount</code>.
-     * @param prev The prior source value.
-     */
-    /*@
-     @ requires 0 < bitcount && bitcount < 32 && anticount == 32 - bitcount;
-     @ requires src.length >= idx && result.length > idx;
-     @ assignable result[*];
-     @ ensures AP(result, \old(idx + 1)) == \old((AP(src, idx) + UNSIGNED(prev) << (idx*32)) << bitcount);
-     @*/
-    private static void leftShift(int[] src, int idx, int result[], int bitcount, int anticount, int prev){
-        for (; idx > 0; idx--) {
-            int v = (prev << bitcount);
-            prev = src[idx - 1];
-            v |= (prev >>> anticount);
-            result[idx] = v;
-        }
-        int v = prev << bitcount;
-        result[0] = v;
-    }
-
-    /**
-     * Shifts this <code>FDBigInteger</code> to the left. The shift is performed
-     * in-place unless the <code>FDBigInteger</code> is immutable in which case
-     * a new instance of <code>FDBigInteger</code> is returned.
-     *
-     * @param shift The number of bits to shift left.
-     * @return The shifted <code>FDBigInteger</code>.
-     */
-    /*@
-     @ requires this.value() == 0 || shift == 0;
-     @ assignable \nothing;
-     @ ensures \result == this;
-     @
-     @  also
-     @
-     @ requires this.value() > 0 && shift > 0 && this.isImmutable;
-     @ assignable \nothing;
-     @ ensures \result.value() == \old(this.value() << shift);
-     @
-     @  also
-     @
-     @ requires this.value() > 0 && shift > 0 && this.isImmutable;
-     @ assignable \nothing;
-     @ ensures \result == this;
-     @ ensures \result.value() == \old(this.value() << shift);
-     @*/
-    public FDBigInteger leftShift(int shift) {
-        if (shift == 0 || nWords == 0) {
-            return this;
-        }
-        int wordcount = shift >> 5;
-        int bitcount = shift & 0x1f;
-        if (this.isImmutable) {
-            if (bitcount == 0) {
-                return new FDBigInteger(Arrays.copyOf(data, nWords), offset + wordcount);
-            } else {
-                int anticount = 32 - bitcount;
-                int idx = nWords - 1;
-                int prev = data[idx];
-                int hi = prev >>> anticount;
-                int[] result;
-                if (hi != 0) {
-                    result = new int[nWords + 1];
-                    result[nWords] = hi;
-                } else {
-                    result = new int[nWords];
-                }
-                leftShift(data,idx,result,bitcount,anticount,prev);
-                return new FDBigInteger(result, offset + wordcount);
-            }
-        } else {
-            if (bitcount != 0) {
-                int anticount = 32 - bitcount;
-                if ((data[0] << bitcount) == 0) {
-                    int idx = 0;
-                    int prev = data[idx];
-                    for (; idx < nWords - 1; idx++) {
-                        int v = (prev >>> anticount);
-                        prev = data[idx + 1];
-                        v |= (prev << bitcount);
-                        data[idx] = v;
-                    }
-                    int v = prev >>> anticount;
-                    data[idx] = v;
-                    if(v==0) {
-                        nWords--;
-                    }
-                    offset++;
-                } else {
-                    int idx = nWords - 1;
-                    int prev = data[idx];
-                    int hi = prev >>> anticount;
-                    int[] result = data;
-                    int[] src = data;
-                    if (hi != 0) {
-                        if(nWords == data.length) {
-                            data = result = new int[nWords + 1];
-                        }
-                        result[nWords++] = hi;
-                    }
-                    leftShift(src,idx,result,bitcount,anticount,prev);
-                }
-            }
-            offset += wordcount;
-            return this;
-        }
-    }
-
-    /**
-     * Returns the number of <code>int</code>s this <code>FDBigInteger</code> represents.
-     *
-     * @return Number of <code>int</code>s required to represent this <code>FDBigInteger</code>.
-     */
-    /*@
-     @ requires this.value() == 0;
-     @ ensures \result == 0;
-     @
-     @  also
-     @
-     @ requires this.value() > 0;
-     @ ensures ((\bigint)1) << (\result - 1) <= this.value() && this.value() <= ((\bigint)1) << \result;
-     @*/
-    private /*@ pure @*/ int size() {
-        return nWords + offset;
-    }
-
-
-    /**
-     * Computes
-     * <pre>
-     * q = (int)( this / S )
-     * this = 10 * ( this mod S )
-     * Return q.
-     * </pre>
-     * This is the iteration step of digit development for output.
-     * We assume that S has been normalized, as above, and that
-     * "this" has been left-shifted accordingly.
-     * Also assumed, of course, is that the result, q, can be expressed
-     * as an integer, {@code 0 <= q < 10}.
-     *
-     * @param S The divisor of this <code>FDBigInteger</code>.
-     * @return <code>q = (int)(this / S)</code>.
-     */
-    /*@
-     @ requires !this.isImmutable;
-     @ requires this.size() <= S.size();
-     @ requires this.data.length + this.offset >= S.size();
-     @ requires S.value() >= ((\bigint)1) << (S.size()*32 - 4);
-     @ assignable this.nWords, this.offset, this.data, this.data[*];
-     @ ensures \result == \old(this.value() / S.value());
-     @ ensures this.value() == \old(10 * (this.value() % S.value()));
-     @*/
-    public int quoRemIteration(FDBigInteger S) throws IllegalArgumentException {
-        assert !this.isImmutable : "cannot modify immutable value";
-        // ensure that this and S have the same number of
-        // digits. If S is properly normalized and q < 10 then
-        // this must be so.
-        int thSize = this.size();
-        int sSize = S.size();
-        if (thSize < sSize) {
-            // this value is significantly less than S, result of division is zero.
-            // just mult this by 10.
-            int p = multAndCarryBy10(this.data, this.nWords, this.data);
-            if(p!=0) {
-                this.data[nWords++] = p;
-            } else {
-                trimLeadingZeros();
-            }
-            return 0;
-        } else if (thSize > sSize) {
-            throw new IllegalArgumentException("disparate values");
-        }
-        // estimate q the obvious way. We will usually be
-        // right. If not, then we're only off by a little and
-        // will re-add.
-        long q = (this.data[this.nWords - 1] & LONG_MASK) / (S.data[S.nWords - 1] & LONG_MASK);
-        long diff = multDiffMe(q, S);
-        if (diff != 0L) {
-            //@ assert q != 0;
-            //@ assert this.offset == \old(Math.min(this.offset, S.offset));
-            //@ assert this.offset <= S.offset;
-
-            // q is too big.
-            // add S back in until this turns +. This should
-            // not be very many times!
-            long sum = 0L;
-            int tStart = S.offset - this.offset;
-            //@ assert tStart >= 0;
-            int[] sd = S.data;
-            int[] td = this.data;
-            while (sum == 0L) {
-                for (int sIndex = 0, tIndex = tStart; tIndex < this.nWords; sIndex++, tIndex++) {
-                    sum += (td[tIndex] & LONG_MASK) + (sd[sIndex] & LONG_MASK);
-                    td[tIndex] = (int) sum;
-                    sum >>>= 32; // Signed or unsigned, answer is 0 or 1
-                }
-                //
-                // Originally the following line read
-                // "if ( sum !=0 && sum != -1 )"
-                // but that would be wrong, because of the
-                // treatment of the two values as entirely unsigned,
-                // it would be impossible for a carry-out to be interpreted
-                // as -1 -- it would have to be a single-bit carry-out, or +1.
-                //
-                assert sum == 0 || sum == 1 : sum; // carry out of division correction
-                q -= 1;
-            }
-        }
-        // finally, we can multiply this by 10.
-        // it cannot overflow, right, as the high-order word has
-        // at least 4 high-order zeros!
-        int p = multAndCarryBy10(this.data, this.nWords, this.data);
-        assert p == 0 : p; // Carry out of *10
-        trimLeadingZeros();
-        return (int) q;
-    }
-
-    /**
-     * Multiplies this <code>FDBigInteger</code> by 10. The operation will be
-     * performed in place unless the <code>FDBigInteger</code> is immutable in
-     * which case a new <code>FDBigInteger</code> will be returned.
-     *
-     * @return The <code>FDBigInteger</code> multiplied by 10.
-     */
-    /*@
-     @ requires this.value() == 0;
-     @ assignable \nothing;
-     @ ensures \result == this;
-     @
-     @  also
-     @
-     @ requires this.value() > 0 && this.isImmutable;
-     @ assignable \nothing;
-     @ ensures \result.value() == \old(this.value() * 10);
-     @
-     @  also
-     @
-     @ requires this.value() > 0 && !this.isImmutable;
-     @ assignable this.nWords, this.data, this.data[*];
-     @ ensures \result == this;
-     @ ensures \result.value() == \old(this.value() * 10);
-     @*/
-    public FDBigInteger multBy10() {
-        if (nWords == 0) {
-            return this;
-        }
-        if (isImmutable) {
-            int[] res = new int[nWords + 1];
-            res[nWords] = multAndCarryBy10(data, nWords, res);
-            return new FDBigInteger(res, offset);
-        } else {
-            int p = multAndCarryBy10(this.data, this.nWords, this.data);
-            if (p != 0) {
-                if (nWords == data.length) {
-                    if (data[0] == 0) {
-                        System.arraycopy(data, 1, data, 0, --nWords);
-                        offset++;
-                    } else {
-                        data = Arrays.copyOf(data, data.length + 1);
-                    }
-                }
-                data[nWords++] = p;
-            } else {
-                trimLeadingZeros();
-            }
-            return this;
-        }
-    }
-
-    /**
-     * Multiplies this <code>FDBigInteger</code> by
-     * <code>5<sup>p5</sup> * 2<sup>p2</sup></code>. The operation will be
-     * performed in place if possible, otherwise a new <code>FDBigInteger</code>
-     * will be returned.
-     *
-     * @param p5 The exponent of the power-of-five factor.
-     * @param p2 The exponent of the power-of-two factor.
-     * @return The multiplication result.
-     */
-    /*@
-     @ requires this.value() == 0 || p5 == 0 && p2 == 0;
-     @ assignable \nothing;
-     @ ensures \result == this;
-     @
-     @  also
-     @
-     @ requires this.value() > 0 && (p5 > 0 && p2 >= 0 || p5 == 0 && p2 > 0 && this.isImmutable);
-     @ assignable \nothing;
-     @ ensures \result.value() == \old(this.value() * pow52(p5, p2));
-     @
-     @  also
-     @
-     @ requires this.value() > 0 && p5 == 0 && p2 > 0 && !this.isImmutable;
-     @ assignable this.nWords, this.data, this.data[*];
-     @ ensures \result == this;
-     @ ensures \result.value() == \old(this.value() * pow52(p5, p2));
-     @*/
-    public FDBigInteger multByPow52(int p5, int p2) {
-        if (this.nWords == 0) {
-            return this;
-        }
-        FDBigInteger res = this;
-        if (p5 != 0) {
-            int[] r;
-            int extraSize = (p2 != 0) ? 1 : 0;
-            if (p5 < SMALL_5_POW.length) {
-                r = new int[this.nWords + 1 + extraSize];
-                mult(this.data, this.nWords, SMALL_5_POW[p5], r);
-                res = new FDBigInteger(r, this.offset);
-            } else {
-                FDBigInteger pow5 = big5pow(p5);
-                r = new int[this.nWords + pow5.size() + extraSize];
-                mult(this.data, this.nWords, pow5.data, pow5.nWords, r);
-                res = new FDBigInteger(r, this.offset + pow5.offset);
-            }
-        }
-        return res.leftShift(p2);
-    }
-
-    /**
-     * Multiplies two big integers represented as int arrays.
-     *
-     * @param s1 The first array factor.
-     * @param s1Len The number of elements of <code>s1</code> to use.
-     * @param s2 The second array factor.
-     * @param s2Len The number of elements of <code>s2</code> to use.
-     * @param dst The product array.
-     */
-    /*@
-     @ requires s1 != dst && s2 != dst;
-     @ requires s1.length >= s1Len && s2.length >= s2Len && dst.length >= s1Len + s2Len;
-     @ assignable dst[0 .. s1Len + s2Len - 1];
-     @ ensures AP(dst, s1Len + s2Len) == \old(AP(s1, s1Len) * AP(s2, s2Len));
-     @*/
-    private static void mult(int[] s1, int s1Len, int[] s2, int s2Len, int[] dst) {
-        for (int i = 0; i < s1Len; i++) {
-            long v = s1[i] & LONG_MASK;
-            long p = 0L;
-            for (int j = 0; j < s2Len; j++) {
-                p += (dst[i + j] & LONG_MASK) + v * (s2[j] & LONG_MASK);
-                dst[i + j] = (int) p;
-                p >>>= 32;
-            }
-            dst[i + s2Len] = (int) p;
-        }
-    }
-
-    /**
-     * Subtracts the supplied <code>FDBigInteger</code> subtrahend from this
-     * <code>FDBigInteger</code>. Assert that the result is positive.
-     * If the subtrahend is immutable, store the result in this(minuend).
-     * If this(minuend) is immutable a new <code>FDBigInteger</code> is created.
-     *
-     * @param subtrahend The <code>FDBigInteger</code> to be subtracted.
-     * @return This <code>FDBigInteger</code> less the subtrahend.
-     */
-    /*@
-     @ requires this.isImmutable;
-     @ requires this.value() >= subtrahend.value();
-     @ assignable \nothing;
-     @ ensures \result.value() == \old(this.value() - subtrahend.value());
-     @
-     @  also
-     @
-     @ requires !subtrahend.isImmutable;
-     @ requires this.value() >= subtrahend.value();
-     @ assignable this.nWords, this.offset, this.data, this.data[*];
-     @ ensures \result == this;
-     @ ensures \result.value() == \old(this.value() - subtrahend.value());
-     @*/
-    public FDBigInteger leftInplaceSub(FDBigInteger subtrahend) {
-        assert this.size() >= subtrahend.size() : "result should be positive";
-        FDBigInteger minuend;
-        if (this.isImmutable) {
-            minuend = new FDBigInteger(this.data.clone(), this.offset);
-        } else {
-            minuend = this;
-        }
-        int offsetDiff = subtrahend.offset - minuend.offset;
-        int[] sData = subtrahend.data;
-        int[] mData = minuend.data;
-        int subLen = subtrahend.nWords;
-        int minLen = minuend.nWords;
-        if (offsetDiff < 0) {
-            // need to expand minuend
-            int rLen = minLen - offsetDiff;
-            if (rLen < mData.length) {
-                System.arraycopy(mData, 0, mData, -offsetDiff, minLen);
-                Arrays.fill(mData, 0, -offsetDiff, 0);
-            } else {
-                int[] r = new int[rLen];
-                System.arraycopy(mData, 0, r, -offsetDiff, minLen);
-                minuend.data = mData = r;
-            }
-            minuend.offset = subtrahend.offset;
-            minuend.nWords = minLen = rLen;
-            offsetDiff = 0;
-        }
-        long borrow = 0L;
-        int mIndex = offsetDiff;
-        for (int sIndex = 0; sIndex < subLen && mIndex < minLen; sIndex++, mIndex++) {
-            long diff = (mData[mIndex] & LONG_MASK) - (sData[sIndex] & LONG_MASK) + borrow;
-            mData[mIndex] = (int) diff;
-            borrow = diff >> 32; // signed shift
-        }
-        for (; borrow != 0 && mIndex < minLen; mIndex++) {
-            long diff = (mData[mIndex] & LONG_MASK) + borrow;
-            mData[mIndex] = (int) diff;
-            borrow = diff >> 32; // signed shift
-        }
-        assert borrow == 0L : borrow; // borrow out of subtract,
-        // result should be positive
-        minuend.trimLeadingZeros();
-        return minuend;
-    }
-
-    /**
-     * Subtracts the supplied <code>FDBigInteger</code> subtrahend from this
-     * <code>FDBigInteger</code>. Assert that the result is positive.
-     * If the this(minuend) is immutable, store the result in subtrahend.
-     * If subtrahend is immutable a new <code>FDBigInteger</code> is created.
-     *
-     * @param subtrahend The <code>FDBigInteger</code> to be subtracted.
-     * @return This <code>FDBigInteger</code> less the subtrahend.
-     */
-    /*@
-     @ requires subtrahend.isImmutable;
-     @ requires this.value() >= subtrahend.value();
-     @ assignable \nothing;
-     @ ensures \result.value() == \old(this.value() - subtrahend.value());
-     @
-     @  also
-     @
-     @ requires !subtrahend.isImmutable;
-     @ requires this.value() >= subtrahend.value();
-     @ assignable subtrahend.nWords, subtrahend.offset, subtrahend.data, subtrahend.data[*];
-     @ ensures \result == subtrahend;
-     @ ensures \result.value() == \old(this.value() - subtrahend.value());
-     @*/
-    public FDBigInteger rightInplaceSub(FDBigInteger subtrahend) {
-        assert this.size() >= subtrahend.size() : "result should be positive";
-        FDBigInteger minuend = this;
-        if (subtrahend.isImmutable) {
-            subtrahend = new FDBigInteger(subtrahend.data.clone(), subtrahend.offset);
-        }
-        int offsetDiff = minuend.offset - subtrahend.offset;
-        int[] sData = subtrahend.data;
-        int[] mData = minuend.data;
-        int subLen = subtrahend.nWords;
-        int minLen = minuend.nWords;
-        if (offsetDiff < 0) {
-            int rLen = minLen;
-            if (rLen < sData.length) {
-                System.arraycopy(sData, 0, sData, -offsetDiff, subLen);
-                Arrays.fill(sData, 0, -offsetDiff, 0);
-            } else {
-                int[] r = new int[rLen];
-                System.arraycopy(sData, 0, r, -offsetDiff, subLen);
-                subtrahend.data = sData = r;
-            }
-            subtrahend.offset = minuend.offset;
-            subLen -= offsetDiff;
-            offsetDiff = 0;
-        } else {
-            int rLen = minLen + offsetDiff;
-            if (rLen >= sData.length) {
-                subtrahend.data = sData = Arrays.copyOf(sData, rLen);
-            }
-        }
-        //@ assert minuend == this && minuend.value() == \old(this.value());
-        //@ assert mData == minuend.data && minLen == minuend.nWords;
-        //@ assert subtrahend.offset + subtrahend.data.length >= minuend.size();
-        //@ assert sData == subtrahend.data;
-        //@ assert AP(subtrahend.data, subtrahend.data.length) << subtrahend.offset == \old(subtrahend.value());
-        //@ assert subtrahend.offset == Math.min(\old(this.offset), minuend.offset);
-        //@ assert offsetDiff == minuend.offset - subtrahend.offset;
-        //@ assert 0 <= offsetDiff && offsetDiff + minLen <= sData.length;
-        int sIndex = 0;
-        long borrow = 0L;
-        for (; sIndex < offsetDiff; sIndex++) {
-            long diff = 0L - (sData[sIndex] & LONG_MASK) + borrow;
-            sData[sIndex] = (int) diff;
-            borrow = diff >> 32; // signed shift
-        }
-        //@ assert sIndex == offsetDiff;
-        for (int mIndex = 0; mIndex < minLen; sIndex++, mIndex++) {
-            //@ assert sIndex == offsetDiff + mIndex;
-            long diff = (mData[mIndex] & LONG_MASK) - (sData[sIndex] & LONG_MASK) + borrow;
-            sData[sIndex] = (int) diff;
-            borrow = diff >> 32; // signed shift
-        }
-        assert borrow == 0L : borrow; // borrow out of subtract,
-        // result should be positive
-        subtrahend.nWords = sIndex;
-        subtrahend.trimLeadingZeros();
-        return subtrahend;
-
-    }
-
-    /**
-     * Determines whether all elements of an array are zero for all indices less
-     * than a given index.
-     *
-     * @param a The array to be examined.
-     * @param from The index strictly below which elements are to be examined.
-     * @return Zero if all elements in range are zero, 1 otherwise.
-     */
-    /*@
-     @ requires 0 <= from && from <= a.length;
-     @ ensures \result == (AP(a, from) == 0 ? 0 : 1);
-     @*/
-    private /*@ pure @*/ static int checkZeroTail(int[] a, int from) {
-        while (from > 0) {
-            if (a[--from] != 0) {
-                return 1;
-            }
-        }
-        return 0;
-    }
-
-    /**
-     * Compares the parameter with this <code>FDBigInteger</code>. Returns an
-     * integer accordingly as:
-     * <pre>{@code
-     * > 0: this > other
-     *   0: this == other
-     * < 0: this < other
-     * }</pre>
-     *
-     * @param other The <code>FDBigInteger</code> to compare.
-     * @return A negative value, zero, or a positive value according to the
-     * result of the comparison.
-     */
-    /*@
-     @ ensures \result == (this.value() < other.value() ? -1 : this.value() > other.value() ? +1 : 0);
-     @*/
-    public /*@ pure @*/ int cmp(FDBigInteger other) {
-        int aSize = nWords + offset;
-        int bSize = other.nWords + other.offset;
-        if (aSize > bSize) {
-            return 1;
-        } else if (aSize < bSize) {
-            return -1;
-        }
-        int aLen = nWords;
-        int bLen = other.nWords;
-        while (aLen > 0 && bLen > 0) {
-            int a = data[--aLen];
-            int b = other.data[--bLen];
-            if (a != b) {
-                return ((a & LONG_MASK) < (b & LONG_MASK)) ? -1 : 1;
-            }
-        }
-        if (aLen > 0) {
-            return checkZeroTail(data, aLen);
-        }
-        if (bLen > 0) {
-            return -checkZeroTail(other.data, bLen);
-        }
-        return 0;
-    }
-
-    /**
-     * Compares this <code>FDBigInteger</code> with
-     * <code>5<sup>p5</sup> * 2<sup>p2</sup></code>.
-     * Returns an integer accordingly as:
-     * <pre>{@code
-     * > 0: this > other
-     *   0: this == other
-     * < 0: this < other
-     * }</pre>
-     * @param p5 The exponent of the power-of-five factor.
-     * @param p2 The exponent of the power-of-two factor.
-     * @return A negative value, zero, or a positive value according to the
-     * result of the comparison.
-     */
-    /*@
-     @ requires p5 >= 0 && p2 >= 0;
-     @ ensures \result == (this.value() < pow52(p5, p2) ? -1 : this.value() >  pow52(p5, p2) ? +1 : 0);
-     @*/
-    public /*@ pure @*/ int cmpPow52(int p5, int p2) {
-        if (p5 == 0) {
-            int wordcount = p2 >> 5;
-            int bitcount = p2 & 0x1f;
-            int size = this.nWords + this.offset;
-            if (size > wordcount + 1) {
-                return 1;
-            } else if (size < wordcount + 1) {
-                return -1;
-            }
-            int a = this.data[this.nWords -1];
-            int b = 1 << bitcount;
-            if (a != b) {
-                return ( (a & LONG_MASK) < (b & LONG_MASK)) ? -1 : 1;
-            }
-            return checkZeroTail(this.data, this.nWords - 1);
-        }
-        return this.cmp(big5pow(p5).leftShift(p2));
-    }
-
-    /**
-     * Compares this <code>FDBigInteger</code> with <code>x + y</code>. Returns a
-     * value according to the comparison as:
-     * <pre>{@code
-     * -1: this <  x + y
-     *  0: this == x + y
-     *  1: this >  x + y
-     * }</pre>
-     * @param x The first addend of the sum to compare.
-     * @param y The second addend of the sum to compare.
-     * @return -1, 0, or 1 according to the result of the comparison.
-     */
-    /*@
-     @ ensures \result == (this.value() < x.value() + y.value() ? -1 : this.value() > x.value() + y.value() ? +1 : 0);
-     @*/
-    public /*@ pure @*/ int addAndCmp(FDBigInteger x, FDBigInteger y) {
-        FDBigInteger big;
-        FDBigInteger small;
-        int xSize = x.size();
-        int ySize = y.size();
-        int bSize;
-        int sSize;
-        if (xSize >= ySize) {
-            big = x;
-            small = y;
-            bSize = xSize;
-            sSize = ySize;
-        } else {
-            big = y;
-            small = x;
-            bSize = ySize;
-            sSize = xSize;
-        }
-        int thSize = this.size();
-        if (bSize == 0) {
-            return thSize == 0 ? 0 : 1;
-        }
-        if (sSize == 0) {
-            return this.cmp(big);
-        }
-        if (bSize > thSize) {
-            return -1;
-        }
-        if (bSize + 1 < thSize) {
-            return 1;
-        }
-        long top = (big.data[big.nWords - 1] & LONG_MASK);
-        if (sSize == bSize) {
-            top += (small.data[small.nWords - 1] & LONG_MASK);
-        }
-        if ((top >>> 32) == 0) {
-            if (((top + 1) >>> 32) == 0) {
-                // good case - no carry extension
-                if (bSize < thSize) {
-                    return 1;
-                }
-                // here sum.nWords == this.nWords
-                long v = (this.data[this.nWords - 1] & LONG_MASK);
-                if (v < top) {
-                    return -1;
-                }
-                if (v > top + 1) {
-                    return 1;
-                }
-            }
-        } else { // (top>>>32)!=0 guaranteed carry extension
-            if (bSize + 1 > thSize) {
-                return -1;
-            }
-            // here sum.nWords == this.nWords
-            top >>>= 32;
-            long v = (this.data[this.nWords - 1] & LONG_MASK);
-            if (v < top) {
-                return -1;
-            }
-            if (v > top + 1) {
-                return 1;
-            }
-        }
-        return this.cmp(big.add(small));
-    }
-
-    /**
-     * Makes this <code>FDBigInteger</code> immutable.
-     */
-    /*@
-     @ assignable this.isImmutable;
-     @ ensures this.isImmutable;
-     @*/
-    public void makeImmutable() {
-        this.isImmutable = true;
-    }
-
-    /**
-     * Multiplies this <code>FDBigInteger</code> by an integer.
-     *
-     * @param i The factor by which to multiply this <code>FDBigInteger</code>.
-     * @return This <code>FDBigInteger</code> multiplied by an integer.
-     */
-    /*@
-     @ requires this.value() == 0;
-     @ assignable \nothing;
-     @ ensures \result == this;
-     @
-     @  also
-     @
-     @ requires this.value() != 0;
-     @ assignable \nothing;
-     @ ensures \result.value() == \old(this.value() * UNSIGNED(i));
-     @*/
-    private FDBigInteger mult(int i) {
-        if (this.nWords == 0) {
-            return this;
-        }
-        int[] r = new int[nWords + 1];
-        mult(data, nWords, i, r);
-        return new FDBigInteger(r, offset);
-    }
-
-    /**
-     * Multiplies this <code>FDBigInteger</code> by another <code>FDBigInteger</code>.
-     *
-     * @param other The <code>FDBigInteger</code> factor by which to multiply.
-     * @return The product of this and the parameter <code>FDBigInteger</code>s.
-     */
-    /*@
-     @ requires this.value() == 0;
-     @ assignable \nothing;
-     @ ensures \result == this;
-     @
-     @  also
-     @
-     @ requires this.value() != 0 && other.value() == 0;
-     @ assignable \nothing;
-     @ ensures \result == other;
-     @
-     @  also
-     @
-     @ requires this.value() != 0 && other.value() != 0;
-     @ assignable \nothing;
-     @ ensures \result.value() == \old(this.value() * other.value());
-     @*/
-    private FDBigInteger mult(FDBigInteger other) {
-        if (this.nWords == 0) {
-            return this;
-        }
-        if (this.size() == 1) {
-            return other.mult(data[0]);
-        }
-        if (other.nWords == 0) {
-            return other;
-        }
-        if (other.size() == 1) {
-            return this.mult(other.data[0]);
-        }
-        int[] r = new int[nWords + other.nWords];
-        mult(this.data, this.nWords, other.data, other.nWords, r);
-        return new FDBigInteger(r, this.offset + other.offset);
-    }
-
-    /**
-     * Adds another <code>FDBigInteger</code> to this <code>FDBigInteger</code>.
-     *
-     * @param other The <code>FDBigInteger</code> to add.
-     * @return The sum of the <code>FDBigInteger</code>s.
-     */
-    /*@
-     @ assignable \nothing;
-     @ ensures \result.value() == \old(this.value() + other.value());
-     @*/
-    private FDBigInteger add(FDBigInteger other) {
-        FDBigInteger big, small;
-        int bigLen, smallLen;
-        int tSize = this.size();
-        int oSize = other.size();
-        if (tSize >= oSize) {
-            big = this;
-            bigLen = tSize;
-            small = other;
-            smallLen = oSize;
-        } else {
-            big = other;
-            bigLen = oSize;
-            small = this;
-            smallLen = tSize;
-        }
-        int[] r = new int[bigLen + 1];
-        int i = 0;
-        long carry = 0L;
-        for (; i < smallLen; i++) {
-            carry += (i < big.offset   ? 0L : (big.data[i - big.offset] & LONG_MASK) )
-                   + ((i < small.offset ? 0L : (small.data[i - small.offset] & LONG_MASK)));
-            r[i] = (int) carry;
-            carry >>= 32; // signed shift.
-        }
-        for (; i < bigLen; i++) {
-            carry += (i < big.offset ? 0L : (big.data[i - big.offset] & LONG_MASK) );
-            r[i] = (int) carry;
-            carry >>= 32; // signed shift.
-        }
-        r[bigLen] = (int) carry;
-        return new FDBigInteger(r, 0);
-    }
-
-
-    /**
-     * Multiplies a <code>FDBigInteger</code> by an int and adds another int. The
-     * result is computed in place. This method is intended only to be invoked
-     * from
-     * <code>
-     * FDBigInteger(long lValue, char[] digits, int kDigits, int nDigits)
-     * </code>.
-     *
-     * @param iv The factor by which to multiply this <code>FDBigInteger</code>.
-     * @param addend The value to add to the product of this
-     * <code>FDBigInteger</code> and <code>iv</code>.
-     */
-    /*@
-     @ requires this.value()*UNSIGNED(iv) + UNSIGNED(addend) < ((\bigint)1) << ((this.data.length + this.offset)*32);
-     @ assignable this.data[*];
-     @ ensures this.value() == \old(this.value()*UNSIGNED(iv) + UNSIGNED(addend));
-     @*/
-    private /*@ helper @*/ void multAddMe(int iv, int addend) {
-        long v = iv & LONG_MASK;
-        // unroll 0th iteration, doing addition.
-        long p = v * (data[0] & LONG_MASK) + (addend & LONG_MASK);
-        data[0] = (int) p;
-        p >>>= 32;
-        for (int i = 1; i < nWords; i++) {
-            p += v * (data[i] & LONG_MASK);
-            data[i] = (int) p;
-            p >>>= 32;
-        }
-        if (p != 0L) {
-            data[nWords++] = (int) p; // will fail noisily if illegal!
-        }
-    }
-
-    //
-    // original doc:
-    //
-    // do this -=q*S
-    // returns borrow
-    //
-    /**
-     * Multiplies the parameters and subtracts them from this
-     * <code>FDBigInteger</code>.
-     *
-     * @param q The integer parameter.
-     * @param S The <code>FDBigInteger</code> parameter.
-     * @return <code>this - q*S</code>.
-     */
-    /*@
-     @ ensures nWords == 0 ==> offset == 0;
-     @ ensures nWords > 0 ==> data[nWords - 1] != 0;
-     @*/
-    /*@
-     @ requires 0 < q && q <= (1L << 31);
-     @ requires data != null;
-     @ requires 0 <= nWords && nWords <= data.length && offset >= 0;
-     @ requires !this.isImmutable;
-     @ requires this.size() == S.size();
-     @ requires this != S;
-     @ assignable this.nWords, this.offset, this.data, this.data[*];
-     @ ensures -q <= \result && \result <= 0;
-     @ ensures this.size() == \old(this.size());
-     @ ensures this.value() + (\result << (this.size()*32)) == \old(this.value() - q*S.value());
-     @ ensures this.offset == \old(Math.min(this.offset, S.offset));
-     @ ensures \old(this.offset <= S.offset) ==> this.nWords == \old(this.nWords);
-     @ ensures \old(this.offset <= S.offset) ==> this.offset == \old(this.offset);
-     @ ensures \old(this.offset <= S.offset) ==> this.data == \old(this.data);
-     @
-     @  also
-     @
-     @ requires q == 0;
-     @ assignable \nothing;
-     @ ensures \result == 0;
-     @*/
-    private /*@ helper @*/ long multDiffMe(long q, FDBigInteger S) {
-        long diff = 0L;
-        if (q != 0) {
-            int deltaSize = S.offset - this.offset;
-            if (deltaSize >= 0) {
-                int[] sd = S.data;
-                int[] td = this.data;
-                for (int sIndex = 0, tIndex = deltaSize; sIndex < S.nWords; sIndex++, tIndex++) {
-                    diff += (td[tIndex] & LONG_MASK) - q * (sd[sIndex] & LONG_MASK);
-                    td[tIndex] = (int) diff;
-                    diff >>= 32; // N.B. SIGNED shift.
-                }
-            } else {
-                deltaSize = -deltaSize;
-                int[] rd = new int[nWords + deltaSize];
-                int sIndex = 0;
-                int rIndex = 0;
-                int[] sd = S.data;
-                for (; rIndex < deltaSize && sIndex < S.nWords; sIndex++, rIndex++) {
-                    diff -= q * (sd[sIndex] & LONG_MASK);
-                    rd[rIndex] = (int) diff;
-                    diff >>= 32; // N.B. SIGNED shift.
-                }
-                int tIndex = 0;
-                int[] td = this.data;
-                for (; sIndex < S.nWords; sIndex++, tIndex++, rIndex++) {
-                    diff += (td[tIndex] & LONG_MASK) - q * (sd[sIndex] & LONG_MASK);
-                    rd[rIndex] = (int) diff;
-                    diff >>= 32; // N.B. SIGNED shift.
-                }
-                this.nWords += deltaSize;
-                this.offset -= deltaSize;
-                this.data = rd;
-            }
-        }
-        return diff;
-    }
-
-
-    /**
-     * Multiplies by 10 a big integer represented as an array. The final carry
-     * is returned.
-     *
-     * @param src The array representation of the big integer.
-     * @param srcLen The number of elements of <code>src</code> to use.
-     * @param dst The product array.
-     * @return The final carry of the multiplication.
-     */
-    /*@
-     @ requires src.length >= srcLen && dst.length >= srcLen;
-     @ assignable dst[0 .. srcLen - 1];
-     @ ensures 0 <= \result && \result < 10;
-     @ ensures AP(dst, srcLen) + (\result << (srcLen*32)) == \old(AP(src, srcLen) * 10);
-     @*/
-    private static int multAndCarryBy10(int[] src, int srcLen, int[] dst) {
-        long carry = 0;
-        for (int i = 0; i < srcLen; i++) {
-            long product = (src[i] & LONG_MASK) * 10L + carry;
-            dst[i] = (int) product;
-            carry = product >>> 32;
-        }
-        return (int) carry;
-    }
-
-    /**
-     * Multiplies by a constant value a big integer represented as an array.
-     * The constant factor is an <code>int</code>.
-     *
-     * @param src The array representation of the big integer.
-     * @param srcLen The number of elements of <code>src</code> to use.
-     * @param value The constant factor by which to multiply.
-     * @param dst The product array.
-     */
-    /*@
-     @ requires src.length >= srcLen && dst.length >= srcLen + 1;
-     @ assignable dst[0 .. srcLen];
-     @ ensures AP(dst, srcLen + 1) == \old(AP(src, srcLen) * UNSIGNED(value));
-     @*/
-    private static void mult(int[] src, int srcLen, int value, int[] dst) {
-        long val = value & LONG_MASK;
-        long carry = 0;
-        for (int i = 0; i < srcLen; i++) {
-            long product = (src[i] & LONG_MASK) * val + carry;
-            dst[i] = (int) product;
-            carry = product >>> 32;
-        }
-        dst[srcLen] = (int) carry;
-    }
-
-    /**
-     * Multiplies by a constant value a big integer represented as an array.
-     * The constant factor is a long represent as two <code>int</code>s.
-     *
-     * @param src The array representation of the big integer.
-     * @param srcLen The number of elements of <code>src</code> to use.
-     * @param v0 The lower 32 bits of the long factor.
-     * @param v1 The upper 32 bits of the long factor.
-     * @param dst The product array.
-     */
-    /*@
-     @ requires src != dst;
-     @ requires src.length >= srcLen && dst.length >= srcLen + 2;
-     @ assignable dst[0 .. srcLen + 1];
-     @ ensures AP(dst, srcLen + 2) == \old(AP(src, srcLen) * (UNSIGNED(v0) + (UNSIGNED(v1) << 32)));
-     @*/
-    private static void mult(int[] src, int srcLen, int v0, int v1, int[] dst) {
-        long v = v0 & LONG_MASK;
-        long carry = 0;
-        for (int j = 0; j < srcLen; j++) {
-            long product = v * (src[j] & LONG_MASK) + carry;
-            dst[j] = (int) product;
-            carry = product >>> 32;
-        }
-        dst[srcLen] = (int) carry;
-        v = v1 & LONG_MASK;
-        carry = 0;
-        for (int j = 0; j < srcLen; j++) {
-            long product = (dst[j + 1] & LONG_MASK) + v * (src[j] & LONG_MASK) + carry;
-            dst[j + 1] = (int) product;
-            carry = product >>> 32;
-        }
-        dst[srcLen + 1] = (int) carry;
-    }
-
-    // Fails assertion for negative exponent.
-    /**
-     * Computes <code>5</code> raised to a given power.
-     *
-     * @param p The exponent of 5.
-     * @return <code>5<sup>p</sup></code>.
-     */
-    private static FDBigInteger big5pow(int p) {
-        assert p >= 0 : p; // negative power of 5
-        if (p < MAX_FIVE_POW) {
-            return POW_5_CACHE[p];
-        }
-        return big5powRec(p);
-    }
-
-    // slow path
-    /**
-     * Computes <code>5</code> raised to a given power.
-     *
-     * @param p The exponent of 5.
-     * @return <code>5<sup>p</sup></code>.
-     */
-    private static FDBigInteger big5powRec(int p) {
-        if (p < MAX_FIVE_POW) {
-            return POW_5_CACHE[p];
-        }
-        // construct the value.
-        // recursively.
-        int q, r;
-        // in order to compute 5^p,
-        // compute its square root, 5^(p/2) and square.
-        // or, let q = p / 2, r = p -q, then
-        // 5^p = 5^(q+r) = 5^q * 5^r
-        q = p >> 1;
-        r = p - q;
-        FDBigInteger bigq = big5powRec(q);
-        if (r < SMALL_5_POW.length) {
-            return bigq.mult(SMALL_5_POW[r]);
-        } else {
-            return bigq.mult(big5powRec(r));
-        }
-    }
-
-    // for debugging ...
-    /**
-     * Converts this <code>FDBigInteger</code> to a hexadecimal string.
-     *
-     * @return The hexadecimal string representation.
-     */
-    public String toHexString(){
-        if(nWords ==0) {
-            return "0";
-        }
-        StringBuilder sb = new StringBuilder((nWords +offset)*8);
-        for(int i= nWords -1; i>=0; i--) {
-            String subStr = Integer.toHexString(data[i]);
-            for(int j = subStr.length(); j<8; j++) {
-                sb.append('0');
-            }
-            sb.append(subStr);
-        }
-        for(int i=offset; i>0; i--) {
-            sb.append("00000000");
-        }
-        return sb.toString();
-    }
-
-    // for debugging ...
-    /**
-     * Converts this <code>FDBigInteger</code> to a <code>BigInteger</code>.
-     *
-     * @return The <code>BigInteger</code> representation.
-     */
-    public BigInteger toBigInteger() {
-        byte[] magnitude = new byte[nWords * 4 + 1];
-        for (int i = 0; i < nWords; i++) {
-            int w = data[i];
-            magnitude[magnitude.length - 4 * i - 1] = (byte) w;
-            magnitude[magnitude.length - 4 * i - 2] = (byte) (w >> 8);
-            magnitude[magnitude.length - 4 * i - 3] = (byte) (w >> 16);
-            magnitude[magnitude.length - 4 * i - 4] = (byte) (w >> 24);
-        }
-        return new BigInteger(magnitude).shiftLeft(offset * 32);
-    }
-
-    // for debugging ...
-    /**
-     * Converts this <code>FDBigInteger</code> to a string.
-     *
-     * @return The string representation.
-     */
-    @Override
-    public String toString(){
-        return toBigInteger().toString();
-    }
-}
--- a/jdk/src/java.base/share/classes/sun/misc/FloatConsts.java	Thu Dec 24 10:33:21 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,111 +0,0 @@
-/*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.misc;
-
-/**
- * This class contains additional constants documenting limits of the
- * <code>float</code> type.
- *
- * @author Joseph D. Darcy
- */
-
-public class FloatConsts {
-    /**
-     * Don't let anyone instantiate this class.
-     */
-    private FloatConsts() {}
-
-    public static final float POSITIVE_INFINITY = java.lang.Float.POSITIVE_INFINITY;
-    public static final float NEGATIVE_INFINITY = java.lang.Float.NEGATIVE_INFINITY;
-    public static final float NaN = java.lang.Float.NaN;
-    public static final float MAX_VALUE = java.lang.Float.MAX_VALUE;
-    public static final float MIN_VALUE = java.lang.Float.MIN_VALUE;
-
-    /**
-     * A constant holding the smallest positive normal value of type
-     * <code>float</code>, 2<sup>-126</sup>.  It is equal to the value
-     * returned by <code>Float.intBitsToFloat(0x00800000)</code>.
-     */
-    public static final float   MIN_NORMAL      = 1.17549435E-38f;
-
-    /**
-     * The number of logical bits in the significand of a
-     * <code>float</code> number, including the implicit bit.
-     */
-    public static final int SIGNIFICAND_WIDTH   = 24;
-
-    /**
-     * Maximum exponent a finite <code>float</code> number may have.
-     * It is equal to the value returned by
-     * <code>Math.ilogb(Float.MAX_VALUE)</code>.
-     */
-    public static final int     MAX_EXPONENT    = 127;
-
-    /**
-     * Minimum exponent a normalized <code>float</code> number may
-     * have.  It is equal to the value returned by
-     * <code>Math.ilogb(Float.MIN_NORMAL)</code>.
-     */
-    public static final int     MIN_EXPONENT    = -126;
-
-    /**
-     * The exponent the smallest positive <code>float</code> subnormal
-     * value would have if it could be normalized.
-     */
-    public static final int     MIN_SUB_EXPONENT = MIN_EXPONENT -
-                                                   (SIGNIFICAND_WIDTH - 1);
-
-    /**
-     * Bias used in representing a <code>float</code> exponent.
-     */
-    public static final int     EXP_BIAS        = 127;
-
-    /**
-     * Bit mask to isolate the sign bit of a <code>float</code>.
-     */
-    public static final int     SIGN_BIT_MASK   = 0x80000000;
-
-    /**
-     * Bit mask to isolate the exponent field of a
-     * <code>float</code>.
-     */
-    public static final int     EXP_BIT_MASK    = 0x7F800000;
-
-    /**
-     * Bit mask to isolate the significand field of a
-     * <code>float</code>.
-     */
-    public static final int     SIGNIF_BIT_MASK = 0x007FFFFF;
-
-    static {
-        // verify bit masks cover all bit positions and that the bit
-        // masks are non-overlapping
-        assert(((SIGN_BIT_MASK | EXP_BIT_MASK | SIGNIF_BIT_MASK) == ~0) &&
-               (((SIGN_BIT_MASK & EXP_BIT_MASK) == 0) &&
-                ((SIGN_BIT_MASK & SIGNIF_BIT_MASK) == 0) &&
-                ((EXP_BIT_MASK & SIGNIF_BIT_MASK) == 0)));
-    }
-}
--- a/jdk/src/java.base/share/classes/sun/misc/FloatingDecimal.java	Thu Dec 24 10:33:21 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2552 +0,0 @@
-/*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.misc;
-
-import java.util.Arrays;
-import java.util.regex.*;
-
-/**
- * A class for converting between ASCII and decimal representations of a single
- * or double precision floating point number. Most conversions are provided via
- * static convenience methods, although a <code>BinaryToASCIIConverter</code>
- * instance may be obtained and reused.
- */
-public class FloatingDecimal{
-    //
-    // Constants of the implementation;
-    // most are IEEE-754 related.
-    // (There are more really boring constants at the end.)
-    //
-    static final int    EXP_SHIFT = DoubleConsts.SIGNIFICAND_WIDTH - 1;
-    static final long   FRACT_HOB = ( 1L<<EXP_SHIFT ); // assumed High-Order bit
-    static final long   EXP_ONE   = ((long)DoubleConsts.EXP_BIAS)<<EXP_SHIFT; // exponent of 1.0
-    static final int    MAX_SMALL_BIN_EXP = 62;
-    static final int    MIN_SMALL_BIN_EXP = -( 63 / 3 );
-    static final int    MAX_DECIMAL_DIGITS = 15;
-    static final int    MAX_DECIMAL_EXPONENT = 308;
-    static final int    MIN_DECIMAL_EXPONENT = -324;
-    static final int    BIG_DECIMAL_EXPONENT = 324; // i.e. abs(MIN_DECIMAL_EXPONENT)
-    static final int    MAX_NDIGITS = 1100;
-
-    static final int    SINGLE_EXP_SHIFT  =   FloatConsts.SIGNIFICAND_WIDTH - 1;
-    static final int    SINGLE_FRACT_HOB  =   1<<SINGLE_EXP_SHIFT;
-    static final int    SINGLE_MAX_DECIMAL_DIGITS = 7;
-    static final int    SINGLE_MAX_DECIMAL_EXPONENT = 38;
-    static final int    SINGLE_MIN_DECIMAL_EXPONENT = -45;
-    static final int    SINGLE_MAX_NDIGITS = 200;
-
-    static final int    INT_DECIMAL_DIGITS = 9;
-
-    /**
-     * Converts a double precision floating point value to a <code>String</code>.
-     *
-     * @param d The double precision value.
-     * @return The value converted to a <code>String</code>.
-     */
-    public static String toJavaFormatString(double d) {
-        return getBinaryToASCIIConverter(d).toJavaFormatString();
-    }
-
-    /**
-     * Converts a single precision floating point value to a <code>String</code>.
-     *
-     * @param f The single precision value.
-     * @return The value converted to a <code>String</code>.
-     */
-    public static String toJavaFormatString(float f) {
-        return getBinaryToASCIIConverter(f).toJavaFormatString();
-    }
-
-    /**
-     * Appends a double precision floating point value to an <code>Appendable</code>.
-     * @param d The double precision value.
-     * @param buf The <code>Appendable</code> with the value appended.
-     */
-    public static void appendTo(double d, Appendable buf) {
-        getBinaryToASCIIConverter(d).appendTo(buf);
-    }
-
-    /**
-     * Appends a single precision floating point value to an <code>Appendable</code>.
-     * @param f The single precision value.
-     * @param buf The <code>Appendable</code> with the value appended.
-     */
-    public static void appendTo(float f, Appendable buf) {
-        getBinaryToASCIIConverter(f).appendTo(buf);
-    }
-
-    /**
-     * Converts a <code>String</code> to a double precision floating point value.
-     *
-     * @param s The <code>String</code> to convert.
-     * @return The double precision value.
-     * @throws NumberFormatException If the <code>String</code> does not
-     * represent a properly formatted double precision value.
-     */
-    public static double parseDouble(String s) throws NumberFormatException {
-        return readJavaFormatString(s).doubleValue();
-    }
-
-    /**
-     * Converts a <code>String</code> to a single precision floating point value.
-     *
-     * @param s The <code>String</code> to convert.
-     * @return The single precision value.
-     * @throws NumberFormatException If the <code>String</code> does not
-     * represent a properly formatted single precision value.
-     */
-    public static float parseFloat(String s) throws NumberFormatException {
-        return readJavaFormatString(s).floatValue();
-    }
-
-    /**
-     * A converter which can process single or double precision floating point
-     * values into an ASCII <code>String</code> representation.
-     */
-    public interface BinaryToASCIIConverter {
-        /**
-         * Converts a floating point value into an ASCII <code>String</code>.
-         * @return The value converted to a <code>String</code>.
-         */
-        public String toJavaFormatString();
-
-        /**
-         * Appends a floating point value to an <code>Appendable</code>.
-         * @param buf The <code>Appendable</code> to receive the value.
-         */
-        public void appendTo(Appendable buf);
-
-        /**
-         * Retrieves the decimal exponent most closely corresponding to this value.
-         * @return The decimal exponent.
-         */
-        public int getDecimalExponent();
-
-        /**
-         * Retrieves the value as an array of digits.
-         * @param digits The digit array.
-         * @return The number of valid digits copied into the array.
-         */
-        public int getDigits(char[] digits);
-
-        /**
-         * Indicates the sign of the value.
-         * @return {@code value < 0.0}.
-         */
-        public boolean isNegative();
-
-        /**
-         * Indicates whether the value is either infinite or not a number.
-         *
-         * @return <code>true</code> if and only if the value is <code>NaN</code>
-         * or infinite.
-         */
-        public boolean isExceptional();
-
-        /**
-         * Indicates whether the value was rounded up during the binary to ASCII
-         * conversion.
-         *
-         * @return <code>true</code> if and only if the value was rounded up.
-         */
-        public boolean digitsRoundedUp();
-
-        /**
-         * Indicates whether the binary to ASCII conversion was exact.
-         *
-         * @return <code>true</code> if any only if the conversion was exact.
-         */
-        public boolean decimalDigitsExact();
-    }
-
-    /**
-     * A <code>BinaryToASCIIConverter</code> which represents <code>NaN</code>
-     * and infinite values.
-     */
-    private static class ExceptionalBinaryToASCIIBuffer implements BinaryToASCIIConverter {
-        private final String image;
-        private boolean isNegative;
-
-        public ExceptionalBinaryToASCIIBuffer(String image, boolean isNegative) {
-            this.image = image;
-            this.isNegative = isNegative;
-        }
-
-        @Override
-        public String toJavaFormatString() {
-            return image;
-        }
-
-        @Override
-        public void appendTo(Appendable buf) {
-            if (buf instanceof StringBuilder) {
-                ((StringBuilder) buf).append(image);
-            } else if (buf instanceof StringBuffer) {
-                ((StringBuffer) buf).append(image);
-            } else {
-                assert false;
-            }
-        }
-
-        @Override
-        public int getDecimalExponent() {
-            throw new IllegalArgumentException("Exceptional value does not have an exponent");
-        }
-
-        @Override
-        public int getDigits(char[] digits) {
-            throw new IllegalArgumentException("Exceptional value does not have digits");
-        }
-
-        @Override
-        public boolean isNegative() {
-            return isNegative;
-        }
-
-        @Override
-        public boolean isExceptional() {
-            return true;
-        }
-
-        @Override
-        public boolean digitsRoundedUp() {
-            throw new IllegalArgumentException("Exceptional value is not rounded");
-        }
-
-        @Override
-        public boolean decimalDigitsExact() {
-            throw new IllegalArgumentException("Exceptional value is not exact");
-        }
-    }
-
-    private static final String INFINITY_REP = "Infinity";
-    private static final int INFINITY_LENGTH = INFINITY_REP.length();
-    private static final String NAN_REP = "NaN";
-    private static final int NAN_LENGTH = NAN_REP.length();
-
-    private static final BinaryToASCIIConverter B2AC_POSITIVE_INFINITY = new ExceptionalBinaryToASCIIBuffer(INFINITY_REP, false);
-    private static final BinaryToASCIIConverter B2AC_NEGATIVE_INFINITY = new ExceptionalBinaryToASCIIBuffer("-" + INFINITY_REP, true);
-    private static final BinaryToASCIIConverter B2AC_NOT_A_NUMBER = new ExceptionalBinaryToASCIIBuffer(NAN_REP, false);
-    private static final BinaryToASCIIConverter B2AC_POSITIVE_ZERO = new BinaryToASCIIBuffer(false, new char[]{'0'});
-    private static final BinaryToASCIIConverter B2AC_NEGATIVE_ZERO = new BinaryToASCIIBuffer(true,  new char[]{'0'});
-
-    /**
-     * A buffered implementation of <code>BinaryToASCIIConverter</code>.
-     */
-    static class BinaryToASCIIBuffer implements BinaryToASCIIConverter {
-        private boolean isNegative;
-        private int decExponent;
-        private int firstDigitIndex;
-        private int nDigits;
-        private final char[] digits;
-        private final char[] buffer = new char[26];
-
-        //
-        // The fields below provide additional information about the result of
-        // the binary to decimal digits conversion done in dtoa() and roundup()
-        // methods. They are changed if needed by those two methods.
-        //
-
-        // True if the dtoa() binary to decimal conversion was exact.
-        private boolean exactDecimalConversion = false;
-
-        // True if the result of the binary to decimal conversion was rounded-up
-        // at the end of the conversion process, i.e. roundUp() method was called.
-        private boolean decimalDigitsRoundedUp = false;
-
-        /**
-         * Default constructor; used for non-zero values,
-         * <code>BinaryToASCIIBuffer</code> may be thread-local and reused
-         */
-        BinaryToASCIIBuffer(){
-            this.digits = new char[20];
-        }
-
-        /**
-         * Creates a specialized value (positive and negative zeros).
-         */
-        BinaryToASCIIBuffer(boolean isNegative, char[] digits){
-            this.isNegative = isNegative;
-            this.decExponent  = 0;
-            this.digits = digits;
-            this.firstDigitIndex = 0;
-            this.nDigits = digits.length;
-        }
-
-        @Override
-        public String toJavaFormatString() {
-            int len = getChars(buffer);
-            return new String(buffer, 0, len);
-        }
-
-        @Override
-        public void appendTo(Appendable buf) {
-            int len = getChars(buffer);
-            if (buf instanceof StringBuilder) {
-                ((StringBuilder) buf).append(buffer, 0, len);
-            } else if (buf instanceof StringBuffer) {
-                ((StringBuffer) buf).append(buffer, 0, len);
-            } else {
-                assert false;
-            }
-        }
-
-        @Override
-        public int getDecimalExponent() {
-            return decExponent;
-        }
-
-        @Override
-        public int getDigits(char[] digits) {
-            System.arraycopy(this.digits,firstDigitIndex,digits,0,this.nDigits);
-            return this.nDigits;
-        }
-
-        @Override
-        public boolean isNegative() {
-            return isNegative;
-        }
-
-        @Override
-        public boolean isExceptional() {
-            return false;
-        }
-
-        @Override
-        public boolean digitsRoundedUp() {
-            return decimalDigitsRoundedUp;
-        }
-
-        @Override
-        public boolean decimalDigitsExact() {
-            return exactDecimalConversion;
-        }
-
-        private void setSign(boolean isNegative) {
-            this.isNegative = isNegative;
-        }
-
-        /**
-         * This is the easy subcase --
-         * all the significant bits, after scaling, are held in lvalue.
-         * negSign and decExponent tell us what processing and scaling
-         * has already been done. Exceptional cases have already been
-         * stripped out.
-         * In particular:
-         * lvalue is a finite number (not Inf, nor NaN)
-         * lvalue > 0L (not zero, nor negative).
-         *
-         * The only reason that we develop the digits here, rather than
-         * calling on Long.toString() is that we can do it a little faster,
-         * and besides want to treat trailing 0s specially. If Long.toString
-         * changes, we should re-evaluate this strategy!
-         */
-        private void developLongDigits( int decExponent, long lvalue, int insignificantDigits ){
-            if ( insignificantDigits != 0 ){
-                // Discard non-significant low-order bits, while rounding,
-                // up to insignificant value.
-                long pow10 = FDBigInteger.LONG_5_POW[insignificantDigits] << insignificantDigits; // 10^i == 5^i * 2^i;
-                long residue = lvalue % pow10;
-                lvalue /= pow10;
-                decExponent += insignificantDigits;
-                if ( residue >= (pow10>>1) ){
-                    // round up based on the low-order bits we're discarding
-                    lvalue++;
-                }
-            }
-            int  digitno = digits.length -1;
-            int  c;
-            if ( lvalue <= Integer.MAX_VALUE ){
-                assert lvalue > 0L : lvalue; // lvalue <= 0
-                // even easier subcase!
-                // can do int arithmetic rather than long!
-                int  ivalue = (int)lvalue;
-                c = ivalue%10;
-                ivalue /= 10;
-                while ( c == 0 ){
-                    decExponent++;
-                    c = ivalue%10;
-                    ivalue /= 10;
-                }
-                while ( ivalue != 0){
-                    digits[digitno--] = (char)(c+'0');
-                    decExponent++;
-                    c = ivalue%10;
-                    ivalue /= 10;
-                }
-                digits[digitno] = (char)(c+'0');
-            } else {
-                // same algorithm as above (same bugs, too )
-                // but using long arithmetic.
-                c = (int)(lvalue%10L);
-                lvalue /= 10L;
-                while ( c == 0 ){
-                    decExponent++;
-                    c = (int)(lvalue%10L);
-                    lvalue /= 10L;
-                }
-                while ( lvalue != 0L ){
-                    digits[digitno--] = (char)(c+'0');
-                    decExponent++;
-                    c = (int)(lvalue%10L);
-                    lvalue /= 10;
-                }
-                digits[digitno] = (char)(c+'0');
-            }
-            this.decExponent = decExponent+1;
-            this.firstDigitIndex = digitno;
-            this.nDigits = this.digits.length - digitno;
-        }
-
-        private void dtoa( int binExp, long fractBits, int nSignificantBits, boolean isCompatibleFormat)
-        {
-            assert fractBits > 0 ; // fractBits here can't be zero or negative
-            assert (fractBits & FRACT_HOB)!=0  ; // Hi-order bit should be set
-            // Examine number. Determine if it is an easy case,
-            // which we can do pretty trivially using float/long conversion,
-            // or whether we must do real work.
-            final int tailZeros = Long.numberOfTrailingZeros(fractBits);
-
-            // number of significant bits of fractBits;
-            final int nFractBits = EXP_SHIFT+1-tailZeros;
-
-            // reset flags to default values as dtoa() does not always set these
-            // flags and a prior call to dtoa() might have set them to incorrect
-            // values with respect to the current state.
-            decimalDigitsRoundedUp = false;
-            exactDecimalConversion = false;
-
-            // number of significant bits to the right of the point.
-            int nTinyBits = Math.max( 0, nFractBits - binExp - 1 );
-            if ( binExp <= MAX_SMALL_BIN_EXP && binExp >= MIN_SMALL_BIN_EXP ){
-                // Look more closely at the number to decide if,
-                // with scaling by 10^nTinyBits, the result will fit in
-                // a long.
-                if ( (nTinyBits < FDBigInteger.LONG_5_POW.length) && ((nFractBits + N_5_BITS[nTinyBits]) < 64 ) ){
-                    //
-                    // We can do this:
-                    // take the fraction bits, which are normalized.
-                    // (a) nTinyBits == 0: Shift left or right appropriately
-                    //     to align the binary point at the extreme right, i.e.
-                    //     where a long int point is expected to be. The integer
-                    //     result is easily converted to a string.
-                    // (b) nTinyBits > 0: Shift right by EXP_SHIFT-nFractBits,
-                    //     which effectively converts to long and scales by
-                    //     2^nTinyBits. Then multiply by 5^nTinyBits to
-                    //     complete the scaling. We know this won't overflow
-                    //     because we just counted the number of bits necessary
-                    //     in the result. The integer you get from this can
-                    //     then be converted to a string pretty easily.
-                    //
-                    if ( nTinyBits == 0 ) {
-                        int insignificant;
-                        if ( binExp > nSignificantBits ){
-                            insignificant = insignificantDigitsForPow2(binExp-nSignificantBits-1);
-                        } else {
-                            insignificant = 0;
-                        }
-                        if ( binExp >= EXP_SHIFT ){
-                            fractBits <<= (binExp-EXP_SHIFT);
-                        } else {
-                            fractBits >>>= (EXP_SHIFT-binExp) ;
-                        }
-                        developLongDigits( 0, fractBits, insignificant );
-                        return;
-                    }
-                    //
-                    // The following causes excess digits to be printed
-                    // out in the single-float case. Our manipulation of
-                    // halfULP here is apparently not correct. If we
-                    // better understand how this works, perhaps we can
-                    // use this special case again. But for the time being,
-                    // we do not.
-                    // else {
-                    //     fractBits >>>= EXP_SHIFT+1-nFractBits;
-                    //     fractBits//= long5pow[ nTinyBits ];
-                    //     halfULP = long5pow[ nTinyBits ] >> (1+nSignificantBits-nFractBits);
-                    //     developLongDigits( -nTinyBits, fractBits, insignificantDigits(halfULP) );
-                    //     return;
-                    // }
-                    //
-                }
-            }
-            //
-            // This is the hard case. We are going to compute large positive
-            // integers B and S and integer decExp, s.t.
-            //      d = ( B / S )// 10^decExp
-            //      1 <= B / S < 10
-            // Obvious choices are:
-            //      decExp = floor( log10(d) )
-            //      B      = d// 2^nTinyBits// 10^max( 0, -decExp )
-            //      S      = 10^max( 0, decExp)// 2^nTinyBits
-            // (noting that nTinyBits has already been forced to non-negative)
-            // I am also going to compute a large positive integer
-            //      M      = (1/2^nSignificantBits)// 2^nTinyBits// 10^max( 0, -decExp )
-            // i.e. M is (1/2) of the ULP of d, scaled like B.
-            // When we iterate through dividing B/S and picking off the
-            // quotient bits, we will know when to stop when the remainder
-            // is <= M.
-            //
-            // We keep track of powers of 2 and powers of 5.
-            //
-            int decExp = estimateDecExp(fractBits,binExp);
-            int B2, B5; // powers of 2 and powers of 5, respectively, in B
-            int S2, S5; // powers of 2 and powers of 5, respectively, in S
-            int M2, M5; // powers of 2 and powers of 5, respectively, in M
-
-            B5 = Math.max( 0, -decExp );
-            B2 = B5 + nTinyBits + binExp;
-
-            S5 = Math.max( 0, decExp );
-            S2 = S5 + nTinyBits;
-
-            M5 = B5;
-            M2 = B2 - nSignificantBits;
-
-            //
-            // the long integer fractBits contains the (nFractBits) interesting
-            // bits from the mantissa of d ( hidden 1 added if necessary) followed
-            // by (EXP_SHIFT+1-nFractBits) zeros. In the interest of compactness,
-            // I will shift out those zeros before turning fractBits into a
-            // FDBigInteger. The resulting whole number will be
-            //      d * 2^(nFractBits-1-binExp).
-            //
-            fractBits >>>= tailZeros;
-            B2 -= nFractBits-1;
-            int common2factor = Math.min( B2, S2 );
-            B2 -= common2factor;
-            S2 -= common2factor;
-            M2 -= common2factor;
-
-            //
-            // HACK!! For exact powers of two, the next smallest number
-            // is only half as far away as we think (because the meaning of
-            // ULP changes at power-of-two bounds) for this reason, we
-            // hack M2. Hope this works.
-            //
-            if ( nFractBits == 1 ) {
-                M2 -= 1;
-            }
-
-            if ( M2 < 0 ){
-                // oops.
-                // since we cannot scale M down far enough,
-                // we must scale the other values up.
-                B2 -= M2;
-                S2 -= M2;
-                M2 =  0;
-            }
-            //
-            // Construct, Scale, iterate.
-            // Some day, we'll write a stopping test that takes
-            // account of the asymmetry of the spacing of floating-point
-            // numbers below perfect powers of 2
-            // 26 Sept 96 is not that day.
-            // So we use a symmetric test.
-            //
-            int ndigit = 0;
-            boolean low, high;
-            long lowDigitDifference;
-            int  q;
-
-            //
-            // Detect the special cases where all the numbers we are about
-            // to compute will fit in int or long integers.
-            // In these cases, we will avoid doing FDBigInteger arithmetic.
-            // We use the same algorithms, except that we "normalize"
-            // our FDBigIntegers before iterating. This is to make division easier,
-            // as it makes our fist guess (quotient of high-order words)
-            // more accurate!
-            //
-            // Some day, we'll write a stopping test that takes
-            // account of the asymmetry of the spacing of floating-point
-            // numbers below perfect powers of 2
-            // 26 Sept 96 is not that day.
-            // So we use a symmetric test.
-            //
-            // binary digits needed to represent B, approx.
-            int Bbits = nFractBits + B2 + (( B5 < N_5_BITS.length )? N_5_BITS[B5] : ( B5*3 ));
-
-            // binary digits needed to represent 10*S, approx.
-            int tenSbits = S2+1 + (( (S5+1) < N_5_BITS.length )? N_5_BITS[(S5+1)] : ( (S5+1)*3 ));
-            if ( Bbits < 64 && tenSbits < 64){
-                if ( Bbits < 32 && tenSbits < 32){
-                    // wa-hoo! They're all ints!
-                    int b = ((int)fractBits * FDBigInteger.SMALL_5_POW[B5] ) << B2;
-                    int s = FDBigInteger.SMALL_5_POW[S5] << S2;
-                    int m = FDBigInteger.SMALL_5_POW[M5] << M2;
-                    int tens = s * 10;
-                    //
-                    // Unroll the first iteration. If our decExp estimate
-                    // was too high, our first quotient will be zero. In this
-                    // case, we discard it and decrement decExp.
-                    //
-                    ndigit = 0;
-                    q = b / s;
-                    b = 10 * ( b % s );
-                    m *= 10;
-                    low  = (b <  m );
-                    high = (b+m > tens );
-                    assert q < 10 : q; // excessively large digit
-                    if ( (q == 0) && ! high ){
-                        // oops. Usually ignore leading zero.
-                        decExp--;
-                    } else {
-                        digits[ndigit++] = (char)('0' + q);
-                    }
-                    //
-                    // HACK! Java spec sez that we always have at least
-                    // one digit after the . in either F- or E-form output.
-                    // Thus we will need more than one digit if we're using
-                    // E-form
-                    //
-                    if ( !isCompatibleFormat ||decExp < -3 || decExp >= 8 ){
-                        high = low = false;
-                    }
-                    while( ! low && ! high ){
-                        q = b / s;
-                        b = 10 * ( b % s );
-                        m *= 10;
-                        assert q < 10 : q; // excessively large digit
-                        if ( m > 0L ){
-                            low  = (b <  m );
-                            high = (b+m > tens );
-                        } else {
-                            // hack -- m might overflow!
-                            // in this case, it is certainly > b,
-                            // which won't
-                            // and b+m > tens, too, since that has overflowed
-                            // either!
-                            low = true;
-                            high = true;
-                        }
-                        digits[ndigit++] = (char)('0' + q);
-                    }
-                    lowDigitDifference = (b<<1) - tens;
-                    exactDecimalConversion  = (b == 0);
-                } else {
-                    // still good! they're all longs!
-                    long b = (fractBits * FDBigInteger.LONG_5_POW[B5] ) << B2;
-                    long s = FDBigInteger.LONG_5_POW[S5] << S2;
-                    long m = FDBigInteger.LONG_5_POW[M5] << M2;
-                    long tens = s * 10L;
-                    //
-                    // Unroll the first iteration. If our decExp estimate
-                    // was too high, our first quotient will be zero. In this
-                    // case, we discard it and decrement decExp.
-                    //
-                    ndigit = 0;
-                    q = (int) ( b / s );
-                    b = 10L * ( b % s );
-                    m *= 10L;
-                    low  = (b <  m );
-                    high = (b+m > tens );
-                    assert q < 10 : q; // excessively large digit
-                    if ( (q == 0) && ! high ){
-                        // oops. Usually ignore leading zero.
-                        decExp--;
-                    } else {
-                        digits[ndigit++] = (char)('0' + q);
-                    }
-                    //
-                    // HACK! Java spec sez that we always have at least
-                    // one digit after the . in either F- or E-form output.
-                    // Thus we will need more than one digit if we're using
-                    // E-form
-                    //
-                    if ( !isCompatibleFormat || decExp < -3 || decExp >= 8 ){
-                        high = low = false;
-                    }
-                    while( ! low && ! high ){
-                        q = (int) ( b / s );
-                        b = 10 * ( b % s );
-                        m *= 10;
-                        assert q < 10 : q;  // excessively large digit
-                        if ( m > 0L ){
-                            low  = (b <  m );
-                            high = (b+m > tens );
-                        } else {
-                            // hack -- m might overflow!
-                            // in this case, it is certainly > b,
-                            // which won't
-                            // and b+m > tens, too, since that has overflowed
-                            // either!
-                            low = true;
-                            high = true;
-                        }
-                        digits[ndigit++] = (char)('0' + q);
-                    }
-                    lowDigitDifference = (b<<1) - tens;
-                    exactDecimalConversion  = (b == 0);
-                }
-            } else {
-                //
-                // We really must do FDBigInteger arithmetic.
-                // Fist, construct our FDBigInteger initial values.
-                //
-                FDBigInteger Sval = FDBigInteger.valueOfPow52(S5, S2);
-                int shiftBias = Sval.getNormalizationBias();
-                Sval = Sval.leftShift(shiftBias); // normalize so that division works better
-
-                FDBigInteger Bval = FDBigInteger.valueOfMulPow52(fractBits, B5, B2 + shiftBias);
-                FDBigInteger Mval = FDBigInteger.valueOfPow52(M5 + 1, M2 + shiftBias + 1);
-
-                FDBigInteger tenSval = FDBigInteger.valueOfPow52(S5 + 1, S2 + shiftBias + 1); //Sval.mult( 10 );
-                //
-                // Unroll the first iteration. If our decExp estimate
-                // was too high, our first quotient will be zero. In this
-                // case, we discard it and decrement decExp.
-                //
-                ndigit = 0;
-                q = Bval.quoRemIteration( Sval );
-                low  = (Bval.cmp( Mval ) < 0);
-                high = tenSval.addAndCmp(Bval,Mval)<=0;
-
-                assert q < 10 : q; // excessively large digit
-                if ( (q == 0) && ! high ){
-                    // oops. Usually ignore leading zero.
-                    decExp--;
-                } else {
-                    digits[ndigit++] = (char)('0' + q);
-                }
-                //
-                // HACK! Java spec sez that we always have at least
-                // one digit after the . in either F- or E-form output.
-                // Thus we will need more than one digit if we're using
-                // E-form
-                //
-                if (!isCompatibleFormat || decExp < -3 || decExp >= 8 ){
-                    high = low = false;
-                }
-                while( ! low && ! high ){
-                    q = Bval.quoRemIteration( Sval );
-                    assert q < 10 : q;  // excessively large digit
-                    Mval = Mval.multBy10(); //Mval = Mval.mult( 10 );
-                    low  = (Bval.cmp( Mval ) < 0);
-                    high = tenSval.addAndCmp(Bval,Mval)<=0;
-                    digits[ndigit++] = (char)('0' + q);
-                }
-                if ( high && low ){
-                    Bval = Bval.leftShift(1);
-                    lowDigitDifference = Bval.cmp(tenSval);
-                } else {
-                    lowDigitDifference = 0L; // this here only for flow analysis!
-                }
-                exactDecimalConversion  = (Bval.cmp( FDBigInteger.ZERO ) == 0);
-            }
-            this.decExponent = decExp+1;
-            this.firstDigitIndex = 0;
-            this.nDigits = ndigit;
-            //
-            // Last digit gets rounded based on stopping condition.
-            //
-            if ( high ){
-                if ( low ){
-                    if ( lowDigitDifference == 0L ){
-                        // it's a tie!
-                        // choose based on which digits we like.
-                        if ( (digits[firstDigitIndex+nDigits-1]&1) != 0 ) {
-                            roundup();
-                        }
-                    } else if ( lowDigitDifference > 0 ){
-                        roundup();
-                    }
-                } else {
-                    roundup();
-                }
-            }
-        }
-
-        // add one to the least significant digit.
-        // in the unlikely event there is a carry out, deal with it.
-        // assert that this will only happen where there
-        // is only one digit, e.g. (float)1e-44 seems to do it.
-        //
-        private void roundup() {
-            int i = (firstDigitIndex + nDigits - 1);
-            int q = digits[i];
-            if (q == '9') {
-                while (q == '9' && i > firstDigitIndex) {
-                    digits[i] = '0';
-                    q = digits[--i];
-                }
-                if (q == '9') {
-                    // carryout! High-order 1, rest 0s, larger exp.
-                    decExponent += 1;
-                    digits[firstDigitIndex] = '1';
-                    return;
-                }
-                // else fall through.
-            }
-            digits[i] = (char) (q + 1);
-            decimalDigitsRoundedUp = true;
-        }
-
-        /**
-         * Estimate decimal exponent. (If it is small-ish,
-         * we could double-check.)
-         *
-         * First, scale the mantissa bits such that 1 <= d2 < 2.
-         * We are then going to estimate
-         *          log10(d2) ~=~  (d2-1.5)/1.5 + log(1.5)
-         * and so we can estimate
-         *      log10(d) ~=~ log10(d2) + binExp * log10(2)
-         * take the floor and call it decExp.
-         */
-        static int estimateDecExp(long fractBits, int binExp) {
-            double d2 = Double.longBitsToDouble( EXP_ONE | ( fractBits & DoubleConsts.SIGNIF_BIT_MASK ) );
-            double d = (d2-1.5D)*0.289529654D + 0.176091259 + (double)binExp * 0.301029995663981;
-            long dBits = Double.doubleToRawLongBits(d);  //can't be NaN here so use raw
-            int exponent = (int)((dBits & DoubleConsts.EXP_BIT_MASK) >> EXP_SHIFT) - DoubleConsts.EXP_BIAS;
-            boolean isNegative = (dBits & DoubleConsts.SIGN_BIT_MASK) != 0; // discover sign
-            if(exponent>=0 && exponent<52) { // hot path
-                long mask   = DoubleConsts.SIGNIF_BIT_MASK >> exponent;
-                int r = (int)(( (dBits&DoubleConsts.SIGNIF_BIT_MASK) | FRACT_HOB )>>(EXP_SHIFT-exponent));
-                return isNegative ? (((mask & dBits) == 0L ) ? -r : -r-1 ) : r;
-            } else if (exponent < 0) {
-                return (((dBits&~DoubleConsts.SIGN_BIT_MASK) == 0) ? 0 :
-                        ( (isNegative) ? -1 : 0) );
-            } else { //if (exponent >= 52)
-                return (int)d;
-            }
-        }
-
-        private static int insignificantDigits(int insignificant) {
-            int i;
-            for ( i = 0; insignificant >= 10L; i++ ) {
-                insignificant /= 10L;
-            }
-            return i;
-        }
-
-        /**
-         * Calculates
-         * <pre>
-         * insignificantDigitsForPow2(v) == insignificantDigits(1L<<v)
-         * </pre>
-         */
-        private static int insignificantDigitsForPow2(int p2) {
-            if(p2>1 && p2 < insignificantDigitsNumber.length) {
-                return insignificantDigitsNumber[p2];
-            }
-            return 0;
-        }
-
-        /**
-         *  If insignificant==(1L << ixd)
-         *  i = insignificantDigitsNumber[idx] is the same as:
-         *  int i;
-         *  for ( i = 0; insignificant >= 10L; i++ )
-         *         insignificant /= 10L;
-         */
-        private static int[] insignificantDigitsNumber = {
-            0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3,
-            4, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7,
-            8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 11, 11, 11,
-            12, 12, 12, 12, 13, 13, 13, 14, 14, 14,
-            15, 15, 15, 15, 16, 16, 16, 17, 17, 17,
-            18, 18, 18, 19
-        };
-
-        // approximately ceil( log2( long5pow[i] ) )
-        private static final int[] N_5_BITS = {
-                0,
-                3,
-                5,
-                7,
-                10,
-                12,
-                14,
-                17,
-                19,
-                21,
-                24,
-                26,
-                28,
-                31,
-                33,
-                35,
-                38,
-                40,
-                42,
-                45,
-                47,
-                49,
-                52,
-                54,
-                56,
-                59,
-                61,
-        };
-
-        private int getChars(char[] result) {
-            assert nDigits <= 19 : nDigits; // generous bound on size of nDigits
-            int i = 0;
-            if (isNegative) {
-                result[0] = '-';
-                i = 1;
-            }
-            if (decExponent > 0 && decExponent < 8) {
-                // print digits.digits.
-                int charLength = Math.min(nDigits, decExponent);
-                System.arraycopy(digits, firstDigitIndex, result, i, charLength);
-                i += charLength;
-                if (charLength < decExponent) {
-                    charLength = decExponent - charLength;
-                    Arrays.fill(result,i,i+charLength,'0');
-                    i += charLength;
-                    result[i++] = '.';
-                    result[i++] = '0';
-                } else {
-                    result[i++] = '.';
-                    if (charLength < nDigits) {
-                        int t = nDigits - charLength;
-                        System.arraycopy(digits, firstDigitIndex+charLength, result, i, t);
-                        i += t;
-                    } else {
-                        result[i++] = '0';
-                    }
-                }
-            } else if (decExponent <= 0 && decExponent > -3) {
-                result[i++] = '0';
-                result[i++] = '.';
-                if (decExponent != 0) {
-                    Arrays.fill(result, i, i-decExponent, '0');
-                    i -= decExponent;
-                }
-                System.arraycopy(digits, firstDigitIndex, result, i, nDigits);
-                i += nDigits;
-            } else {
-                result[i++] = digits[firstDigitIndex];
-                result[i++] = '.';
-                if (nDigits > 1) {
-                    System.arraycopy(digits, firstDigitIndex+1, result, i, nDigits - 1);
-                    i += nDigits - 1;
-                } else {
-                    result[i++] = '0';
-                }
-                result[i++] = 'E';
-                int e;
-                if (decExponent <= 0) {
-                    result[i++] = '-';
-                    e = -decExponent + 1;
-                } else {
-                    e = decExponent - 1;
-                }
-                // decExponent has 1, 2, or 3, digits
-                if (e <= 9) {
-                    result[i++] = (char) (e + '0');
-                } else if (e <= 99) {
-                    result[i++] = (char) (e / 10 + '0');
-                    result[i++] = (char) (e % 10 + '0');
-                } else {
-                    result[i++] = (char) (e / 100 + '0');
-                    e %= 100;
-                    result[i++] = (char) (e / 10 + '0');
-                    result[i++] = (char) (e % 10 + '0');
-                }
-            }
-            return i;
-        }
-
-    }
-
-    private static final ThreadLocal<BinaryToASCIIBuffer> threadLocalBinaryToASCIIBuffer =
-            new ThreadLocal<BinaryToASCIIBuffer>() {
-                @Override
-                protected BinaryToASCIIBuffer initialValue() {
-                    return new BinaryToASCIIBuffer();
-                }
-            };
-
-    private static BinaryToASCIIBuffer getBinaryToASCIIBuffer() {
-        return threadLocalBinaryToASCIIBuffer.get();
-    }
-
-    /**
-     * A converter which can process an ASCII <code>String</code> representation
-     * of a single or double precision floating point value into a
-     * <code>float</code> or a <code>double</code>.
-     */
-    interface ASCIIToBinaryConverter {
-
-        double doubleValue();
-
-        float floatValue();
-
-    }
-
-    /**
-     * A <code>ASCIIToBinaryConverter</code> container for a <code>double</code>.
-     */
-    static class PreparedASCIIToBinaryBuffer implements ASCIIToBinaryConverter {
-        private final double doubleVal;
-        private final float floatVal;
-
-        public PreparedASCIIToBinaryBuffer(double doubleVal, float floatVal) {
-            this.doubleVal = doubleVal;
-            this.floatVal = floatVal;
-        }
-
-        @Override
-        public double doubleValue() {
-            return doubleVal;
-        }
-
-        @Override
-        public float floatValue() {
-            return floatVal;
-        }
-    }
-
-    static final ASCIIToBinaryConverter A2BC_POSITIVE_INFINITY = new PreparedASCIIToBinaryBuffer(Double.POSITIVE_INFINITY, Float.POSITIVE_INFINITY);
-    static final ASCIIToBinaryConverter A2BC_NEGATIVE_INFINITY = new PreparedASCIIToBinaryBuffer(Double.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY);
-    static final ASCIIToBinaryConverter A2BC_NOT_A_NUMBER  = new PreparedASCIIToBinaryBuffer(Double.NaN, Float.NaN);
-    static final ASCIIToBinaryConverter A2BC_POSITIVE_ZERO = new PreparedASCIIToBinaryBuffer(0.0d, 0.0f);
-    static final ASCIIToBinaryConverter A2BC_NEGATIVE_ZERO = new PreparedASCIIToBinaryBuffer(-0.0d, -0.0f);
-
-    /**
-     * A buffered implementation of <code>ASCIIToBinaryConverter</code>.
-     */
-    static class ASCIIToBinaryBuffer implements ASCIIToBinaryConverter {
-        boolean     isNegative;
-        int         decExponent;
-        char        digits[];
-        int         nDigits;
-
-        ASCIIToBinaryBuffer( boolean negSign, int decExponent, char[] digits, int n)
-        {
-            this.isNegative = negSign;
-            this.decExponent = decExponent;
-            this.digits = digits;
-            this.nDigits = n;
-        }
-
-        /**
-         * Takes a FloatingDecimal, which we presumably just scanned in,
-         * and finds out what its value is, as a double.
-         *
-         * AS A SIDE EFFECT, SET roundDir TO INDICATE PREFERRED
-         * ROUNDING DIRECTION in case the result is really destined
-         * for a single-precision float.
-         */
-        @Override
-        public double doubleValue() {
-            int kDigits = Math.min(nDigits, MAX_DECIMAL_DIGITS + 1);
-            //
-            // convert the lead kDigits to a long integer.
-            //
-            // (special performance hack: start to do it using int)
-            int iValue = (int) digits[0] - (int) '0';
-            int iDigits = Math.min(kDigits, INT_DECIMAL_DIGITS);
-            for (int i = 1; i < iDigits; i++) {
-                iValue = iValue * 10 + (int) digits[i] - (int) '0';
-            }
-            long lValue = (long) iValue;
-            for (int i = iDigits; i < kDigits; i++) {
-                lValue = lValue * 10L + (long) ((int) digits[i] - (int) '0');
-            }
-            double dValue = (double) lValue;
-            int exp = decExponent - kDigits;
-            //
-            // lValue now contains a long integer with the value of
-            // the first kDigits digits of the number.
-            // dValue contains the (double) of the same.
-            //
-
-            if (nDigits <= MAX_DECIMAL_DIGITS) {
-                //
-                // possibly an easy case.
-                // We know that the digits can be represented
-                // exactly. And if the exponent isn't too outrageous,
-                // the whole thing can be done with one operation,
-                // thus one rounding error.
-                // Note that all our constructors trim all leading and
-                // trailing zeros, so simple values (including zero)
-                // will always end up here
-                //
-                if (exp == 0 || dValue == 0.0) {
-                    return (isNegative) ? -dValue : dValue; // small floating integer
-                }
-                else if (exp >= 0) {
-                    if (exp <= MAX_SMALL_TEN) {
-                        //
-                        // Can get the answer with one operation,
-                        // thus one roundoff.
-                        //
-                        double rValue = dValue * SMALL_10_POW[exp];
-                        return (isNegative) ? -rValue : rValue;
-                    }
-                    int slop = MAX_DECIMAL_DIGITS - kDigits;
-                    if (exp <= MAX_SMALL_TEN + slop) {
-                        //
-                        // We can multiply dValue by 10^(slop)
-                        // and it is still "small" and exact.
-                        // Then we can multiply by 10^(exp-slop)
-                        // with one rounding.
-                        //
-                        dValue *= SMALL_10_POW[slop];
-                        double rValue = dValue * SMALL_10_POW[exp - slop];
-                        return (isNegative) ? -rValue : rValue;
-                    }
-                    //
-                    // Else we have a hard case with a positive exp.
-                    //
-                } else {
-                    if (exp >= -MAX_SMALL_TEN) {
-                        //
-                        // Can get the answer in one division.
-                        //
-                        double rValue = dValue / SMALL_10_POW[-exp];
-                        return (isNegative) ? -rValue : rValue;
-                    }
-                    //
-                    // Else we have a hard case with a negative exp.
-                    //
-                }
-            }
-
-            //
-            // Harder cases:
-            // The sum of digits plus exponent is greater than
-            // what we think we can do with one error.
-            //
-            // Start by approximating the right answer by,
-            // naively, scaling by powers of 10.
-            //
-            if (exp > 0) {
-                if (decExponent > MAX_DECIMAL_EXPONENT + 1) {
-                    //
-                    // Lets face it. This is going to be
-                    // Infinity. Cut to the chase.
-                    //
-                    return (isNegative) ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
-                }
-                if ((exp & 15) != 0) {
-                    dValue *= SMALL_10_POW[exp & 15];
-                }
-                if ((exp >>= 4) != 0) {
-                    int j;
-                    for (j = 0; exp > 1; j++, exp >>= 1) {
-                        if ((exp & 1) != 0) {
-                            dValue *= BIG_10_POW[j];
-                        }
-                    }
-                    //
-                    // The reason for the weird exp > 1 condition
-                    // in the above loop was so that the last multiply
-                    // would get unrolled. We handle it here.
-                    // It could overflow.
-                    //
-                    double t = dValue * BIG_10_POW[j];
-                    if (Double.isInfinite(t)) {
-                        //
-                        // It did overflow.
-                        // Look more closely at the result.
-                        // If the exponent is just one too large,
-                        // then use the maximum finite as our estimate
-                        // value. Else call the result infinity
-                        // and punt it.
-                        // ( I presume this could happen because
-                        // rounding forces the result here to be
-                        // an ULP or two larger than
-                        // Double.MAX_VALUE ).
-                        //
-                        t = dValue / 2.0;
-                        t *= BIG_10_POW[j];
-                        if (Double.isInfinite(t)) {
-                            return (isNegative) ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
-                        }
-                        t = Double.MAX_VALUE;
-                    }
-                    dValue = t;
-                }
-            } else if (exp < 0) {
-                exp = -exp;
-                if (decExponent < MIN_DECIMAL_EXPONENT - 1) {
-                    //
-                    // Lets face it. This is going to be
-                    // zero. Cut to the chase.
-                    //
-                    return (isNegative) ? -0.0 : 0.0;
-                }
-                if ((exp & 15) != 0) {
-                    dValue /= SMALL_10_POW[exp & 15];
-                }
-                if ((exp >>= 4) != 0) {
-                    int j;
-                    for (j = 0; exp > 1; j++, exp >>= 1) {
-                        if ((exp & 1) != 0) {
-                            dValue *= TINY_10_POW[j];
-                        }
-                    }
-                    //
-                    // The reason for the weird exp > 1 condition
-                    // in the above loop was so that the last multiply
-                    // would get unrolled. We handle it here.
-                    // It could underflow.
-                    //
-                    double t = dValue * TINY_10_POW[j];
-                    if (t == 0.0) {
-                        //
-                        // It did underflow.
-                        // Look more closely at the result.
-                        // If the exponent is just one too small,
-                        // then use the minimum finite as our estimate
-                        // value. Else call the result 0.0
-                        // and punt it.
-                        // ( I presume this could happen because
-                        // rounding forces the result here to be
-                        // an ULP or two less than
-                        // Double.MIN_VALUE ).
-                        //
-                        t = dValue * 2.0;
-                        t *= TINY_10_POW[j];
-                        if (t == 0.0) {
-                            return (isNegative) ? -0.0 : 0.0;
-                        }
-                        t = Double.MIN_VALUE;
-                    }
-                    dValue = t;
-                }
-            }
-
-            //
-            // dValue is now approximately the result.
-            // The hard part is adjusting it, by comparison
-            // with FDBigInteger arithmetic.
-            // Formulate the EXACT big-number result as
-            // bigD0 * 10^exp
-            //
-            if (nDigits > MAX_NDIGITS) {
-                nDigits = MAX_NDIGITS + 1;
-                digits[MAX_NDIGITS] = '1';
-            }
-            FDBigInteger bigD0 = new FDBigInteger(lValue, digits, kDigits, nDigits);
-            exp = decExponent - nDigits;
-
-            long ieeeBits = Double.doubleToRawLongBits(dValue); // IEEE-754 bits of double candidate
-            final int B5 = Math.max(0, -exp); // powers of 5 in bigB, value is not modified inside correctionLoop
-            final int D5 = Math.max(0, exp); // powers of 5 in bigD, value is not modified inside correctionLoop
-            bigD0 = bigD0.multByPow52(D5, 0);
-            bigD0.makeImmutable();   // prevent bigD0 modification inside correctionLoop
-            FDBigInteger bigD = null;
-            int prevD2 = 0;
-
-            correctionLoop:
-            while (true) {
-                // here ieeeBits can't be NaN, Infinity or zero
-                int binexp = (int) (ieeeBits >>> EXP_SHIFT);
-                long bigBbits = ieeeBits & DoubleConsts.SIGNIF_BIT_MASK;
-                if (binexp > 0) {
-                    bigBbits |= FRACT_HOB;
-                } else { // Normalize denormalized numbers.
-                    assert bigBbits != 0L : bigBbits; // doubleToBigInt(0.0)
-                    int leadingZeros = Long.numberOfLeadingZeros(bigBbits);
-                    int shift = leadingZeros - (63 - EXP_SHIFT);
-                    bigBbits <<= shift;
-                    binexp = 1 - shift;
-                }
-                binexp -= DoubleConsts.EXP_BIAS;
-                int lowOrderZeros = Long.numberOfTrailingZeros(bigBbits);
-                bigBbits >>>= lowOrderZeros;
-                final int bigIntExp = binexp - EXP_SHIFT + lowOrderZeros;
-                final int bigIntNBits = EXP_SHIFT + 1 - lowOrderZeros;
-
-                //
-                // Scale bigD, bigB appropriately for
-                // big-integer operations.
-                // Naively, we multiply by powers of ten
-                // and powers of two. What we actually do
-                // is keep track of the powers of 5 and
-                // powers of 2 we would use, then factor out
-                // common divisors before doing the work.
-                //
-                int B2 = B5; // powers of 2 in bigB
-                int D2 = D5; // powers of 2 in bigD
-                int Ulp2;   // powers of 2 in halfUlp.
-                if (bigIntExp >= 0) {
-                    B2 += bigIntExp;
-                } else {
-                    D2 -= bigIntExp;
-                }
-                Ulp2 = B2;
-                // shift bigB and bigD left by a number s. t.
-                // halfUlp is still an integer.
-                int hulpbias;
-                if (binexp <= -DoubleConsts.EXP_BIAS) {
-                    // This is going to be a denormalized number
-                    // (if not actually zero).
-                    // half an ULP is at 2^-(DoubleConsts.EXP_BIAS+EXP_SHIFT+1)
-                    hulpbias = binexp + lowOrderZeros + DoubleConsts.EXP_BIAS;
-                } else {
-                    hulpbias = 1 + lowOrderZeros;
-                }
-                B2 += hulpbias;
-                D2 += hulpbias;
-                // if there are common factors of 2, we might just as well
-                // factor them out, as they add nothing useful.
-                int common2 = Math.min(B2, Math.min(D2, Ulp2));
-                B2 -= common2;
-                D2 -= common2;
-                Ulp2 -= common2;
-                // do multiplications by powers of 5 and 2
-                FDBigInteger bigB = FDBigInteger.valueOfMulPow52(bigBbits, B5, B2);
-                if (bigD == null || prevD2 != D2) {
-                    bigD = bigD0.leftShift(D2);
-                    prevD2 = D2;
-                }
-                //
-                // to recap:
-                // bigB is the scaled-big-int version of our floating-point
-                // candidate.
-                // bigD is the scaled-big-int version of the exact value
-                // as we understand it.
-                // halfUlp is 1/2 an ulp of bigB, except for special cases
-                // of exact powers of 2
-                //
-                // the plan is to compare bigB with bigD, and if the difference
-                // is less than halfUlp, then we're satisfied. Otherwise,
-                // use the ratio of difference to halfUlp to calculate a fudge
-                // factor to add to the floating value, then go 'round again.
-                //
-                FDBigInteger diff;
-                int cmpResult;
-                boolean overvalue;
-                if ((cmpResult = bigB.cmp(bigD)) > 0) {
-                    overvalue = true; // our candidate is too big.
-                    diff = bigB.leftInplaceSub(bigD); // bigB is not user further - reuse
-                    if ((bigIntNBits == 1) && (bigIntExp > -DoubleConsts.EXP_BIAS + 1)) {
-                        // candidate is a normalized exact power of 2 and
-                        // is too big (larger than Double.MIN_NORMAL). We will be subtracting.
-                        // For our purposes, ulp is the ulp of the
-                        // next smaller range.
-                        Ulp2 -= 1;
-                        if (Ulp2 < 0) {
-                            // rats. Cannot de-scale ulp this far.
-                            // must scale diff in other direction.
-                            Ulp2 = 0;
-                            diff = diff.leftShift(1);
-                        }
-                    }
-                } else if (cmpResult < 0) {
-                    overvalue = false; // our candidate is too small.
-                    diff = bigD.rightInplaceSub(bigB); // bigB is not user further - reuse
-                } else {
-                    // the candidate is exactly right!
-                    // this happens with surprising frequency
-                    break correctionLoop;
-                }
-                cmpResult = diff.cmpPow52(B5, Ulp2);
-                if ((cmpResult) < 0) {
-                    // difference is small.
-                    // this is close enough
-                    break correctionLoop;
-                } else if (cmpResult == 0) {
-                    // difference is exactly half an ULP
-                    // round to some other value maybe, then finish
-                    if ((ieeeBits & 1) != 0) { // half ties to even
-                        ieeeBits += overvalue ? -1 : 1; // nextDown or nextUp
-                    }
-                    break correctionLoop;
-                } else {
-                    // difference is non-trivial.
-                    // could scale addend by ratio of difference to
-                    // halfUlp here, if we bothered to compute that difference.
-                    // Most of the time ( I hope ) it is about 1 anyway.
-                    ieeeBits += overvalue ? -1 : 1; // nextDown or nextUp
-                    if (ieeeBits == 0 || ieeeBits == DoubleConsts.EXP_BIT_MASK) { // 0.0 or Double.POSITIVE_INFINITY
-                        break correctionLoop; // oops. Fell off end of range.
-                    }
-                    continue; // try again.
-                }
-
-            }
-            if (isNegative) {
-                ieeeBits |= DoubleConsts.SIGN_BIT_MASK;
-            }
-            return Double.longBitsToDouble(ieeeBits);
-        }
-
-        /**
-         * Takes a FloatingDecimal, which we presumably just scanned in,
-         * and finds out what its value is, as a float.
-         * This is distinct from doubleValue() to avoid the extremely
-         * unlikely case of a double rounding error, wherein the conversion
-         * to double has one rounding error, and the conversion of that double
-         * to a float has another rounding error, IN THE WRONG DIRECTION,
-         * ( because of the preference to a zero low-order bit ).
-         */
-        @Override
-        public float floatValue() {
-            int kDigits = Math.min(nDigits, SINGLE_MAX_DECIMAL_DIGITS + 1);
-            //
-            // convert the lead kDigits to an integer.
-            //
-            int iValue = (int) digits[0] - (int) '0';
-            for (int i = 1; i < kDigits; i++) {
-                iValue = iValue * 10 + (int) digits[i] - (int) '0';
-            }
-            float fValue = (float) iValue;
-            int exp = decExponent - kDigits;
-            //
-            // iValue now contains an integer with the value of
-            // the first kDigits digits of the number.
-            // fValue contains the (float) of the same.
-            //
-
-            if (nDigits <= SINGLE_MAX_DECIMAL_DIGITS) {
-                //
-                // possibly an easy case.
-                // We know that the digits can be represented
-                // exactly. And if the exponent isn't too outrageous,
-                // the whole thing can be done with one operation,
-                // thus one rounding error.
-                // Note that all our constructors trim all leading and
-                // trailing zeros, so simple values (including zero)
-                // will always end up here.
-                //
-                if (exp == 0 || fValue == 0.0f) {
-                    return (isNegative) ? -fValue : fValue; // small floating integer
-                } else if (exp >= 0) {
-                    if (exp <= SINGLE_MAX_SMALL_TEN) {
-                        //
-                        // Can get the answer with one operation,
-                        // thus one roundoff.
-                        //
-                        fValue *= SINGLE_SMALL_10_POW[exp];
-                        return (isNegative) ? -fValue : fValue;
-                    }
-                    int slop = SINGLE_MAX_DECIMAL_DIGITS - kDigits;
-                    if (exp <= SINGLE_MAX_SMALL_TEN + slop) {
-                        //
-                        // We can multiply fValue by 10^(slop)
-                        // and it is still "small" and exact.
-                        // Then we can multiply by 10^(exp-slop)
-                        // with one rounding.
-                        //
-                        fValue *= SINGLE_SMALL_10_POW[slop];
-                        fValue *= SINGLE_SMALL_10_POW[exp - slop];
-                        return (isNegative) ? -fValue : fValue;
-                    }
-                    //
-                    // Else we have a hard case with a positive exp.
-                    //
-                } else {
-                    if (exp >= -SINGLE_MAX_SMALL_TEN) {
-                        //
-                        // Can get the answer in one division.
-                        //
-                        fValue /= SINGLE_SMALL_10_POW[-exp];
-                        return (isNegative) ? -fValue : fValue;
-                    }
-                    //
-                    // Else we have a hard case with a negative exp.
-                    //
-                }
-            } else if ((decExponent >= nDigits) && (nDigits + decExponent <= MAX_DECIMAL_DIGITS)) {
-                //
-                // In double-precision, this is an exact floating integer.
-                // So we can compute to double, then shorten to float
-                // with one round, and get the right answer.
-                //
-                // First, finish accumulating digits.
-                // Then convert that integer to a double, multiply
-                // by the appropriate power of ten, and convert to float.
-                //
-                long lValue = (long) iValue;
-                for (int i = kDigits; i < nDigits; i++) {
-                    lValue = lValue * 10L + (long) ((int) digits[i] - (int) '0');
-                }
-                double dValue = (double) lValue;
-                exp = decExponent - nDigits;
-                dValue *= SMALL_10_POW[exp];
-                fValue = (float) dValue;
-                return (isNegative) ? -fValue : fValue;
-
-            }
-            //
-            // Harder cases:
-            // The sum of digits plus exponent is greater than
-            // what we think we can do with one error.
-            //
-            // Start by approximating the right answer by,
-            // naively, scaling by powers of 10.
-            // Scaling uses doubles to avoid overflow/underflow.
-            //
-            double dValue = fValue;
-            if (exp > 0) {
-                if (decExponent > SINGLE_MAX_DECIMAL_EXPONENT + 1) {
-                    //
-                    // Lets face it. This is going to be
-                    // Infinity. Cut to the chase.
-                    //
-                    return (isNegative) ? Float.NEGATIVE_INFINITY : Float.POSITIVE_INFINITY;
-                }
-                if ((exp & 15) != 0) {
-                    dValue *= SMALL_10_POW[exp & 15];
-                }
-                if ((exp >>= 4) != 0) {
-                    int j;
-                    for (j = 0; exp > 0; j++, exp >>= 1) {
-                        if ((exp & 1) != 0) {
-                            dValue *= BIG_10_POW[j];
-                        }
-                    }
-                }
-            } else if (exp < 0) {
-                exp = -exp;
-                if (decExponent < SINGLE_MIN_DECIMAL_EXPONENT - 1) {
-                    //
-                    // Lets face it. This is going to be
-                    // zero. Cut to the chase.
-                    //
-                    return (isNegative) ? -0.0f : 0.0f;
-                }
-                if ((exp & 15) != 0) {
-                    dValue /= SMALL_10_POW[exp & 15];
-                }
-                if ((exp >>= 4) != 0) {
-                    int j;
-                    for (j = 0; exp > 0; j++, exp >>= 1) {
-                        if ((exp & 1) != 0) {
-                            dValue *= TINY_10_POW[j];
-                        }
-                    }
-                }
-            }
-            fValue = Math.max(Float.MIN_VALUE, Math.min(Float.MAX_VALUE, (float) dValue));
-
-            //
-            // fValue is now approximately the result.
-            // The hard part is adjusting it, by comparison
-            // with FDBigInteger arithmetic.
-            // Formulate the EXACT big-number result as
-            // bigD0 * 10^exp
-            //
-            if (nDigits > SINGLE_MAX_NDIGITS) {
-                nDigits = SINGLE_MAX_NDIGITS + 1;
-                digits[SINGLE_MAX_NDIGITS] = '1';
-            }
-            FDBigInteger bigD0 = new FDBigInteger(iValue, digits, kDigits, nDigits);
-            exp = decExponent - nDigits;
-
-            int ieeeBits = Float.floatToRawIntBits(fValue); // IEEE-754 bits of float candidate
-            final int B5 = Math.max(0, -exp); // powers of 5 in bigB, value is not modified inside correctionLoop
-            final int D5 = Math.max(0, exp); // powers of 5 in bigD, value is not modified inside correctionLoop
-            bigD0 = bigD0.multByPow52(D5, 0);
-            bigD0.makeImmutable();   // prevent bigD0 modification inside correctionLoop
-            FDBigInteger bigD = null;
-            int prevD2 = 0;
-
-            correctionLoop:
-            while (true) {
-                // here ieeeBits can't be NaN, Infinity or zero
-                int binexp = ieeeBits >>> SINGLE_EXP_SHIFT;
-                int bigBbits = ieeeBits & FloatConsts.SIGNIF_BIT_MASK;
-                if (binexp > 0) {
-                    bigBbits |= SINGLE_FRACT_HOB;
-                } else { // Normalize denormalized numbers.
-                    assert bigBbits != 0 : bigBbits; // floatToBigInt(0.0)
-                    int leadingZeros = Integer.numberOfLeadingZeros(bigBbits);
-                    int shift = leadingZeros - (31 - SINGLE_EXP_SHIFT);
-                    bigBbits <<= shift;
-                    binexp = 1 - shift;
-                }
-                binexp -= FloatConsts.EXP_BIAS;
-                int lowOrderZeros = Integer.numberOfTrailingZeros(bigBbits);
-                bigBbits >>>= lowOrderZeros;
-                final int bigIntExp = binexp - SINGLE_EXP_SHIFT + lowOrderZeros;
-                final int bigIntNBits = SINGLE_EXP_SHIFT + 1 - lowOrderZeros;
-
-                //
-                // Scale bigD, bigB appropriately for
-                // big-integer operations.
-                // Naively, we multiply by powers of ten
-                // and powers of two. What we actually do
-                // is keep track of the powers of 5 and
-                // powers of 2 we would use, then factor out
-                // common divisors before doing the work.
-                //
-                int B2 = B5; // powers of 2 in bigB
-                int D2 = D5; // powers of 2 in bigD
-                int Ulp2;   // powers of 2 in halfUlp.
-                if (bigIntExp >= 0) {
-                    B2 += bigIntExp;
-                } else {
-                    D2 -= bigIntExp;
-                }
-                Ulp2 = B2;
-                // shift bigB and bigD left by a number s. t.
-                // halfUlp is still an integer.
-                int hulpbias;
-                if (binexp <= -FloatConsts.EXP_BIAS) {
-                    // This is going to be a denormalized number
-                    // (if not actually zero).
-                    // half an ULP is at 2^-(FloatConsts.EXP_BIAS+SINGLE_EXP_SHIFT+1)
-                    hulpbias = binexp + lowOrderZeros + FloatConsts.EXP_BIAS;
-                } else {
-                    hulpbias = 1 + lowOrderZeros;
-                }
-                B2 += hulpbias;
-                D2 += hulpbias;
-                // if there are common factors of 2, we might just as well
-                // factor them out, as they add nothing useful.
-                int common2 = Math.min(B2, Math.min(D2, Ulp2));
-                B2 -= common2;
-                D2 -= common2;
-                Ulp2 -= common2;
-                // do multiplications by powers of 5 and 2
-                FDBigInteger bigB = FDBigInteger.valueOfMulPow52(bigBbits, B5, B2);
-                if (bigD == null || prevD2 != D2) {
-                    bigD = bigD0.leftShift(D2);
-                    prevD2 = D2;
-                }
-                //
-                // to recap:
-                // bigB is the scaled-big-int version of our floating-point
-                // candidate.
-                // bigD is the scaled-big-int version of the exact value
-                // as we understand it.
-                // halfUlp is 1/2 an ulp of bigB, except for special cases
-                // of exact powers of 2
-                //
-                // the plan is to compare bigB with bigD, and if the difference
-                // is less than halfUlp, then we're satisfied. Otherwise,
-                // use the ratio of difference to halfUlp to calculate a fudge
-                // factor to add to the floating value, then go 'round again.
-                //
-                FDBigInteger diff;
-                int cmpResult;
-                boolean overvalue;
-                if ((cmpResult = bigB.cmp(bigD)) > 0) {
-                    overvalue = true; // our candidate is too big.
-                    diff = bigB.leftInplaceSub(bigD); // bigB is not user further - reuse
-                    if ((bigIntNBits == 1) && (bigIntExp > -FloatConsts.EXP_BIAS + 1)) {
-                        // candidate is a normalized exact power of 2 and
-                        // is too big (larger than Float.MIN_NORMAL). We will be subtracting.
-                        // For our purposes, ulp is the ulp of the
-                        // next smaller range.
-                        Ulp2 -= 1;
-                        if (Ulp2 < 0) {
-                            // rats. Cannot de-scale ulp this far.
-                            // must scale diff in other direction.
-                            Ulp2 = 0;
-                            diff = diff.leftShift(1);
-                        }
-                    }
-                } else if (cmpResult < 0) {
-                    overvalue = false; // our candidate is too small.
-                    diff = bigD.rightInplaceSub(bigB); // bigB is not user further - reuse
-                } else {
-                    // the candidate is exactly right!
-                    // this happens with surprising frequency
-                    break correctionLoop;
-                }
-                cmpResult = diff.cmpPow52(B5, Ulp2);
-                if ((cmpResult) < 0) {
-                    // difference is small.
-                    // this is close enough
-                    break correctionLoop;
-                } else if (cmpResult == 0) {
-                    // difference is exactly half an ULP
-                    // round to some other value maybe, then finish
-                    if ((ieeeBits & 1) != 0) { // half ties to even
-                        ieeeBits += overvalue ? -1 : 1; // nextDown or nextUp
-                    }
-                    break correctionLoop;
-                } else {
-                    // difference is non-trivial.
-                    // could scale addend by ratio of difference to
-                    // halfUlp here, if we bothered to compute that difference.
-                    // Most of the time ( I hope ) it is about 1 anyway.
-                    ieeeBits += overvalue ? -1 : 1; // nextDown or nextUp
-                    if (ieeeBits == 0 || ieeeBits == FloatConsts.EXP_BIT_MASK) { // 0.0 or Float.POSITIVE_INFINITY
-                        break correctionLoop; // oops. Fell off end of range.
-                    }
-                    continue; // try again.
-                }
-
-            }
-            if (isNegative) {
-                ieeeBits |= FloatConsts.SIGN_BIT_MASK;
-            }
-            return Float.intBitsToFloat(ieeeBits);
-        }
-
-
-        /**
-         * All the positive powers of 10 that can be
-         * represented exactly in double/float.
-         */
-        private static final double[] SMALL_10_POW = {
-            1.0e0,
-            1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5,
-            1.0e6, 1.0e7, 1.0e8, 1.0e9, 1.0e10,
-            1.0e11, 1.0e12, 1.0e13, 1.0e14, 1.0e15,
-            1.0e16, 1.0e17, 1.0e18, 1.0e19, 1.0e20,
-            1.0e21, 1.0e22
-        };
-
-        private static final float[] SINGLE_SMALL_10_POW = {
-            1.0e0f,
-            1.0e1f, 1.0e2f, 1.0e3f, 1.0e4f, 1.0e5f,
-            1.0e6f, 1.0e7f, 1.0e8f, 1.0e9f, 1.0e10f
-        };
-
-        private static final double[] BIG_10_POW = {
-            1e16, 1e32, 1e64, 1e128, 1e256 };
-        private static final double[] TINY_10_POW = {
-            1e-16, 1e-32, 1e-64, 1e-128, 1e-256 };
-
-        private static final int MAX_SMALL_TEN = SMALL_10_POW.length-1;
-        private static final int SINGLE_MAX_SMALL_TEN = SINGLE_SMALL_10_POW.length-1;
-
-    }
-
-    /**
-     * Returns a <code>BinaryToASCIIConverter</code> for a <code>double</code>.
-     * The returned object is a <code>ThreadLocal</code> variable of this class.
-     *
-     * @param d The double precision value to convert.
-     * @return The converter.
-     */
-    public static BinaryToASCIIConverter getBinaryToASCIIConverter(double d) {
-        return getBinaryToASCIIConverter(d, true);
-    }
-
-    /**
-     * Returns a <code>BinaryToASCIIConverter</code> for a <code>double</code>.
-     * The returned object is a <code>ThreadLocal</code> variable of this class.
-     *
-     * @param d The double precision value to convert.
-     * @param isCompatibleFormat
-     * @return The converter.
-     */
-    static BinaryToASCIIConverter getBinaryToASCIIConverter(double d, boolean isCompatibleFormat) {
-        long dBits = Double.doubleToRawLongBits(d);
-        boolean isNegative = (dBits&DoubleConsts.SIGN_BIT_MASK) != 0; // discover sign
-        long fractBits = dBits & DoubleConsts.SIGNIF_BIT_MASK;
-        int  binExp = (int)( (dBits&DoubleConsts.EXP_BIT_MASK) >> EXP_SHIFT );
-        // Discover obvious special cases of NaN and Infinity.
-        if ( binExp == (int)(DoubleConsts.EXP_BIT_MASK>>EXP_SHIFT) ) {
-            if ( fractBits == 0L ){
-                return isNegative ? B2AC_NEGATIVE_INFINITY : B2AC_POSITIVE_INFINITY;
-            } else {
-                return B2AC_NOT_A_NUMBER;
-            }
-        }
-        // Finish unpacking
-        // Normalize denormalized numbers.
-        // Insert assumed high-order bit for normalized numbers.
-        // Subtract exponent bias.
-        int  nSignificantBits;
-        if ( binExp == 0 ){
-            if ( fractBits == 0L ){
-                // not a denorm, just a 0!
-                return isNegative ? B2AC_NEGATIVE_ZERO : B2AC_POSITIVE_ZERO;
-            }
-            int leadingZeros = Long.numberOfLeadingZeros(fractBits);
-            int shift = leadingZeros-(63-EXP_SHIFT);
-            fractBits <<= shift;
-            binExp = 1 - shift;
-            nSignificantBits =  64-leadingZeros; // recall binExp is  - shift count.
-        } else {
-            fractBits |= FRACT_HOB;
-            nSignificantBits = EXP_SHIFT+1;
-        }
-        binExp -= DoubleConsts.EXP_BIAS;
-        BinaryToASCIIBuffer buf = getBinaryToASCIIBuffer();
-        buf.setSign(isNegative);
-        // call the routine that actually does all the hard work.
-        buf.dtoa(binExp, fractBits, nSignificantBits, isCompatibleFormat);
-        return buf;
-    }
-
-    private static BinaryToASCIIConverter getBinaryToASCIIConverter(float f) {
-        int fBits = Float.floatToRawIntBits( f );
-        boolean isNegative = (fBits&FloatConsts.SIGN_BIT_MASK) != 0;
-        int fractBits = fBits&FloatConsts.SIGNIF_BIT_MASK;
-        int binExp = (fBits&FloatConsts.EXP_BIT_MASK) >> SINGLE_EXP_SHIFT;
-        // Discover obvious special cases of NaN and Infinity.
-        if ( binExp == (FloatConsts.EXP_BIT_MASK>>SINGLE_EXP_SHIFT) ) {
-            if ( fractBits == 0L ){
-                return isNegative ? B2AC_NEGATIVE_INFINITY : B2AC_POSITIVE_INFINITY;
-            } else {
-                return B2AC_NOT_A_NUMBER;
-            }
-        }
-        // Finish unpacking
-        // Normalize denormalized numbers.
-        // Insert assumed high-order bit for normalized numbers.
-        // Subtract exponent bias.
-        int  nSignificantBits;
-        if ( binExp == 0 ){
-            if ( fractBits == 0 ){
-                // not a denorm, just a 0!
-                return isNegative ? B2AC_NEGATIVE_ZERO : B2AC_POSITIVE_ZERO;
-            }
-            int leadingZeros = Integer.numberOfLeadingZeros(fractBits);
-            int shift = leadingZeros-(31-SINGLE_EXP_SHIFT);
-            fractBits <<= shift;
-            binExp = 1 - shift;
-            nSignificantBits =  32 - leadingZeros; // recall binExp is  - shift count.
-        } else {
-            fractBits |= SINGLE_FRACT_HOB;
-            nSignificantBits = SINGLE_EXP_SHIFT+1;
-        }
-        binExp -= FloatConsts.EXP_BIAS;
-        BinaryToASCIIBuffer buf = getBinaryToASCIIBuffer();
-        buf.setSign(isNegative);
-        // call the routine that actually does all the hard work.
-        buf.dtoa(binExp, ((long)fractBits)<<(EXP_SHIFT-SINGLE_EXP_SHIFT), nSignificantBits, true);
-        return buf;
-    }
-
-    @SuppressWarnings("fallthrough")
-    static ASCIIToBinaryConverter readJavaFormatString( String in ) throws NumberFormatException {
-        boolean isNegative = false;
-        boolean signSeen   = false;
-        int     decExp;
-        char    c;
-
-    parseNumber:
-        try{
-            in = in.trim(); // don't fool around with white space.
-                            // throws NullPointerException if null
-            int len = in.length();
-            if ( len == 0 ) {
-                throw new NumberFormatException("empty String");
-            }
-            int i = 0;
-            switch (in.charAt(i)){
-            case '-':
-                isNegative = true;
-                //FALLTHROUGH
-            case '+':
-                i++;
-                signSeen = true;
-            }
-            c = in.charAt(i);
-            if(c == 'N') { // Check for NaN
-                if((len-i)==NAN_LENGTH && in.indexOf(NAN_REP,i)==i) {
-                    return A2BC_NOT_A_NUMBER;
-                }
-                // something went wrong, throw exception
-                break parseNumber;
-            } else if(c == 'I') { // Check for Infinity strings
-                if((len-i)==INFINITY_LENGTH && in.indexOf(INFINITY_REP,i)==i) {
-                    return isNegative? A2BC_NEGATIVE_INFINITY : A2BC_POSITIVE_INFINITY;
-                }
-                // something went wrong, throw exception
-                break parseNumber;
-            } else if (c == '0')  { // check for hexadecimal floating-point number
-                if (len > i+1 ) {
-                    char ch = in.charAt(i+1);
-                    if (ch == 'x' || ch == 'X' ) { // possible hex string
-                        return parseHexString(in);
-                    }
-                }
-            }  // look for and process decimal floating-point string
-
-            char[] digits = new char[ len ];
-            int    nDigits= 0;
-            boolean decSeen = false;
-            int decPt = 0;
-            int nLeadZero = 0;
-            int nTrailZero= 0;
-
-        skipLeadingZerosLoop:
-            while (i < len) {
-                c = in.charAt(i);
-                if (c == '0') {
-                    nLeadZero++;
-                } else if (c == '.') {
-                    if (decSeen) {
-                        // already saw one ., this is the 2nd.
-                        throw new NumberFormatException("multiple points");
-                    }
-                    decPt = i;
-                    if (signSeen) {
-                        decPt -= 1;
-                    }
-                    decSeen = true;
-                } else {
-                    break skipLeadingZerosLoop;
-                }
-                i++;
-            }
-        digitLoop:
-            while (i < len) {
-                c = in.charAt(i);
-                if (c >= '1' && c <= '9') {
-                    digits[nDigits++] = c;
-                    nTrailZero = 0;
-                } else if (c == '0') {
-                    digits[nDigits++] = c;
-                    nTrailZero++;
-                } else if (c == '.') {
-                    if (decSeen) {
-                        // already saw one ., this is the 2nd.
-                        throw new NumberFormatException("multiple points");
-                    }
-                    decPt = i;
-                    if (signSeen) {
-                        decPt -= 1;
-                    }
-                    decSeen = true;
-                } else {
-                    break digitLoop;
-                }
-                i++;
-            }
-            nDigits -=nTrailZero;
-            //
-            // At this point, we've scanned all the digits and decimal
-            // point we're going to see. Trim off leading and trailing
-            // zeros, which will just confuse us later, and adjust
-            // our initial decimal exponent accordingly.
-            // To review:
-            // we have seen i total characters.
-            // nLeadZero of them were zeros before any other digits.
-            // nTrailZero of them were zeros after any other digits.
-            // if ( decSeen ), then a . was seen after decPt characters
-            // ( including leading zeros which have been discarded )
-            // nDigits characters were neither lead nor trailing
-            // zeros, nor point
-            //
-            //
-            // special hack: if we saw no non-zero digits, then the
-            // answer is zero!
-            // Unfortunately, we feel honor-bound to keep parsing!
-            //
-            boolean isZero = (nDigits == 0);
-            if ( isZero &&  nLeadZero == 0 ){
-                // we saw NO DIGITS AT ALL,
-                // not even a crummy 0!
-                // this is not allowed.
-                break parseNumber; // go throw exception
-            }
-            //
-            // Our initial exponent is decPt, adjusted by the number of
-            // discarded zeros. Or, if there was no decPt,
-            // then its just nDigits adjusted by discarded trailing zeros.
-            //
-            if ( decSeen ){
-                decExp = decPt - nLeadZero;
-            } else {
-                decExp = nDigits + nTrailZero;
-            }
-
-            //
-            // Look for 'e' or 'E' and an optionally signed integer.
-            //
-            if ( (i < len) &&  (((c = in.charAt(i) )=='e') || (c == 'E') ) ){
-                int expSign = 1;
-                int expVal  = 0;
-                int reallyBig = Integer.MAX_VALUE / 10;
-                boolean expOverflow = false;
-                switch( in.charAt(++i) ){
-                case '-':
-                    expSign = -1;
-                    //FALLTHROUGH
-                case '+':
-                    i++;
-                }
-                int expAt = i;
-            expLoop:
-                while ( i < len  ){
-                    if ( expVal >= reallyBig ){
-                        // the next character will cause integer
-                        // overflow.
-                        expOverflow = true;
-                    }
-                    c = in.charAt(i++);
-                    if(c>='0' && c<='9') {
-                        expVal = expVal*10 + ( (int)c - (int)'0' );
-                    } else {
-                        i--;           // back up.
-                        break expLoop; // stop parsing exponent.
-                    }
-                }
-                int expLimit = BIG_DECIMAL_EXPONENT + nDigits + nTrailZero;
-                if (expOverflow || (expVal > expLimit)) {
-                    // There is still a chance that the exponent will be safe to
-                    // use: if it would eventually decrease due to a negative
-                    // decExp, and that number is below the limit.  We check for
-                    // that here.
-                    if (!expOverflow && (expSign == 1 && decExp < 0)
-                            && (expVal + decExp) < expLimit) {
-                        // Cannot overflow: adding a positive and negative number.
-                        decExp += expVal;
-                    } else {
-                        //
-                        // The intent here is to end up with
-                        // infinity or zero, as appropriate.
-                        // The reason for yielding such a small decExponent,
-                        // rather than something intuitive such as
-                        // expSign*Integer.MAX_VALUE, is that this value
-                        // is subject to further manipulation in
-                        // doubleValue() and floatValue(), and I don't want
-                        // it to be able to cause overflow there!
-                        // (The only way we can get into trouble here is for
-                        // really outrageous nDigits+nTrailZero, such as 2
-                        // billion.)
-                        //
-                        decExp = expSign * expLimit;
-                    }
-                } else {
-                    // this should not overflow, since we tested
-                    // for expVal > (MAX+N), where N >= abs(decExp)
-                    decExp = decExp + expSign*expVal;
-                }
-
-                // if we saw something not a digit ( or end of string )
-                // after the [Ee][+-], without seeing any digits at all
-                // this is certainly an error. If we saw some digits,
-                // but then some trailing garbage, that might be ok.
-                // so we just fall through in that case.
-                // HUMBUG
-                if ( i == expAt ) {
-                    break parseNumber; // certainly bad
-                }
-            }
-            //
-            // We parsed everything we could.
-            // If there are leftovers, then this is not good input!
-            //
-            if ( i < len &&
-                ((i != len - 1) ||
-                (in.charAt(i) != 'f' &&
-                 in.charAt(i) != 'F' &&
-                 in.charAt(i) != 'd' &&
-                 in.charAt(i) != 'D'))) {
-                break parseNumber; // go throw exception
-            }
-            if(isZero) {
-                return isNegative ? A2BC_NEGATIVE_ZERO : A2BC_POSITIVE_ZERO;
-            }
-            return new ASCIIToBinaryBuffer(isNegative, decExp, digits, nDigits);
-        } catch ( StringIndexOutOfBoundsException e ){ }
-        throw new NumberFormatException("For input string: \"" + in + "\"");
-    }
-
-    private static class HexFloatPattern {
-        /**
-         * Grammar is compatible with hexadecimal floating-point constants
-         * described in section 6.4.4.2 of the C99 specification.
-         */
-        private static final Pattern VALUE = Pattern.compile(
-                   //1           234                   56                7                   8      9
-                    "([-+])?0[xX](((\\p{XDigit}+)\\.?)|((\\p{XDigit}*)\\.(\\p{XDigit}+)))[pP]([-+])?(\\p{Digit}+)[fFdD]?"
-                    );
-    }
-
-    /**
-     * Converts string s to a suitable floating decimal; uses the
-     * double constructor and sets the roundDir variable appropriately
-     * in case the value is later converted to a float.
-     *
-     * @param s The <code>String</code> to parse.
-     */
-   static ASCIIToBinaryConverter parseHexString(String s) {
-            // Verify string is a member of the hexadecimal floating-point
-            // string language.
-            Matcher m = HexFloatPattern.VALUE.matcher(s);
-            boolean validInput = m.matches();
-            if (!validInput) {
-                // Input does not match pattern
-                throw new NumberFormatException("For input string: \"" + s + "\"");
-            } else { // validInput
-                //
-                // We must isolate the sign, significand, and exponent
-                // fields.  The sign value is straightforward.  Since
-                // floating-point numbers are stored with a normalized
-                // representation, the significand and exponent are
-                // interrelated.
-                //
-                // After extracting the sign, we normalized the
-                // significand as a hexadecimal value, calculating an
-                // exponent adjust for any shifts made during
-                // normalization.  If the significand is zero, the
-                // exponent doesn't need to be examined since the output
-                // will be zero.
-                //
-                // Next the exponent in the input string is extracted.
-                // Afterwards, the significand is normalized as a *binary*
-                // value and the input value's normalized exponent can be
-                // computed.  The significand bits are copied into a
-                // double significand; if the string has more logical bits
-                // than can fit in a double, the extra bits affect the
-                // round and sticky bits which are used to round the final
-                // value.
-                //
-                //  Extract significand sign
-                String group1 = m.group(1);
-                boolean isNegative = ((group1 != null) && group1.equals("-"));
-
-                //  Extract Significand magnitude
-                //
-                // Based on the form of the significand, calculate how the
-                // binary exponent needs to be adjusted to create a
-                // normalized//hexadecimal* floating-point number; that
-                // is, a number where there is one nonzero hex digit to
-                // the left of the (hexa)decimal point.  Since we are
-                // adjusting a binary, not hexadecimal exponent, the
-                // exponent is adjusted by a multiple of 4.
-                //
-                // There are a number of significand scenarios to consider;
-                // letters are used in indicate nonzero digits:
-                //
-                // 1. 000xxxx       =>      x.xxx   normalized
-                //    increase exponent by (number of x's - 1)*4
-                //
-                // 2. 000xxx.yyyy =>        x.xxyyyy        normalized
-                //    increase exponent by (number of x's - 1)*4
-                //
-                // 3. .000yyy  =>   y.yy    normalized
-                //    decrease exponent by (number of zeros + 1)*4
-                //
-                // 4. 000.00000yyy => y.yy normalized
-                //    decrease exponent by (number of zeros to right of point + 1)*4
-                //
-                // If the significand is exactly zero, return a properly
-                // signed zero.
-                //
-
-                String significandString = null;
-                int signifLength = 0;
-                int exponentAdjust = 0;
-                {
-                    int leftDigits = 0; // number of meaningful digits to
-                    // left of "decimal" point
-                    // (leading zeros stripped)
-                    int rightDigits = 0; // number of digits to right of
-                    // "decimal" point; leading zeros
-                    // must always be accounted for
-                    //
-                    // The significand is made up of either
-                    //
-                    // 1. group 4 entirely (integer portion only)
-                    //
-                    // OR
-                    //
-                    // 2. the fractional portion from group 7 plus any
-                    // (optional) integer portions from group 6.
-                    //
-                    String group4;
-                    if ((group4 = m.group(4)) != null) {  // Integer-only significand
-                        // Leading zeros never matter on the integer portion
-                        significandString = stripLeadingZeros(group4);
-                        leftDigits = significandString.length();
-                    } else {
-                        // Group 6 is the optional integer; leading zeros
-                        // never matter on the integer portion
-                        String group6 = stripLeadingZeros(m.group(6));
-                        leftDigits = group6.length();
-
-                        // fraction
-                        String group7 = m.group(7);
-                        rightDigits = group7.length();
-
-                        // Turn "integer.fraction" into "integer"+"fraction"
-                        significandString =
-                                ((group6 == null) ? "" : group6) + // is the null
-                                        // check necessary?
-                                        group7;
-                    }
-
-                    significandString = stripLeadingZeros(significandString);
-                    signifLength = significandString.length();
-
-                    //
-                    // Adjust exponent as described above
-                    //
-                    if (leftDigits >= 1) {  // Cases 1 and 2
-                        exponentAdjust = 4 * (leftDigits - 1);
-                    } else {                // Cases 3 and 4
-                        exponentAdjust = -4 * (rightDigits - signifLength + 1);
-                    }
-
-                    // If the significand is zero, the exponent doesn't
-                    // matter; return a properly signed zero.
-
-                    if (signifLength == 0) { // Only zeros in input
-                        return isNegative ? A2BC_NEGATIVE_ZERO : A2BC_POSITIVE_ZERO;
-                    }
-                }
-
-                //  Extract Exponent
-                //
-                // Use an int to read in the exponent value; this should
-                // provide more than sufficient range for non-contrived
-                // inputs.  If reading the exponent in as an int does
-                // overflow, examine the sign of the exponent and
-                // significand to determine what to do.
-                //
-                String group8 = m.group(8);
-                boolean positiveExponent = (group8 == null) || group8.equals("+");
-                long unsignedRawExponent;
-                try {
-                    unsignedRawExponent = Integer.parseInt(m.group(9));
-                }
-                catch (NumberFormatException e) {
-                    // At this point, we know the exponent is
-                    // syntactically well-formed as a sequence of
-                    // digits.  Therefore, if an NumberFormatException
-                    // is thrown, it must be due to overflowing int's
-                    // range.  Also, at this point, we have already
-                    // checked for a zero significand.  Thus the signs
-                    // of the exponent and significand determine the
-                    // final result:
-                    //
-                    //                      significand
-                    //                      +               -
-                    // exponent     +       +infinity       -infinity
-                    //              -       +0.0            -0.0
-                    return isNegative ?
-                              (positiveExponent ? A2BC_NEGATIVE_INFINITY : A2BC_NEGATIVE_ZERO)
-                            : (positiveExponent ? A2BC_POSITIVE_INFINITY : A2BC_POSITIVE_ZERO);
-
-                }
-
-                long rawExponent =
-                        (positiveExponent ? 1L : -1L) * // exponent sign
-                                unsignedRawExponent;            // exponent magnitude
-
-                // Calculate partially adjusted exponent
-                long exponent = rawExponent + exponentAdjust;
-
-                // Starting copying non-zero bits into proper position in
-                // a long; copy explicit bit too; this will be masked
-                // later for normal values.
-
-                boolean round = false;
-                boolean sticky = false;
-                int nextShift = 0;
-                long significand = 0L;
-                // First iteration is different, since we only copy
-                // from the leading significand bit; one more exponent
-                // adjust will be needed...
-
-                // IMPORTANT: make leadingDigit a long to avoid
-                // surprising shift semantics!
-                long leadingDigit = getHexDigit(significandString, 0);
-
-                //
-                // Left shift the leading digit (53 - (bit position of
-                // leading 1 in digit)); this sets the top bit of the
-                // significand to 1.  The nextShift value is adjusted
-                // to take into account the number of bit positions of
-                // the leadingDigit actually used.  Finally, the
-                // exponent is adjusted to normalize the significand
-                // as a binary value, not just a hex value.
-                //
-                if (leadingDigit == 1) {
-                    significand |= leadingDigit << 52;
-                    nextShift = 52 - 4;
-                    // exponent += 0
-                } else if (leadingDigit <= 3) { // [2, 3]
-                    significand |= leadingDigit << 51;
-                    nextShift = 52 - 5;
-                    exponent += 1;
-                } else if (leadingDigit <= 7) { // [4, 7]
-                    significand |= leadingDigit << 50;
-                    nextShift = 52 - 6;
-                    exponent += 2;
-                } else if (leadingDigit <= 15) { // [8, f]
-                    significand |= leadingDigit << 49;
-                    nextShift = 52 - 7;
-                    exponent += 3;
-                } else {
-                    throw new AssertionError("Result from digit conversion too large!");
-                }
-                // The preceding if-else could be replaced by a single
-                // code block based on the high-order bit set in
-                // leadingDigit.  Given leadingOnePosition,
-
-                // significand |= leadingDigit << (SIGNIFICAND_WIDTH - leadingOnePosition);
-                // nextShift = 52 - (3 + leadingOnePosition);
-                // exponent += (leadingOnePosition-1);
-
-                //
-                // Now the exponent variable is equal to the normalized
-                // binary exponent.  Code below will make representation
-                // adjustments if the exponent is incremented after
-                // rounding (includes overflows to infinity) or if the
-                // result is subnormal.
-                //
-
-                // Copy digit into significand until the significand can't
-                // hold another full hex digit or there are no more input
-                // hex digits.
-                int i = 0;
-                for (i = 1;
-                     i < signifLength && nextShift >= 0;
-                     i++) {
-                    long currentDigit = getHexDigit(significandString, i);
-                    significand |= (currentDigit << nextShift);
-                    nextShift -= 4;
-                }
-
-                // After the above loop, the bulk of the string is copied.
-                // Now, we must copy any partial hex digits into the
-                // significand AND compute the round bit and start computing
-                // sticky bit.
-
-                if (i < signifLength) { // at least one hex input digit exists
-                    long currentDigit = getHexDigit(significandString, i);
-
-                    // from nextShift, figure out how many bits need
-                    // to be copied, if any
-                    switch (nextShift) { // must be negative
-                        case -1:
-                            // three bits need to be copied in; can
-                            // set round bit
-                            significand |= ((currentDigit & 0xEL) >> 1);
-                            round = (currentDigit & 0x1L) != 0L;
-                            break;
-
-                        case -2:
-                            // two bits need to be copied in; can
-                            // set round and start sticky
-                            significand |= ((currentDigit & 0xCL) >> 2);
-                            round = (currentDigit & 0x2L) != 0L;
-                            sticky = (currentDigit & 0x1L) != 0;
-                            break;
-
-                        case -3:
-                            // one bit needs to be copied in
-                            significand |= ((currentDigit & 0x8L) >> 3);
-                            // Now set round and start sticky, if possible
-                            round = (currentDigit & 0x4L) != 0L;
-                            sticky = (currentDigit & 0x3L) != 0;
-                            break;
-
-                        case -4:
-                            // all bits copied into significand; set
-                            // round and start sticky
-                            round = ((currentDigit & 0x8L) != 0);  // is top bit set?
-                            // nonzeros in three low order bits?
-                            sticky = (currentDigit & 0x7L) != 0;
-                            break;
-
-                        default:
-                            throw new AssertionError("Unexpected shift distance remainder.");
-                            // break;
-                    }
-
-                    // Round is set; sticky might be set.
-
-                    // For the sticky bit, it suffices to check the
-                    // current digit and test for any nonzero digits in
-                    // the remaining unprocessed input.
-                    i++;
-                    while (i < signifLength && !sticky) {
-                        currentDigit = getHexDigit(significandString, i);
-                        sticky = sticky || (currentDigit != 0);
-                        i++;
-                    }
-
-                }
-                // else all of string was seen, round and sticky are
-                // correct as false.
-
-                // Float calculations
-                int floatBits = isNegative ? FloatConsts.SIGN_BIT_MASK : 0;
-                if (exponent >= FloatConsts.MIN_EXPONENT) {
-                    if (exponent > FloatConsts.MAX_EXPONENT) {
-                        // Float.POSITIVE_INFINITY
-                        floatBits |= FloatConsts.EXP_BIT_MASK;
-                    } else {
-                        int threshShift = DoubleConsts.SIGNIFICAND_WIDTH - FloatConsts.SIGNIFICAND_WIDTH - 1;
-                        boolean floatSticky = (significand & ((1L << threshShift) - 1)) != 0 || round || sticky;
-                        int iValue = (int) (significand >>> threshShift);
-                        if ((iValue & 3) != 1 || floatSticky) {
-                            iValue++;
-                        }
-                        floatBits |= (((((int) exponent) + (FloatConsts.EXP_BIAS - 1))) << SINGLE_EXP_SHIFT) + (iValue >> 1);
-                    }
-                } else {
-                    if (exponent < FloatConsts.MIN_SUB_EXPONENT - 1) {
-                        // 0
-                    } else {
-                        // exponent == -127 ==> threshShift = 53 - 2 + (-149) - (-127) = 53 - 24
-                        int threshShift = (int) ((DoubleConsts.SIGNIFICAND_WIDTH - 2 + FloatConsts.MIN_SUB_EXPONENT) - exponent);
-                        assert threshShift >= DoubleConsts.SIGNIFICAND_WIDTH - FloatConsts.SIGNIFICAND_WIDTH;
-                        assert threshShift < DoubleConsts.SIGNIFICAND_WIDTH;
-                        boolean floatSticky = (significand & ((1L << threshShift) - 1)) != 0 || round || sticky;
-                        int iValue = (int) (significand >>> threshShift);
-                        if ((iValue & 3) != 1 || floatSticky) {
-                            iValue++;
-                        }
-                        floatBits |= iValue >> 1;
-                    }
-                }
-                float fValue = Float.intBitsToFloat(floatBits);
-
-                // Check for overflow and update exponent accordingly.
-                if (exponent > DoubleConsts.MAX_EXPONENT) {         // Infinite result
-                    // overflow to properly signed infinity
-                    return isNegative ? A2BC_NEGATIVE_INFINITY : A2BC_POSITIVE_INFINITY;
-                } else {  // Finite return value
-                    if (exponent <= DoubleConsts.MAX_EXPONENT && // (Usually) normal result
-                            exponent >= DoubleConsts.MIN_EXPONENT) {
-
-                        // The result returned in this block cannot be a
-                        // zero or subnormal; however after the
-                        // significand is adjusted from rounding, we could
-                        // still overflow in infinity.
-
-                        // AND exponent bits into significand; if the
-                        // significand is incremented and overflows from
-                        // rounding, this combination will update the
-                        // exponent correctly, even in the case of
-                        // Double.MAX_VALUE overflowing to infinity.
-
-                        significand = ((( exponent +
-                                (long) DoubleConsts.EXP_BIAS) <<
-                                (DoubleConsts.SIGNIFICAND_WIDTH - 1))
-                                & DoubleConsts.EXP_BIT_MASK) |
-                                (DoubleConsts.SIGNIF_BIT_MASK & significand);
-
-                    } else {  // Subnormal or zero
-                        // (exponent < DoubleConsts.MIN_EXPONENT)
-
-                        if (exponent < (DoubleConsts.MIN_SUB_EXPONENT - 1)) {
-                            // No way to round back to nonzero value
-                            // regardless of significand if the exponent is
-                            // less than -1075.
-                            return isNegative ? A2BC_NEGATIVE_ZERO : A2BC_POSITIVE_ZERO;
-                        } else { //  -1075 <= exponent <= MIN_EXPONENT -1 = -1023
-                            //
-                            // Find bit position to round to; recompute
-                            // round and sticky bits, and shift
-                            // significand right appropriately.
-                            //
-
-                            sticky = sticky || round;
-                            round = false;
-
-                            // Number of bits of significand to preserve is
-                            // exponent - abs_min_exp +1
-                            // check:
-                            // -1075 +1074 + 1 = 0
-                            // -1023 +1074 + 1 = 52
-
-                            int bitsDiscarded = 53 -
-                                    ((int) exponent - DoubleConsts.MIN_SUB_EXPONENT + 1);
-                            assert bitsDiscarded >= 1 && bitsDiscarded <= 53;
-
-                            // What to do here:
-                            // First, isolate the new round bit
-                            round = (significand & (1L << (bitsDiscarded - 1))) != 0L;
-                            if (bitsDiscarded > 1) {
-                                // create mask to update sticky bits; low
-                                // order bitsDiscarded bits should be 1
-                                long mask = ~((~0L) << (bitsDiscarded - 1));
-                                sticky = sticky || ((significand & mask) != 0L);
-                            }
-
-                            // Now, discard the bits
-                            significand = significand >> bitsDiscarded;
-
-                            significand = ((((long) (DoubleConsts.MIN_EXPONENT - 1) + // subnorm exp.
-                                    (long) DoubleConsts.EXP_BIAS) <<
-                                    (DoubleConsts.SIGNIFICAND_WIDTH - 1))
-                                    & DoubleConsts.EXP_BIT_MASK) |
-                                    (DoubleConsts.SIGNIF_BIT_MASK & significand);
-                        }
-                    }
-
-                    // The significand variable now contains the currently
-                    // appropriate exponent bits too.
-
-                    //
-                    // Determine if significand should be incremented;
-                    // making this determination depends on the least
-                    // significant bit and the round and sticky bits.
-                    //
-                    // Round to nearest even rounding table, adapted from
-                    // table 4.7 in "Computer Arithmetic" by IsraelKoren.
-                    // The digit to the left of the "decimal" point is the
-                    // least significant bit, the digits to the right of
-                    // the point are the round and sticky bits
-                    //
-                    // Number       Round(x)
-                    // x0.00        x0.
-                    // x0.01        x0.
-                    // x0.10        x0.
-                    // x0.11        x1. = x0. +1
-                    // x1.00        x1.
-                    // x1.01        x1.
-                    // x1.10        x1. + 1
-                    // x1.11        x1. + 1
-                    //
-                    boolean leastZero = ((significand & 1L) == 0L);
-                    if ((leastZero && round && sticky) ||
-                            ((!leastZero) && round)) {
-                        significand++;
-                    }
-
-                    double value = isNegative ?
-                            Double.longBitsToDouble(significand | DoubleConsts.SIGN_BIT_MASK) :
-                            Double.longBitsToDouble(significand );
-
-                    return new PreparedASCIIToBinaryBuffer(value, fValue);
-                }
-            }
-    }
-
-    /**
-     * Returns <code>s</code> with any leading zeros removed.
-     */
-    static String stripLeadingZeros(String s) {
-//        return  s.replaceFirst("^0+", "");
-        if(!s.isEmpty() && s.charAt(0)=='0') {
-            for(int i=1; i<s.length(); i++) {
-                if(s.charAt(i)!='0') {
-                    return s.substring(i);
-                }
-            }
-            return "";
-        }
-        return s;
-    }
-
-    /**
-     * Extracts a hexadecimal digit from position <code>position</code>
-     * of string <code>s</code>.
-     */
-    static int getHexDigit(String s, int position) {
-        int value = Character.digit(s.charAt(position), 16);
-        if (value <= -1 || value >= 16) {
-            throw new AssertionError("Unexpected failure of digit conversion of " +
-                                     s.charAt(position));
-        }
-        return value;
-    }
-}
--- a/jdk/src/java.base/share/classes/sun/misc/FormattedFloatingDecimal.java	Thu Dec 24 10:33:21 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,349 +0,0 @@
-/*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.misc;
-
-import java.util.Arrays;
-
-public class FormattedFloatingDecimal{
-
-    public enum Form { SCIENTIFIC, COMPATIBLE, DECIMAL_FLOAT, GENERAL };
-
-
-    public static FormattedFloatingDecimal valueOf(double d, int precision, Form form){
-        FloatingDecimal.BinaryToASCIIConverter fdConverter =
-                FloatingDecimal.getBinaryToASCIIConverter(d, form == Form.COMPATIBLE);
-        return new FormattedFloatingDecimal(precision,form, fdConverter);
-    }
-
-    private int decExponentRounded;
-    private char[] mantissa;
-    private char[] exponent;
-
-    private static final ThreadLocal<Object> threadLocalCharBuffer =
-            new ThreadLocal<Object>() {
-                @Override
-                protected Object initialValue() {
-                    return new char[20];
-                }
-            };
-
-    private static char[] getBuffer(){
-        return (char[]) threadLocalCharBuffer.get();
-    }
-
-    private FormattedFloatingDecimal(int precision, Form form, FloatingDecimal.BinaryToASCIIConverter fdConverter) {
-        if (fdConverter.isExceptional()) {
-            this.mantissa = fdConverter.toJavaFormatString().toCharArray();
-            this.exponent = null;
-            return;
-        }
-        char[] digits = getBuffer();
-        int nDigits = fdConverter.getDigits(digits);
-        int decExp = fdConverter.getDecimalExponent();
-        int exp;
-        boolean isNegative = fdConverter.isNegative();
-        switch (form) {
-            case COMPATIBLE:
-                exp = decExp;
-                this.decExponentRounded = exp;
-                fillCompatible(precision, digits, nDigits, exp, isNegative);
-                break;
-            case DECIMAL_FLOAT:
-                exp = applyPrecision(decExp, digits, nDigits, decExp + precision);
-                fillDecimal(precision, digits, nDigits, exp, isNegative);
-                this.decExponentRounded = exp;
-                break;
-            case SCIENTIFIC:
-                exp = applyPrecision(decExp, digits, nDigits, precision + 1);
-                fillScientific(precision, digits, nDigits, exp, isNegative);
-                this.decExponentRounded = exp;
-                break;
-            case GENERAL:
-                exp = applyPrecision(decExp, digits, nDigits, precision);
-                // adjust precision to be the number of digits to right of decimal
-                // the real exponent to be output is actually exp - 1, not exp
-                if (exp - 1 < -4 || exp - 1 >= precision) {
-                    // form = Form.SCIENTIFIC;
-                    precision--;
-                    fillScientific(precision, digits, nDigits, exp, isNegative);
-                } else {
-                    // form = Form.DECIMAL_FLOAT;
-                    precision = precision - exp;
-                    fillDecimal(precision, digits, nDigits, exp, isNegative);
-                }
-                this.decExponentRounded = exp;
-                break;
-            default:
-                assert false;
-        }
-    }
-
-    // returns the exponent after rounding has been done by applyPrecision
-    public int getExponentRounded() {
-        return decExponentRounded - 1;
-    }
-
-    public char[] getMantissa(){
-        return mantissa;
-    }
-
-    public char[] getExponent(){
-        return exponent;
-    }
-
-    /**
-     * Returns new decExp in case of overflow.
-     */
-    private static int applyPrecision(int decExp, char[] digits, int nDigits, int prec) {
-        if (prec >= nDigits || prec < 0) {
-            // no rounding necessary
-            return decExp;
-        }
-        if (prec == 0) {
-            // only one digit (0 or 1) is returned because the precision
-            // excludes all significant digits
-            if (digits[0] >= '5') {
-                digits[0] = '1';
-                Arrays.fill(digits, 1, nDigits, '0');
-                return decExp + 1;
-            } else {
-                Arrays.fill(digits, 0, nDigits, '0');
-                return decExp;
-            }
-        }
-        int q = digits[prec];
-        if (q >= '5') {
-            int i = prec;
-            q = digits[--i];
-            if ( q == '9' ) {
-                while ( q == '9' && i > 0 ){
-                    q = digits[--i];
-                }
-                if ( q == '9' ){
-                    // carryout! High-order 1, rest 0s, larger exp.
-                    digits[0] = '1';
-                    Arrays.fill(digits, 1, nDigits, '0');
-                    return decExp+1;
-                }
-            }
-            digits[i] = (char)(q + 1);
-            Arrays.fill(digits, i+1, nDigits, '0');
-        } else {
-            Arrays.fill(digits, prec, nDigits, '0');
-        }
-        return decExp;
-    }
-
-    /**
-     * Fills mantissa and exponent char arrays for compatible format.
-     */
-    private void fillCompatible(int precision, char[] digits, int nDigits, int exp, boolean isNegative) {
-        int startIndex = isNegative ? 1 : 0;
-        if (exp > 0 && exp < 8) {
-            // print digits.digits.
-            if (nDigits < exp) {
-                int extraZeros = exp - nDigits;
-                mantissa = create(isNegative, nDigits + extraZeros + 2);
-                System.arraycopy(digits, 0, mantissa, startIndex, nDigits);
-                Arrays.fill(mantissa, startIndex + nDigits, startIndex + nDigits + extraZeros, '0');
-                mantissa[startIndex + nDigits + extraZeros] = '.';
-                mantissa[startIndex + nDigits + extraZeros+1] = '0';
-            } else if (exp < nDigits) {
-                int t = Math.min(nDigits - exp, precision);
-                mantissa = create(isNegative, exp + 1 + t);
-                System.arraycopy(digits, 0, mantissa, startIndex, exp);
-                mantissa[startIndex + exp ] = '.';
-                System.arraycopy(digits, exp, mantissa, startIndex+exp+1, t);
-            } else { // exp == digits.length
-                mantissa = create(isNegative, nDigits + 2);
-                System.arraycopy(digits, 0, mantissa, startIndex, nDigits);
-                mantissa[startIndex + nDigits ] = '.';
-                mantissa[startIndex + nDigits +1] = '0';
-            }
-        } else if (exp <= 0 && exp > -3) {
-            int zeros = Math.max(0, Math.min(-exp, precision));
-            int t = Math.max(0, Math.min(nDigits, precision + exp));
-            // write '0' s before the significant digits
-            if (zeros > 0) {
-                mantissa = create(isNegative, zeros + 2 + t);
-                mantissa[startIndex] = '0';
-                mantissa[startIndex+1] = '.';
-                Arrays.fill(mantissa, startIndex + 2, startIndex + 2 + zeros, '0');
-                if (t > 0) {
-                    // copy only when significant digits are within the precision
-                    System.arraycopy(digits, 0, mantissa, startIndex + 2 + zeros, t);
-                }
-            } else if (t > 0) {
-                mantissa = create(isNegative, zeros + 2 + t);
-                mantissa[startIndex] = '0';
-                mantissa[startIndex + 1] = '.';
-                // copy only when significant digits are within the precision
-                System.arraycopy(digits, 0, mantissa, startIndex + 2, t);
-            } else {
-                this.mantissa = create(isNegative, 1);
-                this.mantissa[startIndex] = '0';
-            }
-        } else {
-            if (nDigits > 1) {
-                mantissa = create(isNegative, nDigits + 1);
-                mantissa[startIndex] = digits[0];
-                mantissa[startIndex + 1] = '.';
-                System.arraycopy(digits, 1, mantissa, startIndex + 2, nDigits - 1);
-            } else {
-                mantissa = create(isNegative, 3);
-                mantissa[startIndex] = digits[0];
-                mantissa[startIndex + 1] = '.';
-                mantissa[startIndex + 2] = '0';
-            }
-            int e, expStartIntex;
-            boolean isNegExp = (exp <= 0);
-            if (isNegExp) {
-                e = -exp + 1;
-                expStartIntex = 1;
-            } else {
-                e = exp - 1;
-                expStartIntex = 0;
-            }
-            // decExponent has 1, 2, or 3, digits
-            if (e <= 9) {
-                exponent = create(isNegExp,1);
-                exponent[expStartIntex] = (char) (e + '0');
-            } else if (e <= 99) {
-                exponent = create(isNegExp,2);
-                exponent[expStartIntex] = (char) (e / 10 + '0');
-                exponent[expStartIntex+1] = (char) (e % 10 + '0');
-            } else {
-                exponent = create(isNegExp,3);
-                exponent[expStartIntex] = (char) (e / 100 + '0');
-                e %= 100;
-                exponent[expStartIntex+1] = (char) (e / 10 + '0');
-                exponent[expStartIntex+2] = (char) (e % 10 + '0');
-            }
-        }
-    }
-
-    private static char[] create(boolean isNegative, int size) {
-        if(isNegative) {
-            char[] r = new char[size +1];
-            r[0] = '-';
-            return r;
-        } else {
-            return new char[size];
-        }
-    }
-
-    /*
-     * Fills mantissa char arrays for DECIMAL_FLOAT format.
-     * Exponent should be equal to null.
-     */
-    private void fillDecimal(int precision, char[] digits, int nDigits, int exp, boolean isNegative) {
-        int startIndex = isNegative ? 1 : 0;
-        if (exp > 0) {
-            // print digits.digits.
-            if (nDigits < exp) {
-                mantissa = create(isNegative,exp);
-                System.arraycopy(digits, 0, mantissa, startIndex, nDigits);
-                Arrays.fill(mantissa, startIndex + nDigits, startIndex + exp, '0');
-                // Do not append ".0" for formatted floats since the user
-                // may request that it be omitted. It is added as necessary
-                // by the Formatter.
-            } else {
-                int t = Math.min(nDigits - exp, precision);
-                mantissa = create(isNegative, exp + (t > 0 ? (t + 1) : 0));
-                System.arraycopy(digits, 0, mantissa, startIndex, exp);
-                // Do not append ".0" for formatted floats since the user
-                // may request that it be omitted. It is added as necessary
-                // by the Formatter.
-                if (t > 0) {
-                    mantissa[startIndex + exp] = '.';
-                    System.arraycopy(digits, exp, mantissa, startIndex + exp + 1, t);
-                }
-            }
-        } else if (exp <= 0) {
-            int zeros = Math.max(0, Math.min(-exp, precision));
-            int t = Math.max(0, Math.min(nDigits, precision + exp));
-            // write '0' s before the significant digits
-            if (zeros > 0) {
-                mantissa = create(isNegative, zeros + 2 + t);
-                mantissa[startIndex] = '0';
-                mantissa[startIndex+1] = '.';
-                Arrays.fill(mantissa, startIndex + 2, startIndex + 2 + zeros, '0');
-                if (t > 0) {
-                    // copy only when significant digits are within the precision
-                    System.arraycopy(digits, 0, mantissa, startIndex + 2 + zeros, t);
-                }
-            } else if (t > 0) {
-                mantissa = create(isNegative, zeros + 2 + t);
-                mantissa[startIndex] = '0';
-                mantissa[startIndex + 1] = '.';
-                // copy only when significant digits are within the precision
-                System.arraycopy(digits, 0, mantissa, startIndex + 2, t);
-            } else {
-                this.mantissa = create(isNegative, 1);
-                this.mantissa[startIndex] = '0';
-            }
-        }
-    }
-
-    /**
-     * Fills mantissa and exponent char arrays for SCIENTIFIC format.
-     */
-    private void fillScientific(int precision, char[] digits, int nDigits, int exp, boolean isNegative) {
-        int startIndex = isNegative ? 1 : 0;
-        int t = Math.max(0, Math.min(nDigits - 1, precision));
-        if (t > 0) {
-            mantissa = create(isNegative, t + 2);
-            mantissa[startIndex] = digits[0];
-            mantissa[startIndex + 1] = '.';
-            System.arraycopy(digits, 1, mantissa, startIndex + 2, t);
-        } else {
-            mantissa = create(isNegative, 1);
-            mantissa[startIndex] = digits[0];
-        }
-        char expSign;
-        int e;
-        if (exp <= 0) {
-            expSign = '-';
-            e = -exp + 1;
-        } else {
-            expSign = '+' ;
-            e = exp - 1;
-        }
-        // decExponent has 1, 2, or 3, digits
-        if (e <= 9) {
-            exponent = new char[] { expSign,
-                    '0', (char) (e + '0') };
-        } else if (e <= 99) {
-            exponent = new char[] { expSign,
-                    (char) (e / 10 + '0'), (char) (e % 10 + '0') };
-        } else {
-            char hiExpChar = (char) (e / 100 + '0');
-            e %= 100;
-            exponent = new char[] { expSign,
-                    hiExpChar, (char) (e / 10 + '0'), (char) (e % 10 + '0') };
-        }
-    }
-}
--- a/jdk/src/java.base/share/classes/sun/misc/VM.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/misc/VM.java	Wed Jul 05 21:10:50 2017 +0200
@@ -27,9 +27,6 @@
 
 import static java.lang.Thread.State.*;
 import java.util.Properties;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
 
 public class VM {
 
@@ -288,10 +285,10 @@
     }
 
     /* Current count of objects pending for finalization */
-    private static volatile int finalRefCount = 0;
+    private static volatile int finalRefCount;
 
     /* Peak count of objects pending for finalization */
-    private static volatile int peakFinalRefCount = 0;
+    private static volatile int peakFinalRefCount;
 
     /*
      * Gets the number of objects pending for finalization.
--- a/jdk/src/java.base/share/classes/sun/net/www/http/HttpCapture.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/net/www/http/HttpCapture.java	Wed Jul 05 21:10:50 2017 +0200
@@ -54,12 +54,12 @@
  * @author jccollet
  */
 public class HttpCapture {
-    private File file = null;
+    private File file;
     private boolean incoming = true;
-    private BufferedWriter out = null;
-    private static boolean initialized = false;
-    private static volatile ArrayList<Pattern> patterns = null;
-    private static volatile ArrayList<String> capFiles = null;
+    private BufferedWriter out;
+    private static boolean initialized;
+    private static volatile ArrayList<Pattern> patterns;
+    private static volatile ArrayList<String> capFiles;
 
     private static synchronized void init() {
         initialized = true;
--- a/jdk/src/java.base/share/classes/sun/net/www/http/HttpClient.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/net/www/http/HttpClient.java	Wed Jul 05 21:10:50 2017 +0200
@@ -98,7 +98,7 @@
     // from previous releases.
     private static boolean retryPostProp = true;
 
-    volatile boolean keepingAlive = false;     /* this is a keep-alive connection */
+    volatile boolean keepingAlive;    /* this is a keep-alive connection */
     int keepAliveConnections = -1;    /* number of keep-alives left */
 
     /**Idle timeout value, in milliseconds. Zero means infinity,
--- a/jdk/src/java.base/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java	Wed Jul 05 21:10:50 2017 +0200
@@ -51,14 +51,14 @@
     protected final FileDescriptor fd;
 
     // the local address to which the channel's socket is bound
-    protected volatile InetSocketAddress localAddress = null;
+    protected volatile InetSocketAddress localAddress;
 
     // need this lock to set local address
     private final Object stateLock = new Object();
 
     // close support
     private ReadWriteLock closeLock = new ReentrantReadWriteLock();
-    private volatile boolean open = true;
+    private volatile boolean closed;
 
     // set true when accept operation is cancelled
     private volatile boolean acceptKilled;
@@ -73,7 +73,7 @@
 
     @Override
     public final boolean isOpen() {
-        return open;
+        return !closed;
     }
 
     /**
@@ -102,9 +102,9 @@
         // synchronize with any threads using file descriptor/handle
         closeLock.writeLock().lock();
         try {
-            if (!open)
+            if (closed)
                 return;     // already closed
-            open = false;
+            closed = true;
         } finally {
             closeLock.writeLock().unlock();
         }
--- a/jdk/src/java.base/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java	Wed Jul 05 21:10:50 2017 +0200
@@ -54,8 +54,8 @@
     // protects state, localAddress, and remoteAddress
     protected final Object stateLock = new Object();
 
-    protected volatile InetSocketAddress localAddress = null;
-    protected volatile InetSocketAddress remoteAddress = null;
+    protected volatile InetSocketAddress localAddress;
+    protected volatile InetSocketAddress remoteAddress;
 
     // State, increases monotonically
     static final int ST_UNINITIALIZED = -1;
@@ -78,7 +78,7 @@
 
     // close support
     private final ReadWriteLock closeLock = new ReentrantReadWriteLock();
-    private volatile boolean open = true;
+    private volatile boolean closed;
 
     // set true when exclusive binding is on and SO_REUSEADDR is emulated
     private boolean isReuseAddress;
@@ -106,7 +106,7 @@
 
     @Override
     public final boolean isOpen() {
-        return open;
+        return !closed;
     }
 
     /**
@@ -135,9 +135,9 @@
         // synchronize with any threads initiating asynchronous operations
         closeLock.writeLock().lock();
         try {
-            if (!open)
+            if (closed)
                 return;     // already closed
-            open = false;
+            closed = true;
         } finally {
             closeLock.writeLock().unlock();
         }
--- a/jdk/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java	Wed Jul 05 21:10:50 2017 +0200
@@ -58,8 +58,8 @@
     private final ProtocolFamily family;
 
     // IDs of native threads doing reads and writes, for signalling
-    private volatile long readerThread = 0;
-    private volatile long writerThread = 0;
+    private volatile long readerThread;
+    private volatile long writerThread;
 
     // Cached InetAddress and port for unconnected DatagramChannels
     // used by receive0
--- a/jdk/src/java.base/share/classes/sun/nio/ch/DatagramSocketAdaptor.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/nio/ch/DatagramSocketAdaptor.java	Wed Jul 05 21:10:50 2017 +0200
@@ -46,7 +46,7 @@
     private final DatagramChannelImpl dc;
 
     // Timeout "option" value for receives
-    private volatile int timeout = 0;
+    private volatile int timeout;
 
     // ## super will create a useless impl
     private DatagramSocketAdaptor(DatagramChannelImpl dc) throws IOException {
--- a/jdk/src/java.base/share/classes/sun/nio/ch/FileLockImpl.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/nio/ch/FileLockImpl.java	Wed Jul 05 21:10:50 2017 +0200
@@ -31,7 +31,7 @@
 public class FileLockImpl
     extends FileLock
 {
-    private volatile boolean valid = true;
+    private volatile boolean invalid;
 
     FileLockImpl(FileChannel channel, long position, long size, boolean shared)
     {
@@ -44,25 +44,25 @@
     }
 
     public boolean isValid() {
-        return valid;
+        return !invalid;
     }
 
     void invalidate() {
         assert Thread.holdsLock(this);
-        valid = false;
+        invalid = true;
     }
 
     public synchronized void release() throws IOException {
         Channel ch = acquiredBy();
         if (!ch.isOpen())
             throw new ClosedChannelException();
-        if (valid) {
+        if (isValid()) {
             if (ch instanceof FileChannelImpl)
                 ((FileChannelImpl)ch).release(this);
             else if (ch instanceof AsynchronousFileChannelImpl)
                 ((AsynchronousFileChannelImpl)ch).release(this);
             else throw new AssertionError();
-            valid = false;
+            invalidate();
         }
     }
 }
--- a/jdk/src/java.base/share/classes/sun/nio/ch/MembershipKeyImpl.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/nio/ch/MembershipKeyImpl.java	Wed Jul 05 21:10:50 2017 +0200
@@ -43,8 +43,7 @@
     private final NetworkInterface interf;
     private final InetAddress source;
 
-    // true when key is valid
-    private volatile boolean valid = true;
+    private volatile boolean invalid;
 
     // lock used when creating or accessing blockedSet
     private Object stateLock = new Object();
@@ -134,12 +133,12 @@
     }
 
     public boolean isValid() {
-        return valid;
+        return !invalid;
     }
 
     // package-private
     void invalidate() {
-        valid = false;
+        invalid = true;
     }
 
     public void drop() {
--- a/jdk/src/java.base/share/classes/sun/nio/ch/Net.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/nio/ch/Net.java	Wed Jul 05 21:10:50 2017 +0200
@@ -32,7 +32,6 @@
 import java.util.*;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
-import java.security.PrivilegedExceptionAction;
 import sun.net.ExtendedOptionsImpl;
 
 
@@ -55,7 +54,7 @@
 
     // -- Miscellaneous utilities --
 
-    private static volatile boolean checkedIPv6 = false;
+    private static volatile boolean checkedIPv6;
     private static volatile boolean isIPv6Available;
 
     /**
--- a/jdk/src/java.base/share/classes/sun/nio/ch/ServerSocketAdaptor.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/nio/ch/ServerSocketAdaptor.java	Wed Jul 05 21:10:50 2017 +0200
@@ -45,7 +45,7 @@
     private final ServerSocketChannelImpl ssc;
 
     // Timeout "option" value for accepts
-    private volatile int timeout = 0;
+    private volatile int timeout;
 
     public static ServerSocket create(ServerSocketChannelImpl ssc) {
         try {
--- a/jdk/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java	Wed Jul 05 21:10:50 2017 +0200
@@ -54,7 +54,7 @@
     private int fdVal;
 
     // ID of native thread currently blocked in this channel, for signalling
-    private volatile long thread = 0;
+    private volatile long thread;
 
     // Lock held by thread currently blocked in this channel
     private final Object lock = new Object();
--- a/jdk/src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java	Wed Jul 05 21:10:50 2017 +0200
@@ -26,13 +26,11 @@
 package sun.nio.ch;
 
 import java.io.*;
-import java.lang.ref.*;
 import java.net.*;
 import java.nio.*;
 import java.nio.channels.*;
 import java.security.AccessController;
 import java.security.PrivilegedExceptionAction;
-import java.util.*;
 
 
 // Make a socket channel look like a socket.
@@ -55,7 +53,7 @@
     private final SocketChannelImpl sc;
 
     // Timeout "option" value for reads
-    private volatile int timeout = 0;
+    private volatile int timeout;
 
     private SocketAdaptor(SocketChannelImpl sc) throws SocketException {
         super((SocketImpl) null);
--- a/jdk/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java	Wed Jul 05 21:10:50 2017 +0200
@@ -56,8 +56,8 @@
     private final int fdVal;
 
     // IDs of native threads doing reads and writes, for signalling
-    private volatile long readerThread = 0;
-    private volatile long writerThread = 0;
+    private volatile long readerThread;
+    private volatile long writerThread;
 
     // Lock held by current reading or connecting thread
     private final Object readLock = new Object();
--- a/jdk/src/java.base/share/classes/sun/nio/ch/Util.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/nio/ch/Util.java	Wed Jul 05 21:10:50 2017 +0200
@@ -25,13 +25,10 @@
 
 package sun.nio.ch;
 
-import java.lang.ref.SoftReference;
 import java.lang.reflect.*;
-import java.io.IOException;
 import java.io.FileDescriptor;
 import java.nio.ByteBuffer;
 import java.nio.MappedByteBuffer;
-import java.nio.channels.*;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.*;
@@ -295,7 +292,7 @@
         return pageSize;
     }
 
-    private static volatile Constructor<?> directByteBufferConstructor = null;
+    private static volatile Constructor<?> directByteBufferConstructor;
 
     private static void initDBBConstructor() {
         AccessController.doPrivileged(new PrivilegedAction<Void>() {
@@ -340,7 +337,7 @@
         return dbb;
     }
 
-    private static volatile Constructor<?> directByteBufferRConstructor = null;
+    private static volatile Constructor<?> directByteBufferRConstructor;
 
     private static void initDBBRConstructor() {
         AccessController.doPrivileged(new PrivilegedAction<Void>() {
@@ -388,7 +385,7 @@
 
     // -- Bug compatibility --
 
-    private static volatile String bugLevel = null;
+    private static volatile String bugLevel;
 
     static boolean atBugLevel(String bl) {              // package-private
         if (bugLevel == null) {
--- a/jdk/src/java.base/share/classes/sun/nio/cs/StreamDecoder.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/nio/cs/StreamDecoder.java	Wed Jul 05 21:10:50 2017 +0200
@@ -39,10 +39,10 @@
     private static final int MIN_BYTE_BUFFER_SIZE = 32;
     private static final int DEFAULT_BYTE_BUFFER_SIZE = 8192;
 
-    private volatile boolean isOpen = true;
+    private volatile boolean closed;
 
     private void ensureOpen() throws IOException {
-        if (!isOpen)
+        if (closed)
             throw new IOException("Stream closed");
     }
 
@@ -188,15 +188,15 @@
 
     public void close() throws IOException {
         synchronized (lock) {
-            if (!isOpen)
+            if (closed)
                 return;
             implClose();
-            isOpen = false;
+            closed = true;
         }
     }
 
     private boolean isOpen() {
-        return isOpen;
+        return !closed;
     }
 
 
--- a/jdk/src/java.base/share/classes/sun/nio/cs/StreamEncoder.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/nio/cs/StreamEncoder.java	Wed Jul 05 21:10:50 2017 +0200
@@ -38,10 +38,10 @@
 
     private static final int DEFAULT_BYTE_BUFFER_SIZE = 8192;
 
-    private volatile boolean isOpen = true;
+    private volatile boolean closed;
 
     private void ensureOpen() throws IOException {
-        if (!isOpen)
+        if (closed)
             throw new IOException("Stream closed");
     }
 
@@ -156,15 +156,15 @@
 
     public void close() throws IOException {
         synchronized (lock) {
-            if (!isOpen)
+            if (closed)
                 return;
             implClose();
-            isOpen = false;
+            closed = true;
         }
     }
 
     private boolean isOpen() {
-        return isOpen;
+        return !closed;
     }
 
 
--- a/jdk/src/java.base/share/classes/sun/reflect/MethodAccessorGenerator.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/reflect/MethodAccessorGenerator.java	Wed Jul 05 21:10:50 2017 +0200
@@ -44,9 +44,9 @@
     // Only used if forSerialization is true
     private static final short NUM_SERIALIZATION_CPOOL_ENTRIES = (short) 2;
 
-    private static volatile int methodSymnum = 0;
-    private static volatile int constructorSymnum = 0;
-    private static volatile int serializationConstructorSymnum = 0;
+    private static volatile int methodSymnum;
+    private static volatile int constructorSymnum;
+    private static volatile int serializationConstructorSymnum;
 
     private Class<?>   declaringClass;
     private Class<?>[] parameterTypes;
--- a/jdk/src/java.base/share/classes/sun/reflect/annotation/AnnotationInvocationHandler.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/reflect/annotation/AnnotationInvocationHandler.java	Wed Jul 05 21:10:50 2017 +0200
@@ -299,7 +299,7 @@
                 }});
     }
 
-    private transient volatile Method[] memberMethods = null;
+    private transient volatile Method[] memberMethods;
 
     /**
      * Validates that a method is structurally appropriate for an
--- a/jdk/src/java.base/share/classes/sun/security/ssl/CipherBox.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/CipherBox.java	Wed Jul 05 21:10:50 2017 +0200
@@ -1105,41 +1105,6 @@
         return fragLen;
     }
 
-
-    /*
-     * Is this cipher available?
-     *
-     * This method can only be called by CipherSuite.BulkCipher.isAvailable()
-     * to test the availability of a cipher suites.  Please DON'T use it in
-     * other places, otherwise, the behavior may be unexpected because we may
-     * initialize AEAD cipher improperly in the method.
-     */
-    Boolean isAvailable() {
-        // We won't know whether a cipher for a particular key size is
-        // available until the cipher is successfully initialized.
-        //
-        // We do not initialize AEAD cipher in the constructor.  Need to
-        // initialize the cipher to ensure that the AEAD mode for a
-        // particular key size is supported.
-        if (cipherType == AEAD_CIPHER) {
-            try {
-                Authenticator authenticator =
-                    new Authenticator(protocolVersion);
-                byte[] nonce = authenticator.sequenceNumber();
-                byte[] iv = Arrays.copyOf(fixedIv,
-                                            fixedIv.length + nonce.length);
-                System.arraycopy(nonce, 0, iv, fixedIv.length, nonce.length);
-                GCMParameterSpec spec = new GCMParameterSpec(tagSize * 8, iv);
-
-                cipher.init(mode, key, spec, random);
-            } catch (Exception e) {
-                return Boolean.FALSE;
-            }
-        }   // Otherwise, we have initialized the cipher in the constructor.
-
-        return Boolean.TRUE;
-    }
-
     /**
      * Sanity check the length of a fragment before decryption.
      *
--- a/jdk/src/java.base/share/classes/sun/security/ssl/CipherSuite.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/CipherSuite.java	Wed Jul 05 21:10:50 2017 +0200
@@ -77,12 +77,6 @@
     // minimum priority for default enabled CipherSuites
     static final int DEFAULT_SUITES_PRIORITY = 300;
 
-    // Flag indicating if CipherSuite availability can change dynamically.
-    // This is the case when we rely on a JCE cipher implementation that
-    // may not be available in the installed JCE providers.
-    // It is true because we might not have an ECC implementation.
-    static final boolean DYNAMIC_AVAILABILITY = true;
-
     private static final boolean ALLOW_ECC = Debug.getBooleanProperty
         ("com.sun.net.ssl.enableECC", true);
 
@@ -176,9 +170,6 @@
      * Return whether this CipherSuite is available for use. A
      * CipherSuite may be unavailable even if it is supported
      * (i.e. allowed == true) if the required JCE cipher is not installed.
-     * In some configuration, this situation may change over time, call
-     * CipherSuiteList.clearAvailableCache() before this method to obtain
-     * the most current status.
      */
     boolean isAvailable() {
         return allowed && keyExchange.isAvailable() && cipher.isAvailable();
@@ -471,10 +462,6 @@
         B_AES_128_GCM(CIPHER_AES_GCM, AEAD_CIPHER, 16, 12, 4, true),
         B_AES_256_GCM(CIPHER_AES_GCM, AEAD_CIPHER, 32, 12, 4, true);
 
-        // Map BulkCipher -> Boolean(available)
-        private static final Map<BulkCipher,Boolean> availableCache =
-                                            new HashMap<>(8);
-
         // descriptive name including key size, e.g. AES/128
         final String description;
 
@@ -518,6 +505,9 @@
         // The secure random used to detect the cipher availability.
         private static final SecureRandom secureRandom;
 
+        // runtime availability
+        private final boolean isAvailable;
+
         static {
             try {
                 secureRandom = JsseJce.getSecureRandom();
@@ -542,6 +532,17 @@
 
             this.expandedKeySize = expandedKeySize;
             this.exportable = true;
+
+            // availability of this bulk cipher
+            //
+            // Currently all supported ciphers except AES are always available
+            // via the JSSE internal implementations. We also assume AES/128 of
+            // CBC mode is always available since it is shipped with the SunJCE
+            // provider.  However, AES/256 is unavailable when the default JCE
+            // policy jurisdiction files are installed because of key length
+            // restrictions.
+            this.isAvailable =
+                    allowed ? isUnlimited(keySize, transformation) : false;
         }
 
         BulkCipher(String transformation, CipherType cipherType, int keySize,
@@ -558,6 +559,17 @@
 
             this.expandedKeySize = keySize;
             this.exportable = false;
+
+            // availability of this bulk cipher
+            //
+            // Currently all supported ciphers except AES are always available
+            // via the JSSE internal implementations. We also assume AES/128 of
+            // CBC mode is always available since it is shipped with the SunJCE
+            // provider.  However, AES/256 is unavailable when the default JCE
+            // policy jurisdiction files are installed because of key length
+            // restrictions.
+            this.isAvailable =
+                    allowed ? isUnlimited(keySize, transformation) : false;
         }
 
         /**
@@ -575,84 +587,27 @@
 
         /**
          * Test if this bulk cipher is available. For use by CipherSuite.
-         *
-         * Currently all supported ciphers except AES are always available
-         * via the JSSE internal implementations. We also assume AES/128 of
-         * CBC mode is always available since it is shipped with the SunJCE
-         * provider.  However, AES/256 is unavailable when the default JCE
-         * policy jurisdiction files are installed because of key length
-         * restrictions, and AEAD is unavailable when the underlying providers
-         * do not support AEAD/GCM mode.
          */
         boolean isAvailable() {
-            if (allowed == false) {
-                return false;
-            }
-
-            if ((this == B_AES_256) ||
-                    (this.cipherType == CipherType.AEAD_CIPHER)) {
-                return isAvailable(this);
-            }
-
-            // always available
-            return true;
-        }
-
-        // for use by CipherSuiteList.clearAvailableCache();
-        static synchronized void clearAvailableCache() {
-            if (DYNAMIC_AVAILABILITY) {
-                availableCache.clear();
-            }
+            return this.isAvailable;
         }
 
-        private static synchronized boolean isAvailable(BulkCipher cipher) {
-            Boolean b = availableCache.get(cipher);
-            if (b == null) {
-                int keySizeInBits = cipher.keySize * 8;
-                if (keySizeInBits > 128) {    // need the JCE unlimited
-                                               // strength jurisdiction policy
-                    try {
-                        if (Cipher.getMaxAllowedKeyLength(
-                                cipher.transformation) < keySizeInBits) {
-                            b = Boolean.FALSE;
-                        }
-                    } catch (Exception e) {
-                        b = Boolean.FALSE;
-                    }
-                }
+        private static boolean isUnlimited(int keySize, String transformation) {
+            int keySizeInBits = keySize * 8;
+            if (keySizeInBits > 128) {    // need the JCE unlimited
+                                          // strength jurisdiction policy
+                try {
+                    if (Cipher.getMaxAllowedKeyLength(
+                            transformation) < keySizeInBits) {
 
-                if (b == null) {
-                    b = Boolean.FALSE;          // may be reset to TRUE if
-                                                // the cipher is available
-                    CipherBox temporary = null;
-                    try {
-                        SecretKey key = new SecretKeySpec(
-                                            new byte[cipher.expandedKeySize],
-                                            cipher.algorithm);
-                        IvParameterSpec iv;
-                        if (cipher.cipherType == CipherType.AEAD_CIPHER) {
-                            iv = new IvParameterSpec(
-                                            new byte[cipher.fixedIvSize]);
-                        } else {
-                            iv = new IvParameterSpec(new byte[cipher.ivSize]);
-                        }
-                        temporary = cipher.newCipher(
-                                            ProtocolVersion.DEFAULT_TLS,
-                                            key, iv, secureRandom, true);
-                        b = temporary.isAvailable();
-                    } catch (NoSuchAlgorithmException e) {
-                        // not available
-                    } finally {
-                        if (temporary != null) {
-                            temporary.dispose();
-                        }
+                        return false;
                     }
+                } catch (Exception e) {
+                    return false;
                 }
-
-                availableCache.put(cipher, b);
             }
 
-            return b.booleanValue();
+            return true;
         }
 
         @Override
--- a/jdk/src/java.base/share/classes/sun/security/ssl/CipherSuiteList.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/CipherSuiteList.java	Wed Jul 05 21:10:50 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -74,24 +74,12 @@
             throw new IllegalArgumentException("CipherSuites may not be null");
         }
         cipherSuites = new ArrayList<CipherSuite>(names.length);
-        // refresh available cache once if a CipherSuite is not available
-        // (maybe new JCE providers have been installed)
-        boolean refreshed = false;
         for (int i = 0; i < names.length; i++) {
             String suiteName = names[i];
             CipherSuite suite = CipherSuite.valueOf(suiteName);
             if (suite.isAvailable() == false) {
-                if (refreshed == false) {
-                    // clear the cache so that the isAvailable() call below
-                    // does a full check
-                    clearAvailableCache();
-                    refreshed = true;
-                }
-                // still missing?
-                if (suite.isAvailable() == false) {
-                    throw new IllegalArgumentException("Cannot support "
-                        + suiteName + " with currently installed providers");
-                }
+                throw new IllegalArgumentException("Cannot support "
+                    + suiteName + " with currently installed providers");
             }
             cipherSuites.add(suite);
         }
@@ -195,16 +183,4 @@
         }
         s.putBytes16(suiteBytes);
     }
-
-    /**
-     * Clear cache of available ciphersuites. If we support all ciphers
-     * internally, there is no need to clear the cache and calling this
-     * method has no effect.
-     */
-    static synchronized void clearAvailableCache() {
-        if (CipherSuite.DYNAMIC_AVAILABILITY) {
-            CipherSuite.BulkCipher.clearAvailableCache();
-            JsseJce.clearEcAvailable();
-        }
-    }
 }
--- a/jdk/src/java.base/share/classes/sun/security/ssl/JsseJce.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/JsseJce.java	Wed Jul 05 21:10:50 2017 +0200
@@ -55,11 +55,6 @@
 
     private static final ProviderList fipsProviderList;
 
-    // Flag indicating whether EC crypto is available.
-    // If null, then we have not checked yet.
-    // If yes, then all the EC based crypto we need is available.
-    private static Boolean ecAvailable;
-
     // Flag indicating whether Kerberos crypto is available.
     // If true, then all the Kerberos-based crypto we need is available.
     private static final boolean kerberosAvailable;
@@ -180,24 +175,8 @@
         // no instantiation of this class
     }
 
-    static synchronized boolean isEcAvailable() {
-        if (ecAvailable == null) {
-            try {
-                JsseJce.getSignature(SIGNATURE_ECDSA);
-                JsseJce.getSignature(SIGNATURE_RAWECDSA);
-                JsseJce.getKeyAgreement("ECDH");
-                JsseJce.getKeyFactory("EC");
-                JsseJce.getKeyPairGenerator("EC");
-                ecAvailable = true;
-            } catch (Exception e) {
-                ecAvailable = false;
-            }
-        }
-        return ecAvailable;
-    }
-
-    static synchronized void clearEcAvailable() {
-        ecAvailable = null;
+    static boolean isEcAvailable() {
+        return EcAvailability.isAvailable;
     }
 
     static boolean isKerberosAvailable() {
@@ -399,4 +378,27 @@
         }
     }
 
+
+    // lazy initialization holder class idiom for static default parameters
+    //
+    // See Effective Java Second Edition: Item 71.
+    private static class EcAvailability {
+        // Is EC crypto available?
+        private final static boolean isAvailable;
+
+        static {
+            boolean mediator = true;
+            try {
+                JsseJce.getSignature(SIGNATURE_ECDSA);
+                JsseJce.getSignature(SIGNATURE_RAWECDSA);
+                JsseJce.getKeyAgreement("ECDH");
+                JsseJce.getKeyFactory("EC");
+                JsseJce.getKeyPairGenerator("EC");
+            } catch (Exception e) {
+                mediator = false;
+            }
+
+            isAvailable = mediator;
+        }
+    }
 }
--- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java	Wed Jul 05 21:10:50 2017 +0200
@@ -52,18 +52,8 @@
     private X509TrustManager trustManager;
     private SecureRandom secureRandom;
 
-    // supported and default protocols
-    private ProtocolList defaultServerProtocolList;
-    private ProtocolList defaultClientProtocolList;
-    private ProtocolList supportedProtocolList;
-
-    // supported and default cipher suites
-    private CipherSuiteList defaultServerCipherSuiteList;
-    private CipherSuiteList defaultClientCipherSuiteList;
-    private CipherSuiteList supportedCipherSuiteList;
-
     // DTLS cookie exchange manager
-    private HelloCookieManager helloCookieManager;
+    private volatile HelloCookieManager helloCookieManager;
 
     private StatusResponseManager statusResponseManager;
 
@@ -117,6 +107,7 @@
         if (debug != null && Debug.isOn("sslctx")) {
             System.out.println("done seeding SecureRandom");
         }
+
         isInitialized = true;
     }
 
@@ -242,13 +233,20 @@
         return ephemeralKeyManager;
     }
 
+    // Used for DTLS in server mode only, see ServerHandshaker.
     HelloCookieManager getHelloCookieManager() {
         if (!isInitialized) {
             throw new IllegalStateException("SSLContext is not initialized");
         }
 
-        if (helloCookieManager == null) {
-            helloCookieManager = getHelloCookieManager(secureRandom);
+        if (helloCookieManager != null) {
+            return helloCookieManager;
+        }
+
+        synchronized (this) {
+            if (helloCookieManager == null) {
+                helloCookieManager = getHelloCookieManager(secureRandom);
+            }
         }
 
         return helloCookieManager;
@@ -263,78 +261,34 @@
         return statusResponseManager;
     }
 
-    abstract SSLParameters getDefaultServerSSLParams();
-    abstract SSLParameters getDefaultClientSSLParams();
-    abstract SSLParameters getSupportedSSLParams();
+    // Get supported ProtocolList.
+    abstract ProtocolList getSuportedProtocolList();
+
+    // Get default ProtocolList for server mode.
+    abstract ProtocolList getServerDefaultProtocolList();
+
+    // Get default ProtocolList for client mode.
+    abstract ProtocolList getClientDefaultProtocolList();
 
-    // Get supported ProtocolList.
-    ProtocolList getSuportedProtocolList() {
-        if (supportedProtocolList == null) {
-            supportedProtocolList =
-                new ProtocolList(getSupportedSSLParams().getProtocols());
-        }
+    // Get supported CipherSuiteList.
+    abstract CipherSuiteList getSupportedCipherSuiteList();
 
-        return supportedProtocolList;
-    }
+    // Get default CipherSuiteList for server mode.
+    abstract CipherSuiteList getServerDefaultCipherSuiteList();
+
+    // Get default CipherSuiteList for client mode.
+    abstract CipherSuiteList getClientDefaultCipherSuiteList();
 
     // Get default ProtocolList.
     ProtocolList getDefaultProtocolList(boolean roleIsServer) {
-        if (roleIsServer) {
-            if (defaultServerProtocolList == null) {
-                defaultServerProtocolList = new ProtocolList(
-                        getDefaultServerSSLParams().getProtocols());
-            }
-
-            return defaultServerProtocolList;
-        } else {
-            if (defaultClientProtocolList == null) {
-                defaultClientProtocolList = new ProtocolList(
-                        getDefaultClientSSLParams().getProtocols());
-            }
-
-            return defaultClientProtocolList;
-        }
-    }
-
-    // Get supported CipherSuiteList.
-    CipherSuiteList getSupportedCipherSuiteList() {
-        // The maintenance of cipher suites needs to be synchronized.
-        synchronized (this) {
-            // Clear cache of available ciphersuites.
-            clearAvailableCache();
-
-            if (supportedCipherSuiteList == null) {
-                supportedCipherSuiteList = getApplicableCipherSuiteList(
-                        getSuportedProtocolList(), false);
-            }
-
-            return supportedCipherSuiteList;
-        }
+        return roleIsServer ? getServerDefaultProtocolList()
+                            : getClientDefaultProtocolList();
     }
 
     // Get default CipherSuiteList.
     CipherSuiteList getDefaultCipherSuiteList(boolean roleIsServer) {
-        // The maintenance of cipher suites needs to be synchronized.
-        synchronized (this) {
-            // Clear cache of available ciphersuites.
-            clearAvailableCache();
-
-            if (roleIsServer) {
-                if (defaultServerCipherSuiteList == null) {
-                    defaultServerCipherSuiteList = getApplicableCipherSuiteList(
-                        getDefaultProtocolList(true), true);
-                }
-
-                return defaultServerCipherSuiteList;
-            } else {
-                if (defaultClientCipherSuiteList == null) {
-                    defaultClientCipherSuiteList = getApplicableCipherSuiteList(
-                        getDefaultProtocolList(false), true);
-                }
-
-                return defaultClientCipherSuiteList;
-            }
-        }
+        return roleIsServer ? getServerDefaultCipherSuiteList()
+                            : getClientDefaultCipherSuiteList();
     }
 
     /**
@@ -342,8 +296,8 @@
      * protocols.  See: SSLSocket/SSLEngine.setEnabledProtocols()
      */
     boolean isDefaultProtocolList(ProtocolList protocols) {
-        return (protocols == defaultServerProtocolList) ||
-               (protocols == defaultClientProtocolList);
+        return (protocols == getServerDefaultProtocolList()) ||
+               (protocols == getClientDefaultProtocolList());
     }
 
     /**
@@ -351,8 +305,8 @@
      * protocols.  See: SSLSocket/SSLEngine.setEnabledProtocols()
      */
     boolean isDefaultCipherSuiteList(CipherSuiteList cipherSuites) {
-        return (cipherSuites == defaultClientCipherSuiteList) ||
-               (cipherSuites == defaultServerCipherSuiteList);
+        return (cipherSuites == getServerDefaultCipherSuiteList()) ||
+               (cipherSuites == getClientDefaultCipherSuiteList());
     }
 
     /*
@@ -405,24 +359,6 @@
         return new CipherSuiteList(suites);
     }
 
-    /**
-     * Clear cache of available ciphersuites. If we support all ciphers
-     * internally, there is no need to clear the cache and calling this
-     * method has no effect.
-     *
-     * Note that every call to clearAvailableCache() and the maintenance of
-     * cipher suites need to be synchronized with this instance.
-     */
-    private void clearAvailableCache() {
-        if (CipherSuite.DYNAMIC_AVAILABILITY) {
-            supportedCipherSuiteList = null;
-            defaultServerCipherSuiteList = null;
-            defaultClientCipherSuiteList = null;
-            CipherSuite.BulkCipher.clearAvailableCache();
-            JsseJce.clearEcAvailable();
-        }
-    }
-
     private static String[] getAvailableProtocols(
             ProtocolVersion[] protocolCandidates) {
 
@@ -479,31 +415,28 @@
      * @see SSLContext
      */
     private abstract static class AbstractTLSContext extends SSLContextImpl {
-        // parameters
-        private static final SSLParameters defaultServerSSLParams;
-        private static final SSLParameters supportedSSLParams;
+        private static final ProtocolList supportedProtocolList;
+        private static final ProtocolList serverDefaultProtocolList;
+
+        private static final CipherSuiteList supportedCipherSuiteList;
+        private static final CipherSuiteList serverDefaultCipherSuiteList;
 
         static {
-            // supported SSL parameters
-            supportedSSLParams = new SSLParameters();
-
-            // candidates for available protocols
-            ProtocolVersion[] candidates;
-
             if (SunJSSE.isFIPS()) {
-                supportedSSLParams.setProtocols(new String[] {
+                supportedProtocolList = new ProtocolList(new String[] {
                     ProtocolVersion.TLS10.name,
                     ProtocolVersion.TLS11.name,
                     ProtocolVersion.TLS12.name
                 });
 
-                candidates = new ProtocolVersion[] {
+                serverDefaultProtocolList = new ProtocolList(
+                        getAvailableProtocols(new ProtocolVersion[] {
                     ProtocolVersion.TLS10,
                     ProtocolVersion.TLS11,
                     ProtocolVersion.TLS12
-                };
+                }));
             } else {
-                supportedSSLParams.setProtocols(new String[] {
+                supportedProtocolList = new ProtocolList(new String[] {
                     ProtocolVersion.SSL20Hello.name,
                     ProtocolVersion.SSL30.name,
                     ProtocolVersion.TLS10.name,
@@ -511,28 +444,40 @@
                     ProtocolVersion.TLS12.name
                 });
 
-                candidates = new ProtocolVersion[] {
+                serverDefaultProtocolList = new ProtocolList(
+                        getAvailableProtocols(new ProtocolVersion[] {
                     ProtocolVersion.SSL20Hello,
                     ProtocolVersion.SSL30,
                     ProtocolVersion.TLS10,
                     ProtocolVersion.TLS11,
                     ProtocolVersion.TLS12
-                };
+                }));
             }
 
-            defaultServerSSLParams = new SSLParameters();
-            defaultServerSSLParams.setProtocols(
-                    getAvailableProtocols(candidates));
+            supportedCipherSuiteList = getApplicableCipherSuiteList(
+                    supportedProtocolList, false);          // all supported
+            serverDefaultCipherSuiteList = getApplicableCipherSuiteList(
+                    serverDefaultProtocolList, true);       // enabled only
         }
 
         @Override
-        SSLParameters getDefaultServerSSLParams() {
-            return defaultServerSSLParams;
+        ProtocolList getSuportedProtocolList() {
+            return supportedProtocolList;
         }
 
         @Override
-        SSLParameters getSupportedSSLParams() {
-            return supportedSSLParams;
+        CipherSuiteList getSupportedCipherSuiteList() {
+            return supportedCipherSuiteList;
+        }
+
+        @Override
+        ProtocolList getServerDefaultProtocolList() {
+            return serverDefaultProtocolList;
+        }
+
+        @Override
+        CipherSuiteList getServerDefaultCipherSuiteList() {
+            return serverDefaultCipherSuiteList;
         }
 
         @Override
@@ -552,30 +497,35 @@
      * @see SSLContext
      */
     public static final class TLS10Context extends AbstractTLSContext {
-        private static final SSLParameters defaultClientSSLParams;
+        private static final ProtocolList clientDefaultProtocolList;
+        private static final CipherSuiteList clientDefaultCipherSuiteList;
 
         static {
-            // candidates for available protocols
-            ProtocolVersion[] candidates;
             if (SunJSSE.isFIPS()) {
-                candidates = new ProtocolVersion[] {
+                clientDefaultProtocolList = new ProtocolList(
+                        getAvailableProtocols(new ProtocolVersion[] {
                     ProtocolVersion.TLS10
-                };
+                }));
             } else {
-                candidates = new ProtocolVersion[] {
+                clientDefaultProtocolList = new ProtocolList(
+                        getAvailableProtocols(new ProtocolVersion[] {
                     ProtocolVersion.SSL30,
                     ProtocolVersion.TLS10
-                };
+                }));
             }
 
-            defaultClientSSLParams = new SSLParameters();
-            defaultClientSSLParams.setProtocols(
-                    getAvailableProtocols(candidates));
+            clientDefaultCipherSuiteList = getApplicableCipherSuiteList(
+                    clientDefaultProtocolList, true);       // enabled only
         }
 
         @Override
-        SSLParameters getDefaultClientSSLParams() {
-            return defaultClientSSLParams;
+        ProtocolList getClientDefaultProtocolList() {
+            return clientDefaultProtocolList;
+        }
+
+        @Override
+        CipherSuiteList getClientDefaultCipherSuiteList() {
+            return clientDefaultCipherSuiteList;
         }
     }
 
@@ -585,32 +535,37 @@
      * @see SSLContext
      */
     public static final class TLS11Context extends AbstractTLSContext {
-        private static final SSLParameters defaultClientSSLParams;
+        private static final ProtocolList clientDefaultProtocolList;
+        private static final CipherSuiteList clientDefaultCipherSuiteList;
 
         static {
-            // candidates for available protocols
-            ProtocolVersion[] candidates;
             if (SunJSSE.isFIPS()) {
-                candidates = new ProtocolVersion[] {
+                clientDefaultProtocolList = new ProtocolList(
+                        getAvailableProtocols(new ProtocolVersion[] {
                     ProtocolVersion.TLS10,
                     ProtocolVersion.TLS11
-                };
+                }));
             } else {
-                candidates = new ProtocolVersion[] {
+                clientDefaultProtocolList = new ProtocolList(
+                        getAvailableProtocols(new ProtocolVersion[] {
                     ProtocolVersion.SSL30,
                     ProtocolVersion.TLS10,
                     ProtocolVersion.TLS11
-                };
+                }));
             }
 
-            defaultClientSSLParams = new SSLParameters();
-            defaultClientSSLParams.setProtocols(
-                    getAvailableProtocols(candidates));
+            clientDefaultCipherSuiteList = getApplicableCipherSuiteList(
+                    clientDefaultProtocolList, true);       // enabled only
         }
 
         @Override
-        SSLParameters getDefaultClientSSLParams() {
-            return defaultClientSSLParams;
+        ProtocolList getClientDefaultProtocolList() {
+            return clientDefaultProtocolList;
+        }
+
+        @Override
+        CipherSuiteList getClientDefaultCipherSuiteList() {
+            return clientDefaultCipherSuiteList;
         }
     }
 
@@ -620,34 +575,39 @@
      * @see SSLContext
      */
     public static final class TLS12Context extends AbstractTLSContext {
-        private static final SSLParameters defaultClientSSLParams;
+        private static final ProtocolList clientDefaultProtocolList;
+        private static final CipherSuiteList clientDefaultCipherSuiteList;
 
         static {
-            // candidates for available protocols
-            ProtocolVersion[] candidates;
             if (SunJSSE.isFIPS()) {
-                candidates = new ProtocolVersion[] {
+                clientDefaultProtocolList = new ProtocolList(
+                        getAvailableProtocols(new ProtocolVersion[] {
                     ProtocolVersion.TLS10,
                     ProtocolVersion.TLS11,
                     ProtocolVersion.TLS12
-                };
+                }));
             } else {
-                candidates = new ProtocolVersion[] {
+                clientDefaultProtocolList = new ProtocolList(
+                        getAvailableProtocols(new ProtocolVersion[] {
                     ProtocolVersion.SSL30,
                     ProtocolVersion.TLS10,
                     ProtocolVersion.TLS11,
                     ProtocolVersion.TLS12
-                };
+                }));
             }
 
-            defaultClientSSLParams = new SSLParameters();
-            defaultClientSSLParams.setProtocols(
-                    getAvailableProtocols(candidates));
+            clientDefaultCipherSuiteList = getApplicableCipherSuiteList(
+                    clientDefaultProtocolList, true);       // enabled only
         }
 
         @Override
-        SSLParameters getDefaultClientSSLParams() {
-            return defaultClientSSLParams;
+        ProtocolList getClientDefaultProtocolList() {
+            return clientDefaultProtocolList;
+        }
+
+        @Override
+        CipherSuiteList getClientDefaultCipherSuiteList() {
+            return clientDefaultCipherSuiteList;
         }
     }
 
@@ -719,7 +679,9 @@
      */
     private static class CustomizedTLSContext extends AbstractTLSContext {
 
-        private static final SSLParameters defaultClientSSLParams;
+        private static final ProtocolList clientDefaultProtocolList;
+        private static final CipherSuiteList clientDefaultCipherSuiteList;
+
         private static IllegalArgumentException reservedException = null;
 
         // Don't want a java.lang.LinkageError for illegal system property.
@@ -766,11 +728,13 @@
                     candidates = customizedTLSProtocols.toArray(candidates);
                 }
 
-                defaultClientSSLParams = new SSLParameters();
-                defaultClientSSLParams.setProtocols(
+                clientDefaultProtocolList = new ProtocolList(
                         getAvailableProtocols(candidates));
+                clientDefaultCipherSuiteList = getApplicableCipherSuiteList(
+                    clientDefaultProtocolList, true);   // enabled only
             } else {
-                defaultClientSSLParams = null;  // unlikely to be used
+                clientDefaultProtocolList = null;       // unlikely to be used
+                clientDefaultCipherSuiteList = null;    // unlikely to be used
             }
         }
 
@@ -781,8 +745,13 @@
         }
 
         @Override
-        SSLParameters getDefaultClientSSLParams() {
-            return defaultClientSSLParams;
+        ProtocolList getClientDefaultProtocolList() {
+            return clientDefaultProtocolList;
+        }
+
+        @Override
+        CipherSuiteList getClientDefaultCipherSuiteList() {
+            return clientDefaultCipherSuiteList;
         }
     }
 
@@ -795,71 +764,53 @@
         // use the default constructor and methods
     }
 
-    /*
-     * The SSLContext implementation for default "Default" algorithm
-     *
-     * @see SSLContext
-     */
-    public static final class DefaultSSLContext extends CustomizedTLSContext {
+    // lazy initialization holder class idiom for static default parameters
+    //
+    // See Effective Java Second Edition: Item 71.
+    private static final class DefaultManagersHolder {
         private static final String NONE = "NONE";
         private static final String P11KEYSTORE = "PKCS11";
 
-        private static volatile SSLContextImpl defaultImpl;
+        private static final TrustManager[] trustManagers;
+        private static final KeyManager[] keyManagers;
 
-        private static TrustManager[] defaultTrustManagers;
-        private static KeyManager[] defaultKeyManagers;
+        static Exception reservedException = null;
 
-        public DefaultSSLContext() throws Exception {
+        static {
+            TrustManager[] tmMediator;
             try {
-                super.engineInit(getDefaultKeyManager(),
-                        getDefaultTrustManager(), null);
+                tmMediator = getTrustManagers();
             } catch (Exception e) {
-                if (debug != null && Debug.isOn("defaultctx")) {
-                    System.out.println("default context init failed: " + e);
+                reservedException = e;
+                tmMediator = new TrustManager[0];
+            }
+            trustManagers = tmMediator;
+
+            if (reservedException == null) {
+                KeyManager[] kmMediator;
+                try {
+                    kmMediator = getKeyManagers();
+                } catch (Exception e) {
+                    reservedException = e;
+                    kmMediator = new KeyManager[0];
                 }
-                throw e;
-            }
-
-            if (defaultImpl == null) {
-                defaultImpl = this;
+                keyManagers = kmMediator;
+            } else {
+                keyManagers = new KeyManager[0];
             }
         }
 
-        @Override
-        protected void engineInit(KeyManager[] km, TrustManager[] tm,
-            SecureRandom sr) throws KeyManagementException {
-            throw new KeyManagementException
-                ("Default SSLContext is initialized automatically");
-        }
-
-        static synchronized SSLContextImpl getDefaultImpl() throws Exception {
-            if (defaultImpl == null) {
-                new DefaultSSLContext();
-            }
-            return defaultImpl;
-        }
-
-        private static synchronized TrustManager[] getDefaultTrustManager()
-                throws Exception {
-            if (defaultTrustManagers != null) {
-                return defaultTrustManagers;
-            }
-
+        private static TrustManager[] getTrustManagers() throws Exception {
             KeyStore ks =
                 TrustManagerFactoryImpl.getCacertsKeyStore("defaultctx");
 
             TrustManagerFactory tmf = TrustManagerFactory.getInstance(
                 TrustManagerFactory.getDefaultAlgorithm());
             tmf.init(ks);
-            defaultTrustManagers = tmf.getTrustManagers();
-            return defaultTrustManagers;
+            return tmf.getTrustManagers();
         }
 
-        private static synchronized KeyManager[] getDefaultKeyManager()
-                throws Exception {
-            if (defaultKeyManagers != null) {
-                return defaultKeyManagers;
-            }
+        private static KeyManager[] getKeyManagers() throws Exception {
 
             final Map<String,String> props = new HashMap<>();
             AccessController.doPrivileged(
@@ -956,8 +907,71 @@
                 kmf.init(ks, passwd);
             }
 
-            defaultKeyManagers = kmf.getKeyManagers();
-            return defaultKeyManagers;
+            return kmf.getKeyManagers();
+        }
+    }
+
+    // lazy initialization holder class idiom for static default parameters
+    //
+    // See Effective Java Second Edition: Item 71.
+    private static final class DefaultSSLContextHolder {
+
+        private static final SSLContextImpl sslContext;
+        static Exception reservedException = null;
+
+        static {
+            SSLContextImpl mediator = null;
+            if (DefaultManagersHolder.reservedException != null) {
+                reservedException = DefaultManagersHolder.reservedException;
+            } else {
+                try {
+                    mediator = new DefaultSSLContext();
+                } catch (Exception e) {
+                    reservedException = e;
+                }
+            }
+
+            sslContext = mediator;
+        }
+    }
+
+    /*
+     * The SSLContext implementation for default "Default" algorithm
+     *
+     * @see SSLContext
+     */
+    public static final class DefaultSSLContext extends CustomizedTLSContext {
+
+        // public constructor for SSLContext.getInstance("Default")
+        public DefaultSSLContext() throws Exception {
+            if (DefaultManagersHolder.reservedException != null) {
+                throw DefaultManagersHolder.reservedException;
+            }
+
+            try {
+                super.engineInit(DefaultManagersHolder.keyManagers,
+                        DefaultManagersHolder.trustManagers, null);
+            } catch (Exception e) {
+                if (debug != null && Debug.isOn("defaultctx")) {
+                    System.out.println("default context init failed: " + e);
+                }
+                throw e;
+            }
+        }
+
+        @Override
+        protected void engineInit(KeyManager[] km, TrustManager[] tm,
+            SecureRandom sr) throws KeyManagementException {
+            throw new KeyManagementException
+                ("Default SSLContext is initialized automatically");
+        }
+
+        static SSLContextImpl getDefaultImpl() throws Exception {
+            if (DefaultSSLContextHolder.reservedException != null) {
+                throw DefaultSSLContextHolder.reservedException;
+            }
+
+            return DefaultSSLContextHolder.sslContext;
         }
     }
 
@@ -971,39 +985,50 @@
      * @see SSLContext
      */
     private abstract static class AbstractDTLSContext extends SSLContextImpl {
-        // parameters
-        private static final SSLParameters defaultServerSSLParams;
-        private static final SSLParameters supportedSSLParams;
+        private static final ProtocolList supportedProtocolList;
+        private static final ProtocolList serverDefaultProtocolList;
+
+        private static final CipherSuiteList supportedCipherSuiteList;
+        private static final CipherSuiteList serverDefaultCipherSuiteList;
 
         static {
-            // supported SSL parameters
-            supportedSSLParams = new SSLParameters();
-
             // Both DTLSv1.0 and DTLSv1.2 can be used in FIPS mode.
-            supportedSSLParams.setProtocols(new String[] {
+            supportedProtocolList = new ProtocolList(new String[] {
                 ProtocolVersion.DTLS10.name,
                 ProtocolVersion.DTLS12.name
             });
 
-            // candidates for available protocols
-            ProtocolVersion[] candidates = new ProtocolVersion[] {
+            // available protocols for server mode
+            serverDefaultProtocolList = new ProtocolList(
+                    getAvailableProtocols(new ProtocolVersion[] {
                 ProtocolVersion.DTLS10,
                 ProtocolVersion.DTLS12
-            };
+            }));
 
-            defaultServerSSLParams = new SSLParameters();
-            defaultServerSSLParams.setProtocols(
-                    getAvailableProtocols(candidates));
+            supportedCipherSuiteList = getApplicableCipherSuiteList(
+                    supportedProtocolList, false);          // all supported
+            serverDefaultCipherSuiteList = getApplicableCipherSuiteList(
+                    serverDefaultProtocolList, true);       // enabled only
         }
 
         @Override
-        SSLParameters getDefaultServerSSLParams() {
-            return defaultServerSSLParams;
+        ProtocolList getSuportedProtocolList() {
+            return supportedProtocolList;
         }
 
         @Override
-        SSLParameters getSupportedSSLParams() {
-            return supportedSSLParams;
+        CipherSuiteList getSupportedCipherSuiteList() {
+            return supportedCipherSuiteList;
+        }
+
+        @Override
+        ProtocolList getServerDefaultProtocolList() {
+            return serverDefaultProtocolList;
+        }
+
+        @Override
+        CipherSuiteList getServerDefaultCipherSuiteList() {
+            return serverDefaultCipherSuiteList;
         }
 
         @Override
@@ -1028,22 +1053,28 @@
      * @see SSLContext
      */
     public static final class DTLS10Context extends AbstractDTLSContext {
-        private static final SSLParameters defaultClientSSLParams;
+        private static final ProtocolList clientDefaultProtocolList;
+        private static final CipherSuiteList clientDefaultCipherSuiteList;
 
         static {
-            // candidates for available protocols
-            ProtocolVersion[] candidates = new ProtocolVersion[] {
+            // available protocols for client mode
+            clientDefaultProtocolList = new ProtocolList(
+                    getAvailableProtocols(new ProtocolVersion[] {
                 ProtocolVersion.DTLS10
-            };
+            }));
 
-            defaultClientSSLParams = new SSLParameters();
-            defaultClientSSLParams.setProtocols(
-                    getAvailableProtocols(candidates));
+            clientDefaultCipherSuiteList = getApplicableCipherSuiteList(
+                    clientDefaultProtocolList, true);       // enabled only
         }
 
         @Override
-        SSLParameters getDefaultClientSSLParams() {
-            return defaultClientSSLParams;
+        ProtocolList getClientDefaultProtocolList() {
+            return clientDefaultProtocolList;
+        }
+
+        @Override
+        CipherSuiteList getClientDefaultCipherSuiteList() {
+            return clientDefaultCipherSuiteList;
         }
     }
 
@@ -1053,23 +1084,29 @@
      * @see SSLContext
      */
     public static final class DTLS12Context extends AbstractDTLSContext {
-        private static final SSLParameters defaultClientSSLParams;
+        private static final ProtocolList clientDefaultProtocolList;
+        private static final CipherSuiteList clientDefaultCipherSuiteList;
 
         static {
-            // candidates for available protocols
-            ProtocolVersion[] candidates = new ProtocolVersion[] {
+            // available protocols for client mode
+            clientDefaultProtocolList = new ProtocolList(
+                    getAvailableProtocols(new ProtocolVersion[] {
                 ProtocolVersion.DTLS10,
                 ProtocolVersion.DTLS12
-            };
+            }));
 
-            defaultClientSSLParams = new SSLParameters();
-            defaultClientSSLParams.setProtocols(
-                    getAvailableProtocols(candidates));
+            clientDefaultCipherSuiteList = getApplicableCipherSuiteList(
+                    clientDefaultProtocolList, true);       // enabled only
         }
 
         @Override
-        SSLParameters getDefaultClientSSLParams() {
-            return defaultClientSSLParams;
+        ProtocolList getClientDefaultProtocolList() {
+            return clientDefaultProtocolList;
+        }
+
+        @Override
+        CipherSuiteList getClientDefaultCipherSuiteList() {
+            return clientDefaultCipherSuiteList;
         }
     }
 
@@ -1079,7 +1116,9 @@
      * @see SSLContext
      */
     private static class CustomizedDTLSContext extends AbstractDTLSContext {
-        private static final SSLParameters defaultClientSSLParams;
+        private static final ProtocolList clientDefaultProtocolList;
+        private static final CipherSuiteList clientDefaultCipherSuiteList;
+
         private static IllegalArgumentException reservedException = null;
 
         // Don't want a java.lang.LinkageError for illegal system property.
@@ -1119,11 +1158,13 @@
                     candidates = customizedDTLSProtocols.toArray(candidates);
                 }
 
-                defaultClientSSLParams = new SSLParameters();
-                defaultClientSSLParams.setProtocols(
+                clientDefaultProtocolList = new ProtocolList(
                         getAvailableProtocols(candidates));
+                clientDefaultCipherSuiteList = getApplicableCipherSuiteList(
+                    clientDefaultProtocolList, true);   // enabled only
             } else {
-                defaultClientSSLParams = null;   // unlikely to be used
+                clientDefaultProtocolList = null;       // unlikely to be used
+                clientDefaultCipherSuiteList = null;    // unlikely to be used
             }
         }
 
@@ -1134,8 +1175,13 @@
         }
 
         @Override
-        SSLParameters getDefaultClientSSLParams() {
-            return defaultClientSSLParams;
+        ProtocolList getClientDefaultProtocolList() {
+            return clientDefaultProtocolList;
+        }
+
+        @Override
+        CipherSuiteList getClientDefaultCipherSuiteList() {
+            return clientDefaultCipherSuiteList;
         }
     }
 
--- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java	Wed Jul 05 21:10:50 2017 +0200
@@ -130,7 +130,7 @@
      * also since counters make shorter debugging IDs than the big ones
      * we use in the protocol for uniqueness-over-time.
      */
-    private static volatile int counter = 0;
+    private static volatile int counter;
 
     /*
      * Use of session caches is globally enabled/disabled.
--- a/jdk/src/java.base/share/classes/sun/security/x509/X509CRLImpl.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/security/x509/X509CRLImpl.java	Wed Jul 05 21:10:50 2017 +0200
@@ -1290,7 +1290,7 @@
             implements Comparable<X509IssuerSerial> {
         final X500Principal issuer;
         final BigInteger serial;
-        volatile int hashcode = 0;
+        volatile int hashcode;
 
         /**
          * Create an X509IssuerSerial.
@@ -1358,13 +1358,16 @@
          * @return the hash code value
          */
         public int hashCode() {
-            if (hashcode == 0) {
-                int result = 17;
-                result = 37*result + issuer.hashCode();
-                result = 37*result + serial.hashCode();
-                hashcode = result;
+            int h = hashcode;
+            if (h == 0) {
+                h = 17;
+                h = 37*h + issuer.hashCode();
+                h = 37*h + serial.hashCode();
+                if (h != 0) {
+                    hashcode = h;
+                }
             }
-            return hashcode;
+            return h;
         }
 
         @Override
--- a/jdk/src/java.base/share/classes/sun/util/calendar/CalendarSystem.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/util/calendar/CalendarSystem.java	Wed Jul 05 21:10:50 2017 +0200
@@ -25,13 +25,6 @@
 
 package sun.util.calendar;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.security.AccessController;
-import java.security.PrivilegedActionException;
-import java.security.PrivilegedExceptionAction;
-import java.util.Properties;
 import java.util.TimeZone;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
@@ -76,7 +69,7 @@
 
     /////////////////////// Calendar Factory Methods /////////////////////////
 
-    private static volatile boolean initialized = false;
+    private static volatile boolean initialized;
 
     // Map of calendar names and calendar class names
     private static ConcurrentMap<String, String> names;
--- a/jdk/src/java.base/share/classes/sun/util/locale/BaseLocale.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/util/locale/BaseLocale.java	Wed Jul 05 21:10:50 2017 +0200
@@ -46,7 +46,7 @@
     private final String region;
     private final String variant;
 
-    private volatile int hash = 0;
+    private volatile int hash;
 
     // This method must be called only when creating the Locale.* constants.
     private BaseLocale(String language, String region) {
@@ -147,7 +147,9 @@
             h = 31 * h + script.hashCode();
             h = 31 * h + region.hashCode();
             h = 31 * h + variant.hashCode();
-            hash = h;
+            if (h != 0) {
+                hash = h;
+            }
         }
         return h;
     }
--- a/jdk/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java	Wed Jul 05 21:10:50 2017 +0200
@@ -114,20 +114,20 @@
         }
     }
 
-    private volatile BreakIteratorProvider breakIteratorProvider = null;
-    private volatile CollatorProvider collatorProvider = null;
-    private volatile DateFormatProvider dateFormatProvider = null;
-    private volatile DateFormatSymbolsProvider dateFormatSymbolsProvider = null;
-    private volatile DecimalFormatSymbolsProvider decimalFormatSymbolsProvider = null;
-    private volatile NumberFormatProvider numberFormatProvider = null;
+    private volatile BreakIteratorProvider breakIteratorProvider;
+    private volatile CollatorProvider collatorProvider;
+    private volatile DateFormatProvider dateFormatProvider;
+    private volatile DateFormatSymbolsProvider dateFormatSymbolsProvider;
+    private volatile DecimalFormatSymbolsProvider decimalFormatSymbolsProvider;
+    private volatile NumberFormatProvider numberFormatProvider;
 
-    private volatile CurrencyNameProvider currencyNameProvider = null;
-    private volatile LocaleNameProvider localeNameProvider = null;
-    private volatile TimeZoneNameProvider timeZoneNameProvider = null;
-    private volatile CalendarDataProvider calendarDataProvider = null;
-    private volatile CalendarNameProvider calendarNameProvider = null;
+    private volatile CurrencyNameProvider currencyNameProvider;
+    private volatile LocaleNameProvider localeNameProvider;
+    private volatile TimeZoneNameProvider timeZoneNameProvider;
+    private volatile CalendarDataProvider calendarDataProvider;
+    private volatile CalendarNameProvider calendarNameProvider;
 
-    private volatile CalendarProvider calendarProvider = null;
+    private volatile CalendarProvider calendarProvider;
 
     /*
      * Getter methods for java.text.spi.* providers
--- a/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java	Wed Jul 05 21:10:50 2017 +0200
@@ -107,7 +107,7 @@
      * Default fallback adapter type, which should return something meaningful in any case.
      * This is either CLDR or FALLBACK.
      */
-    static volatile LocaleProviderAdapter.Type defaultLocaleProviderAdapter = null;
+    static volatile LocaleProviderAdapter.Type defaultLocaleProviderAdapter;
 
     /**
      * Adapter lookup cache.
--- a/jdk/src/java.base/share/classes/sun/util/resources/OpenListResourceBundle.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/util/resources/OpenListResourceBundle.java	Wed Jul 05 21:10:50 2017 +0200
@@ -164,6 +164,6 @@
         return new HashSet<>();
     }
 
-    private volatile Map<String, Object> lookup = null;
+    private volatile Map<String, Object> lookup;
     private volatile Set<String> keyset;
 }
--- a/jdk/src/java.base/unix/classes/sun/nio/ch/SinkChannelImpl.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/unix/classes/sun/nio/ch/SinkChannelImpl.java	Wed Jul 05 21:10:50 2017 +0200
@@ -47,7 +47,7 @@
     int fdVal;
 
     // ID of native thread doing write, for signalling
-    private volatile long thread = 0;
+    private volatile long thread;
 
     // Lock held by current reading thread
     private final Object lock = new Object();
--- a/jdk/src/java.base/unix/classes/sun/nio/ch/SourceChannelImpl.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/unix/classes/sun/nio/ch/SourceChannelImpl.java	Wed Jul 05 21:10:50 2017 +0200
@@ -47,7 +47,7 @@
     int fdVal;
 
     // ID of native thread doing read, for signalling
-    private volatile long thread = 0;
+    private volatile long thread;
 
     // Lock held by current reading thread
     private final Object lock = new Object();
--- a/jdk/src/java.base/unix/classes/sun/nio/fs/MimeTypesFileTypeDetector.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/unix/classes/sun/nio/fs/MimeTypesFileTypeDetector.java	Wed Jul 05 21:10:50 2017 +0200
@@ -52,7 +52,7 @@
     private Map<String,String> mimeTypeMap;
 
     // set to true when file loaded
-    private volatile boolean loaded = false;
+    private volatile boolean loaded;
 
     public MimeTypesFileTypeDetector(Path filePath) {
         mimeTypesFile = filePath;
--- a/jdk/src/java.base/unix/classes/sun/nio/fs/UnixFileSystemProvider.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/unix/classes/sun/nio/fs/UnixFileSystemProvider.java	Wed Jul 05 21:10:50 2017 +0200
@@ -69,15 +69,16 @@
     private void checkUri(URI uri) {
         if (!uri.getScheme().equalsIgnoreCase(getScheme()))
             throw new IllegalArgumentException("URI does not match this provider");
-        if (uri.getAuthority() != null)
+        if (uri.getRawAuthority() != null)
             throw new IllegalArgumentException("Authority component present");
-        if (uri.getPath() == null)
+        String path = uri.getPath();
+        if (path == null)
             throw new IllegalArgumentException("Path component is undefined");
-        if (!uri.getPath().equals("/"))
+        if (!path.equals("/"))
             throw new IllegalArgumentException("Path component should be '/'");
-        if (uri.getQuery() != null)
+        if (uri.getRawQuery() != null)
             throw new IllegalArgumentException("Query component present");
-        if (uri.getFragment() != null)
+        if (uri.getRawFragment() != null)
             throw new IllegalArgumentException("Fragment component present");
     }
 
--- a/jdk/src/java.base/unix/classes/sun/nio/fs/UnixUriUtils.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/unix/classes/sun/nio/fs/UnixUriUtils.java	Wed Jul 05 21:10:50 2017 +0200
@@ -49,11 +49,11 @@
         String scheme = uri.getScheme();
         if ((scheme == null) || !scheme.equalsIgnoreCase("file"))
             throw new IllegalArgumentException("URI scheme is not \"file\"");
-        if (uri.getAuthority() != null)
+        if (uri.getRawAuthority() != null)
             throw new IllegalArgumentException("URI has an authority component");
-        if (uri.getFragment() != null)
+        if (uri.getRawFragment() != null)
             throw new IllegalArgumentException("URI has a fragment component");
-        if (uri.getQuery() != null)
+        if (uri.getRawQuery() != null)
             throw new IllegalArgumentException("URI has a query component");
 
         // compatibility with java.io.File
--- a/jdk/src/java.base/windows/classes/sun/nio/ch/WindowsSelectorImpl.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/windows/classes/sun/nio/ch/WindowsSelectorImpl.java	Wed Jul 05 21:10:50 2017 +0200
@@ -119,7 +119,7 @@
 
     // Lock for interrupt triggering and clearing
     private final Object interruptLock = new Object();
-    private volatile boolean interruptTriggered = false;
+    private volatile boolean interruptTriggered;
 
     WindowsSelectorImpl(SelectorProvider sp) throws IOException {
         super(sp);
--- a/jdk/src/java.base/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java	Wed Jul 05 21:10:50 2017 +0200
@@ -61,15 +61,16 @@
     private void checkUri(URI uri) {
         if (!uri.getScheme().equalsIgnoreCase(getScheme()))
             throw new IllegalArgumentException("URI does not match this provider");
-        if (uri.getAuthority() != null)
+        if (uri.getRawAuthority() != null)
             throw new IllegalArgumentException("Authority component present");
-        if (uri.getPath() == null)
+        String path = uri.getPath();
+        if (path == null)
             throw new IllegalArgumentException("Path component is undefined");
-        if (!uri.getPath().equals("/"))
+        if (!path.equals("/"))
             throw new IllegalArgumentException("Path component should be '/'");
-        if (uri.getQuery() != null)
+        if (uri.getRawQuery() != null)
             throw new IllegalArgumentException("Query component present");
-        if (uri.getFragment() != null)
+        if (uri.getRawFragment() != null)
             throw new IllegalArgumentException("Fragment component present");
     }
 
--- a/jdk/src/java.base/windows/classes/sun/nio/fs/WindowsUriSupport.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.base/windows/classes/sun/nio/fs/WindowsUriSupport.java	Wed Jul 05 21:10:50 2017 +0200
@@ -123,16 +123,16 @@
         String scheme = uri.getScheme();
         if ((scheme == null) || !scheme.equalsIgnoreCase("file"))
             throw new IllegalArgumentException("URI scheme is not \"file\"");
-        if (uri.getFragment() != null)
+        if (uri.getRawFragment() != null)
             throw new IllegalArgumentException("URI has a fragment component");
-        if (uri.getQuery() != null)
+        if (uri.getRawQuery() != null)
             throw new IllegalArgumentException("URI has a query component");
         String path = uri.getPath();
         if (path.equals(""))
             throw new IllegalArgumentException("URI path component is empty");
 
         // UNC
-        String auth = uri.getAuthority();
+        String auth = uri.getRawAuthority();
         if (auth != null && !auth.equals("")) {
             String host = uri.getHost();
             if (host == null)
--- a/jdk/src/java.datatransfer/share/classes/java/awt/datatransfer/DataFlavor.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.datatransfer/share/classes/java/awt/datatransfer/DataFlavor.java	Wed Jul 05 21:10:50 2017 +0200
@@ -289,6 +289,8 @@
      *     representationClass = String
      *     mimeType           = "text/html"
      * </pre>
+     *
+     * @since 1.8
      */
     public static DataFlavor selectionHtmlFlavor = initHtmlDataFlavor("selection");
 
@@ -301,6 +303,8 @@
      *     representationClass = String
      *     mimeType           = "text/html"
      * </pre>
+     *
+     * @since 1.8
      */
     public static DataFlavor fragmentHtmlFlavor = initHtmlDataFlavor("fragment");
 
@@ -314,6 +318,8 @@
      *     representationClass = String
      *     mimeType           = "text/html"
      * </pre>
+     *
+     * @since 1.8
      */
     public static  DataFlavor allHtmlFlavor = initHtmlDataFlavor("all");
 
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CMenuItem.m	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CMenuItem.m	Wed Jul 05 21:10:50 2017 +0200
@@ -24,6 +24,7 @@
  */
 
 #import <JavaNativeFoundation/JavaNativeFoundation.h>
+#include <Carbon/Carbon.h>
 
 #import "CMenuItem.h"
 #import "CMenu.h"
@@ -40,7 +41,7 @@
 @implementation CMenuItem
 
 - (id) initWithPeer:(jobject)peer asSeparator: (NSNumber *) asSeparator{
-AWT_ASSERT_APPKIT_THREAD;
+    AWT_ASSERT_APPKIT_THREAD;
     self = [super initWithPeer:peer];
     if (self) {
         if ([asSeparator boolValue]) {
@@ -63,13 +64,48 @@
 - (BOOL) worksWhenModal {
     return YES;
 }
+// This is a method written using Carbon framework methods to remove
+// All modifiers including "Shift" modifier.
+// Example 1: Shortcut set is "Command Shift m" returns "m"
+// Example 2: Shortcut set is "Command m" returns "m"
+// Example 3: Shortcut set is "Alt Shift ," returns ","
+
+CFStringRef createStringForKey(CGKeyCode keyCode)
+{
+    TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
+//  currentKeyboard now contains the current input source
+    CFDataRef layoutData =
+    TISGetInputSourceProperty(currentKeyboard,
+                              kTISPropertyUnicodeKeyLayoutData);
+//  the UNICODE keyLayout is fetched from currentKeyboard in layoutData
+    const UCKeyboardLayout *keyboardLayout =
+    (const UCKeyboardLayout *)CFDataGetBytePtr(layoutData);
+//  A read-only data pointer is fetched from layoutData
+    UInt32 keysDown = 0;
+    UniChar chars[4];
+    UniCharCount realLength;
+    
+    UCKeyTranslate(keyboardLayout,
+                   keyCode,
+                   kUCKeyActionDisplay,
+                   0,
+                   LMGetKbdType(),
+                   kUCKeyTranslateNoDeadKeysBit,
+                   &keysDown,
+                   sizeof(chars) / sizeof(chars[0]),
+                   &realLength,
+                   chars);
+    CFRelease(currentKeyboard);
+//  Converts keyCode, modifier and dead-key state into UNICODE characters
+    return CFStringCreateWithCharacters(kCFAllocatorDefault, chars, 1);
+}
 
 // Events
 - (void)handleAction:(NSMenuItem *)sender {
-AWT_ASSERT_APPKIT_THREAD;
+    AWT_ASSERT_APPKIT_THREAD;
     JNIEnv *env = [ThreadUtilities getJNIEnv];
-JNF_COCOA_ENTER(env);
-
+    JNF_COCOA_ENTER(env);
+    
     // If we are called as a result of user pressing a shortcut, do nothing,
     // because AVTView has already sent corresponding key event to the Java
     // layer from performKeyEquivalent.
@@ -82,31 +118,37 @@
     NSEvent *currEvent = [[NSApplication sharedApplication] currentEvent];
     if ([currEvent type] == NSKeyDown) {
         NSString *menuKey = [sender keyEquivalent];
-        NSString *eventKey = [currEvent charactersIgnoringModifiers];
-
-        // Apple uses characters from private Unicode range for some of the
-        // keys, so we need to do the same translation here that we do
-        // for the regular key down events
-        if ([eventKey length] == 1) {
-            unichar origChar = [eventKey characterAtIndex:0];
-            unichar newChar =  NsCharToJavaChar(origChar, 0);
-            if (newChar == java_awt_event_KeyEvent_CHAR_UNDEFINED) {
-                newChar = origChar;
-            }
-
-            eventKey = [NSString stringWithCharacters: &newChar length: 1];
-        }
-
+//      If shortcut is "Command Shift ," the menuKey gets the value ","
+//      But [currEvent charactersIgnoringModifiers]; returns "<" and not ","
+//      because the charactersIgnoreingModifiers does not ignore "Shift"
+//      So a shortcut like "Command Shift m" will return "M" where as the
+//      MenuKey will have the value "m". To remove this issue the below
+//      createStringForKey is used.
+        NSString *eventKey = createStringForKey([currEvent keyCode]);
+        
+//      Apple uses characters from private Unicode range for some of the
+//      keys, so we need to do the same translation here that we do
+//      for the regular key down events
+                if ([eventKey length] == 1) {
+                    unichar origChar = [eventKey characterAtIndex:0];
+                    unichar newChar =  NsCharToJavaChar(origChar, 0);
+                    if (newChar == java_awt_event_KeyEvent_CHAR_UNDEFINED) {
+                        newChar = origChar;
+                    }
+        
+                    eventKey = [NSString stringWithCharacters: &newChar length: 1];
+                }
+        
         NSWindow *keyWindow = [NSApp keyWindow];
         if ([menuKey isEqualToString:eventKey] && keyWindow != nil) {
             return;
         }
     }
-
+    
     if (fIsCheckbox) {
         static JNF_CLASS_CACHE(jc_CCheckboxMenuItem, "sun/lwawt/macosx/CCheckboxMenuItem");
         static JNF_MEMBER_CACHE(jm_ckHandleAction, jc_CCheckboxMenuItem, "handleAction", "(Z)V");
-
+        
         // Send the opposite of what's currently checked -- the action
         // indicates what state we're going to.
         NSInteger state = [sender state];
@@ -115,26 +157,26 @@
     } else {
         static JNF_CLASS_CACHE(jc_CMenuItem, "sun/lwawt/macosx/CMenuItem");
         static JNF_MEMBER_CACHE(jm_handleAction, jc_CMenuItem, "handleAction", "(JI)V"); // AWT_THREADING Safe (event)
-
+        
         NSUInteger modifiers = [currEvent modifierFlags];
         jint javaModifiers = NsKeyModifiersToJavaModifiers(modifiers, NO);
-
+        
         JNFCallVoidMethod(env, fPeer, jm_handleAction, UTC(currEvent), javaModifiers); // AWT_THREADING Safe (event)
     }
-JNF_COCOA_EXIT(env);
+    JNF_COCOA_EXIT(env);
 }
 
 - (void) setJavaLabel:(NSString *)theLabel shortcut:(NSString *)theKeyEquivalent modifierMask:(jint)modifiers {
-
+    
     NSUInteger modifierMask = 0;
-
+    
     if (![theKeyEquivalent isEqualToString:@""]) {
         // Force the key equivalent to lower case if not using the shift key.
         // Otherwise AppKit will draw a Shift glyph in the menu.
         if ((modifiers & java_awt_event_KeyEvent_SHIFT_MASK) == 0) {
             theKeyEquivalent = [theKeyEquivalent lowercaseString];
         }
-
+        
         // Hack for the question mark -- SHIFT and / means use the question mark.
         if ((modifiers & java_awt_event_KeyEvent_SHIFT_MASK) != 0 &&
             [theKeyEquivalent isEqualToString:@"/"])
@@ -142,10 +184,10 @@
             theKeyEquivalent = @"?";
             modifiers &= ~java_awt_event_KeyEvent_SHIFT_MASK;
         }
-
+        
         modifierMask = JavaModifiersToNsKeyModifiers(modifiers, NO);
     }
-
+    
     [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
         [fMenuItem setKeyEquivalent:theKeyEquivalent];
         [fMenuItem setKeyEquivalentModifierMask:modifierMask];
@@ -154,14 +196,14 @@
 }
 
 - (void) setJavaImage:(NSImage *)theImage {
-
+    
     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
         [fMenuItem setImage:theImage];
     }];
 }
 
 - (void) setJavaToolTipText:(NSString *)theText {
-
+    
     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
         [fMenuItem setToolTip:theText];
     }];
@@ -169,11 +211,11 @@
 
 
 - (void)setJavaEnabled:(BOOL) enabled {
-
+    
     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
         @synchronized(self) {
             fIsEnabled = enabled;
-
+            
             // Warning:  This won't work if the parent menu is disabled.
             // See [CMenu syncFromJava]. We still need to call it here so
             // the NSMenuItem itself gets properly updated.
@@ -183,7 +225,7 @@
 }
 
 - (BOOL)isEnabled {
-
+    
     BOOL enabled = NO;
     @synchronized(self) {
         enabled = fIsEnabled;
@@ -193,7 +235,7 @@
 
 
 - (void)setJavaState:(BOOL)newState {
-
+    
     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
         [fMenuItem setState:(newState ? NSOnState : NSOffState)];
     }];
@@ -207,7 +249,7 @@
 - (void)dealloc {
     [fMenuItem release];
     fMenuItem = nil;
-
+    
     [super dealloc];
 }
 
@@ -240,7 +282,7 @@
 /** Convert a Java keycode for SetMenuItemCmd */
 static unichar AWTKeyToMacShortcut(jint awtKey, BOOL doShift) {
     unichar macKey = 0;
-
+    
     if ((awtKey >= java_awt_event_KeyEvent_VK_0 && awtKey <= java_awt_event_KeyEvent_VK_9) ||
         (awtKey >= java_awt_event_KeyEvent_VK_A && awtKey <= java_awt_event_KeyEvent_VK_Z))
     {
@@ -255,68 +297,68 @@
     } else {
         // Special characters
         switch (awtKey) {
-        case java_awt_event_KeyEvent_VK_BACK_QUOTE      : macKey = '`'; break;
-        case java_awt_event_KeyEvent_VK_QUOTE           : macKey = '\''; break;
-
-        case java_awt_event_KeyEvent_VK_ESCAPE          : macKey = 0x1B; break;
-        case java_awt_event_KeyEvent_VK_SPACE           : macKey = ' '; break;
-        case java_awt_event_KeyEvent_VK_PAGE_UP         : macKey = NSPageUpFunctionKey; break;
-        case java_awt_event_KeyEvent_VK_PAGE_DOWN       : macKey = NSPageDownFunctionKey; break;
-        case java_awt_event_KeyEvent_VK_END             : macKey = NSEndFunctionKey; break;
-        case java_awt_event_KeyEvent_VK_HOME            : macKey = NSHomeFunctionKey; break;
-
-        case java_awt_event_KeyEvent_VK_LEFT            : macKey = NSLeftArrowFunctionKey; break;
-        case java_awt_event_KeyEvent_VK_UP              : macKey = NSUpArrowFunctionKey; break;
-        case java_awt_event_KeyEvent_VK_RIGHT           : macKey = NSRightArrowFunctionKey; break;
-        case java_awt_event_KeyEvent_VK_DOWN            : macKey = NSDownArrowFunctionKey; break;
-
-        case java_awt_event_KeyEvent_VK_COMMA           : macKey = ','; break;
-
-        // Mac OS doesn't distinguish between the two '-' keys...
-        case java_awt_event_KeyEvent_VK_MINUS           :
-        case java_awt_event_KeyEvent_VK_SUBTRACT        : macKey = '-'; break;
-
-        // or the two '.' keys...
-        case java_awt_event_KeyEvent_VK_DECIMAL         :
-        case java_awt_event_KeyEvent_VK_PERIOD          : macKey = '.'; break;
-
-        // or the two '/' keys.
-        case java_awt_event_KeyEvent_VK_DIVIDE          :
-        case java_awt_event_KeyEvent_VK_SLASH           : macKey = '/'; break;
-
-        case java_awt_event_KeyEvent_VK_SEMICOLON       : macKey = ';'; break;
-        case java_awt_event_KeyEvent_VK_EQUALS          : macKey = '='; break;
-
-        case java_awt_event_KeyEvent_VK_OPEN_BRACKET    : macKey = '['; break;
-        case java_awt_event_KeyEvent_VK_BACK_SLASH      : macKey = '\\'; break;
-        case java_awt_event_KeyEvent_VK_CLOSE_BRACKET   : macKey = ']'; break;
-
-        case java_awt_event_KeyEvent_VK_MULTIPLY        : macKey = '*'; break;
-        case java_awt_event_KeyEvent_VK_ADD             : macKey = '+'; break;
-
-        case java_awt_event_KeyEvent_VK_HELP            : macKey = NSHelpFunctionKey; break;
-        case java_awt_event_KeyEvent_VK_TAB             : macKey = NSTabCharacter; break;
-        case java_awt_event_KeyEvent_VK_ENTER           : macKey = NSNewlineCharacter; break;
-        case java_awt_event_KeyEvent_VK_BACK_SPACE      : macKey = NSBackspaceCharacter; break;
-        case java_awt_event_KeyEvent_VK_DELETE          : macKey = NSDeleteCharacter; break;
-        case java_awt_event_KeyEvent_VK_CLEAR           : macKey = NSClearDisplayFunctionKey; break;
-        case java_awt_event_KeyEvent_VK_AMPERSAND       : macKey = '&'; break;
-        case java_awt_event_KeyEvent_VK_ASTERISK        : macKey = '*'; break;
-        case java_awt_event_KeyEvent_VK_QUOTEDBL        : macKey = '\"'; break;
-        case java_awt_event_KeyEvent_VK_LESS            : macKey = '<'; break;
-        case java_awt_event_KeyEvent_VK_GREATER         : macKey = '>'; break;
-        case java_awt_event_KeyEvent_VK_BRACELEFT       : macKey = '{'; break;
-        case java_awt_event_KeyEvent_VK_BRACERIGHT      : macKey = '}'; break;
-        case java_awt_event_KeyEvent_VK_AT              : macKey = '@'; break;
-        case java_awt_event_KeyEvent_VK_COLON           : macKey = ':'; break;
-        case java_awt_event_KeyEvent_VK_CIRCUMFLEX      : macKey = '^'; break;
-        case java_awt_event_KeyEvent_VK_DOLLAR          : macKey = '$'; break;
-        case java_awt_event_KeyEvent_VK_EXCLAMATION_MARK : macKey = '!'; break;
-        case java_awt_event_KeyEvent_VK_LEFT_PARENTHESIS : macKey = '('; break;
-        case java_awt_event_KeyEvent_VK_NUMBER_SIGN     : macKey = '#'; break;
-        case java_awt_event_KeyEvent_VK_PLUS            : macKey = '+'; break;
-        case java_awt_event_KeyEvent_VK_RIGHT_PARENTHESIS: macKey = ')'; break;
-        case java_awt_event_KeyEvent_VK_UNDERSCORE      : macKey = '_'; break;
+            case java_awt_event_KeyEvent_VK_BACK_QUOTE      : macKey = '`'; break;
+            case java_awt_event_KeyEvent_VK_QUOTE           : macKey = '\''; break;
+                
+            case java_awt_event_KeyEvent_VK_ESCAPE          : macKey = 0x1B; break;
+            case java_awt_event_KeyEvent_VK_SPACE           : macKey = ' '; break;
+            case java_awt_event_KeyEvent_VK_PAGE_UP         : macKey = NSPageUpFunctionKey; break;
+            case java_awt_event_KeyEvent_VK_PAGE_DOWN       : macKey = NSPageDownFunctionKey; break;
+            case java_awt_event_KeyEvent_VK_END             : macKey = NSEndFunctionKey; break;
+            case java_awt_event_KeyEvent_VK_HOME            : macKey = NSHomeFunctionKey; break;
+                
+            case java_awt_event_KeyEvent_VK_LEFT            : macKey = NSLeftArrowFunctionKey; break;
+            case java_awt_event_KeyEvent_VK_UP              : macKey = NSUpArrowFunctionKey; break;
+            case java_awt_event_KeyEvent_VK_RIGHT           : macKey = NSRightArrowFunctionKey; break;
+            case java_awt_event_KeyEvent_VK_DOWN            : macKey = NSDownArrowFunctionKey; break;
+                
+            case java_awt_event_KeyEvent_VK_COMMA           : macKey = ','; break;
+                
+                // Mac OS doesn't distinguish between the two '-' keys...
+            case java_awt_event_KeyEvent_VK_MINUS           :
+            case java_awt_event_KeyEvent_VK_SUBTRACT        : macKey = '-'; break;
+                
+                // or the two '.' keys...
+            case java_awt_event_KeyEvent_VK_DECIMAL         :
+            case java_awt_event_KeyEvent_VK_PERIOD          : macKey = '.'; break;
+                
+                // or the two '/' keys.
+            case java_awt_event_KeyEvent_VK_DIVIDE          :
+            case java_awt_event_KeyEvent_VK_SLASH           : macKey = '/'; break;
+                
+            case java_awt_event_KeyEvent_VK_SEMICOLON       : macKey = ';'; break;
+            case java_awt_event_KeyEvent_VK_EQUALS          : macKey = '='; break;
+                
+            case java_awt_event_KeyEvent_VK_OPEN_BRACKET    : macKey = '['; break;
+            case java_awt_event_KeyEvent_VK_BACK_SLASH      : macKey = '\\'; break;
+            case java_awt_event_KeyEvent_VK_CLOSE_BRACKET   : macKey = ']'; break;
+                
+            case java_awt_event_KeyEvent_VK_MULTIPLY        : macKey = '*'; break;
+            case java_awt_event_KeyEvent_VK_ADD             : macKey = '+'; break;
+                
+            case java_awt_event_KeyEvent_VK_HELP            : macKey = NSHelpFunctionKey; break;
+            case java_awt_event_KeyEvent_VK_TAB             : macKey = NSTabCharacter; break;
+            case java_awt_event_KeyEvent_VK_ENTER           : macKey = NSNewlineCharacter; break;
+            case java_awt_event_KeyEvent_VK_BACK_SPACE      : macKey = NSBackspaceCharacter; break;
+            case java_awt_event_KeyEvent_VK_DELETE          : macKey = NSDeleteCharacter; break;
+            case java_awt_event_KeyEvent_VK_CLEAR           : macKey = NSClearDisplayFunctionKey; break;
+            case java_awt_event_KeyEvent_VK_AMPERSAND       : macKey = '&'; break;
+            case java_awt_event_KeyEvent_VK_ASTERISK        : macKey = '*'; break;
+            case java_awt_event_KeyEvent_VK_QUOTEDBL        : macKey = '\"'; break;
+            case java_awt_event_KeyEvent_VK_LESS            : macKey = '<'; break;
+            case java_awt_event_KeyEvent_VK_GREATER         : macKey = '>'; break;
+            case java_awt_event_KeyEvent_VK_BRACELEFT       : macKey = '{'; break;
+            case java_awt_event_KeyEvent_VK_BRACERIGHT      : macKey = '}'; break;
+            case java_awt_event_KeyEvent_VK_AT              : macKey = '@'; break;
+            case java_awt_event_KeyEvent_VK_COLON           : macKey = ':'; break;
+            case java_awt_event_KeyEvent_VK_CIRCUMFLEX      : macKey = '^'; break;
+            case java_awt_event_KeyEvent_VK_DOLLAR          : macKey = '$'; break;
+            case java_awt_event_KeyEvent_VK_EXCLAMATION_MARK : macKey = '!'; break;
+            case java_awt_event_KeyEvent_VK_LEFT_PARENTHESIS : macKey = '('; break;
+            case java_awt_event_KeyEvent_VK_NUMBER_SIGN     : macKey = '#'; break;
+            case java_awt_event_KeyEvent_VK_PLUS            : macKey = '+'; break;
+            case java_awt_event_KeyEvent_VK_RIGHT_PARENTHESIS: macKey = ')'; break;
+            case java_awt_event_KeyEvent_VK_UNDERSCORE      : macKey = '_'; break;
         }
     }
     return macKey;
@@ -330,27 +372,27 @@
 JNIEXPORT void JNICALL
 Java_sun_lwawt_macosx_CMenuItem_nativeSetLabel
 (JNIEnv *env, jobject peer,
-     jlong menuItemObj, jstring label,
-     jchar shortcutKey, jint shortcutKeyCode, jint mods)
+ jlong menuItemObj, jstring label,
+ jchar shortcutKey, jint shortcutKeyCode, jint mods)
 {
-JNF_COCOA_ENTER(env);
+    JNF_COCOA_ENTER(env);
     NSString *theLabel = JNFJavaToNSString(env, label);
     NSString *theKeyEquivalent = nil;
     unichar macKey = shortcutKey;
-
+    
     if (macKey == 0) {
         macKey = AWTKeyToMacShortcut(shortcutKeyCode, (mods & java_awt_event_KeyEvent_SHIFT_MASK) != 0);
     }
-
+    
     if (macKey != 0) {
         unichar equivalent[1] = {macKey};
         theKeyEquivalent = [NSString stringWithCharacters:equivalent length:1];
     } else {
         theKeyEquivalent = @"";
     }
-
+    
     [((CMenuItem *)jlong_to_ptr(menuItemObj)) setJavaLabel:theLabel shortcut:theKeyEquivalent modifierMask:mods];
-JNF_COCOA_EXIT(env);
+    JNF_COCOA_EXIT(env);
 }
 
 /*
@@ -362,10 +404,10 @@
 Java_sun_lwawt_macosx_CMenuItem_nativeSetTooltip
 (JNIEnv *env, jobject peer, jlong menuItemObj, jstring tooltip)
 {
-JNF_COCOA_ENTER(env);
+    JNF_COCOA_ENTER(env);
     NSString *theTooltip = JNFJavaToNSString(env, tooltip);
     [((CMenuItem *)jlong_to_ptr(menuItemObj)) setJavaToolTipText:theTooltip];
-JNF_COCOA_EXIT(env);
+    JNF_COCOA_EXIT(env);
 }
 
 /*
@@ -377,9 +419,9 @@
 Java_sun_lwawt_macosx_CMenuItem_nativeSetImage
 (JNIEnv *env, jobject peer, jlong menuItemObj, jlong image)
 {
-JNF_COCOA_ENTER(env);
+    JNF_COCOA_ENTER(env);
     [((CMenuItem *)jlong_to_ptr(menuItemObj)) setJavaImage:(NSImage*)jlong_to_ptr(image)];
-JNF_COCOA_EXIT(env);
+    JNF_COCOA_EXIT(env);
 }
 
 /*
@@ -389,38 +431,38 @@
  */
 JNIEXPORT jlong JNICALL
 Java_sun_lwawt_macosx_CMenuItem_nativeCreate
-    (JNIEnv *env, jobject peer, jlong parentCMenuObj, jboolean isSeparator)
+(JNIEnv *env, jobject peer, jlong parentCMenuObj, jboolean isSeparator)
 {
-
+    
     CMenuItem *aCMenuItem = nil;
     CMenu *parentCMenu = (CMenu *)jlong_to_ptr(parentCMenuObj);
-JNF_COCOA_ENTER(env);
-
+    JNF_COCOA_ENTER(env);
+    
     jobject cPeerObjGlobal = (*env)->NewGlobalRef(env, peer);
-
+    
     NSMutableArray *args = nil;
-
+    
     // Create a new item....
     if (isSeparator == JNI_TRUE) {
         args = [[NSMutableArray alloc] initWithObjects:[NSValue valueWithBytes:&cPeerObjGlobal objCType:@encode(jobject)], [NSNumber numberWithBool:YES],  nil];
     } else {
         args = [[NSMutableArray alloc] initWithObjects:[NSValue valueWithBytes:&cPeerObjGlobal objCType:@encode(jobject)], [NSNumber numberWithBool:NO],  nil];
     }
-
+    
     [ThreadUtilities performOnMainThread:@selector(_createMenuItem_OnAppKitThread:) on:[CMenuItem alloc] withObject:args waitUntilDone:YES];
-
+    
     aCMenuItem = (CMenuItem *)[args objectAtIndex: 0];
-
+    
     if (aCMenuItem == nil) {
         return 0L;
     }
-
+    
     // and add it to the parent item.
     [parentCMenu addJavaMenuItem: aCMenuItem];
-
+    
     // setLabel will be called after creation completes.
-
-JNF_COCOA_EXIT(env);
+    
+    JNF_COCOA_EXIT(env);
     return ptr_to_jlong(aCMenuItem);
 }
 
@@ -433,10 +475,10 @@
 Java_sun_lwawt_macosx_CMenuItem_nativeSetEnabled
 (JNIEnv *env, jobject peer, jlong menuItemObj, jboolean enable)
 {
-JNF_COCOA_ENTER(env);
+    JNF_COCOA_ENTER(env);
     CMenuItem *item = (CMenuItem *)jlong_to_ptr(menuItemObj);
     [item setJavaEnabled: (enable == JNI_TRUE)];
-JNF_COCOA_EXIT(env);
+    JNF_COCOA_EXIT(env);
 }
 
 /*
@@ -448,10 +490,10 @@
 Java_sun_lwawt_macosx_CCheckboxMenuItem_nativeSetState
 (JNIEnv *env, jobject peer, jlong menuItemObj, jboolean state)
 {
-JNF_COCOA_ENTER(env);
+    JNF_COCOA_ENTER(env);
     CMenuItem *item = (CMenuItem *)jlong_to_ptr(menuItemObj);
     [item setJavaState: (state == JNI_TRUE)];
-JNF_COCOA_EXIT(env);
+    JNF_COCOA_EXIT(env);
 }
 
 /*
@@ -463,8 +505,8 @@
 Java_sun_lwawt_macosx_CCheckboxMenuItem_nativeSetIsCheckbox
 (JNIEnv *env, jobject peer, jlong menuItemObj)
 {
-JNF_COCOA_ENTER(env);
+    JNF_COCOA_ENTER(env);
     CMenuItem *item = (CMenuItem *)jlong_to_ptr(menuItemObj);
     [item setIsCheckbox];
-JNF_COCOA_EXIT(env);
+    JNF_COCOA_EXIT(env);
 }
--- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java	Wed Jul 05 21:10:50 2017 +0200
@@ -874,13 +874,13 @@
             return chroma;
         }
 
-        boolean idsAreJFIF = true;
+        boolean idsAreJFIF = false;
 
-        for (int i = 0; i < sof.componentSpecs.length; i++) {
-            int id = sof.componentSpecs[i].componentId;
-            if ((id < 1) || (id >= sof.componentSpecs.length)) {
-                idsAreJFIF = false;
-            }
+        int cid0 = sof.componentSpecs[0].componentId;
+        int cid1 = sof.componentSpecs[1].componentId;
+        int cid2 = sof.componentSpecs[2].componentId;
+        if ((cid0 == 1) && (cid1 == 2) && (cid2 == 3)) {
+            idsAreJFIF = true;
         }
 
         if (idsAreJFIF) {
--- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java	Wed Jul 05 21:10:50 2017 +0200
@@ -193,7 +193,17 @@
 
         // Return to end of chunk and flush to minimize buffering
         stream.seek(pos);
-        stream.flushBefore(pos);
+        try {
+            stream.flushBefore(pos);
+        } catch (IOException e) {
+            /*
+             * If flushBefore() fails we try to access startPos in finally
+             * block of write_IDAT(). We should update startPos to avoid
+             * IndexOutOfBoundException while seek() is happening.
+             */
+            this.startPos = stream.getStreamPosition();
+            throw e;
+        }
     }
 
     public int read() throws IOException {
--- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java	Wed Jul 05 21:10:50 2017 +0200
@@ -472,6 +472,14 @@
             // Read tag number, value type, and value count.
             int tagNumber = stream.readUnsignedShort();
             int type = stream.readUnsignedShort();
+            int sizeOfType;
+            try {
+                sizeOfType = TIFFTag.getSizeOfType(type);
+            } catch (IllegalArgumentException ignored) {
+                // Continue with the next IFD entry.
+                stream.skipBytes(4);
+                continue;
+            }
             int count = (int)stream.readUnsignedInt();
 
             // Get the associated TIFFTag.
@@ -510,14 +518,14 @@
                 }
             }
 
-            int size = count*TIFFTag.getSizeOfType(type);
+            int size = count*sizeOfType;
             if (size > 4 || tag.isIFDPointer()) {
                 // The IFD entry value is a pointer to the actual field value.
                 long offset = stream.readUnsignedInt();
 
                 // Check whether the the field value is within the stream.
                 if (haveStreamLength && offset + size > streamLength) {
-                    throw new IIOException("Field data is past end-of-stream");
+                    continue;
                 }
 
                 // Add a TIFFIFDEntry as a placeholder. This avoids a mark,
--- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java	Wed Jul 05 21:10:50 2017 +0200
@@ -205,6 +205,10 @@
     // Next available space.
     private long nextSpace = 0L;
 
+    private long prevStreamPosition;
+    private long prevHeaderPosition;
+    private long prevNextSpace;
+
     // Whether a sequence is being written.
     private boolean isWritingSequence = false;
     private boolean isInsertingEmpty = false;
@@ -2300,7 +2304,14 @@
     public void write(IIOMetadata sm,
                       IIOImage iioimage,
                       ImageWriteParam p) throws IOException {
+        if (stream == null) {
+            throw new IllegalStateException("output == null!");
+        }
+        markPositions();
         write(sm, iioimage, p, true, true);
+        if (abortRequested()) {
+            resetPositions();
+        }
     }
 
     private void writeHeader() throws IOException {
@@ -2333,7 +2344,7 @@
             throw new IllegalStateException("output == null!");
         }
         if (iioimage == null) {
-            throw new NullPointerException("image == null!");
+            throw new IllegalArgumentException("image == null!");
         }
         if(iioimage.hasRaster() && !canWriteRasters()) {
             throw new UnsupportedOperationException
@@ -2767,7 +2778,7 @@
             throw new IllegalStateException("Output not set!");
         }
         if (image == null) {
-            throw new NullPointerException("image == null!");
+            throw new IllegalArgumentException("image == null!");
         }
 
         // Locate the position of the old IFD (ifd) and the location
@@ -2779,9 +2790,16 @@
         // imageIndex is < -1 or is too big thereby satisfying the spec.
         locateIFD(imageIndex, ifdpos, ifd);
 
+        markPositions();
+
         // Seek to the position containing the pointer to the old IFD.
         stream.seek(ifdpos[0]);
 
+        // Save the previous pointer value in case of abort.
+        stream.mark();
+        long prevPointerValue = stream.readUnsignedInt();
+        stream.reset();
+
         // Update next space pointer in anticipation of next write.
         if(ifdpos[0] + 4 > nextSpace) {
             nextSpace = ifdpos[0] + 4;
@@ -2805,6 +2823,12 @@
         // Update the new IFD to point to the old IFD.
         stream.writeInt((int)ifd[0]);
         // Don't need to update nextSpace here as already done in write().
+
+        if (abortRequested()) {
+            stream.seek(ifdpos[0]);
+            stream.writeInt((int)prevPointerValue);
+            resetPositions();
+        }
     }
 
     // ----- BEGIN insert/writeEmpty methods -----
@@ -2834,7 +2858,7 @@
         }
 
         if(imageType == null) {
-            throw new NullPointerException("imageType == null!");
+            throw new IllegalArgumentException("imageType == null!");
         }
 
         if(width < 1 || height < 1) {
@@ -2891,6 +2915,10 @@
                                   IIOMetadata imageMetadata,
                                   List<? extends BufferedImage> thumbnails,
                                   ImageWriteParam param) throws IOException {
+        if (stream == null) {
+            throw new IllegalStateException("output == null!");
+        }
+
         checkParamsEmpty(imageType, width, height, thumbnails);
 
         this.isWritingEmpty = true;
@@ -2901,8 +2929,12 @@
                            0, 0, emptySM.getWidth(), emptySM.getHeight(),
                            emptySM, imageType.getColorModel());
 
+        markPositions();
         write(streamMetadata, new IIOImage(emptyImage, null, imageMetadata),
               param, true, false);
+        if (abortRequested()) {
+            resetPositions();
+        }
     }
 
     public void endInsertEmpty() throws IOException {
@@ -3015,7 +3047,7 @@
                 throw new IllegalStateException("Output not set!");
             }
             if (region == null) {
-                throw new NullPointerException("region == null!");
+                throw new IllegalArgumentException("region == null!");
             }
             if (region.getWidth() < 1) {
                 throw new IllegalArgumentException("region.getWidth() < 1!");
@@ -3200,7 +3232,7 @@
             }
 
             if (image == null) {
-                throw new NullPointerException("image == null!");
+                throw new IllegalArgumentException("image == null!");
             }
 
             if (!inReplacePixelsNest) {
@@ -3559,6 +3591,20 @@
 
     // ----- END replacePixels methods -----
 
+    // Save stream positions for use when aborted.
+    private void markPositions() throws IOException {
+        prevStreamPosition = stream.getStreamPosition();
+        prevHeaderPosition = headerPosition;
+        prevNextSpace = nextSpace;
+    }
+
+    // Reset to positions saved by markPositions().
+    private void resetPositions() throws IOException {
+        stream.seek(prevStreamPosition);
+        headerPosition = prevHeaderPosition;
+        nextSpace = prevNextSpace;
+    }
+
     public void reset() {
         super.reset();
 
--- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/AbstractMidiDeviceProvider.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/AbstractMidiDeviceProvider.java	Wed Jul 05 21:10:50 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,10 +25,11 @@
 
 package com.sun.media.sound;
 
+import java.util.Objects;
+
 import javax.sound.midi.MidiDevice;
 import javax.sound.midi.spi.MidiDeviceProvider;
 
-
 /**
  * Super class for MIDI input or output device provider.
  *
@@ -127,7 +128,8 @@
     }
 
     @Override
-    public final MidiDevice getDevice(MidiDevice.Info info) {
+    public final MidiDevice getDevice(final MidiDevice.Info info) {
+        Objects.requireNonNull(info);
         if (info instanceof Info) {
             readDeviceInfos();
             MidiDevice[] devices = getDeviceCache();
--- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/JARSoundbankReader.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/JARSoundbankReader.java	Wed Jul 05 21:10:50 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,6 +22,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package com.sun.media.sound;
 
 import java.io.BufferedReader;
@@ -32,6 +33,8 @@
 import java.net.URL;
 import java.net.URLClassLoader;
 import java.util.ArrayList;
+import java.util.Objects;
+
 import javax.sound.midi.InvalidMidiDataException;
 import javax.sound.midi.Soundbank;
 import javax.sound.midi.spi.SoundbankReader;
@@ -112,6 +115,7 @@
 
     public Soundbank getSoundbank(InputStream stream)
             throws InvalidMidiDataException, IOException {
+        Objects.requireNonNull(stream);
         return null;
     }
 
--- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/RealTimeSequencerProvider.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/RealTimeSequencerProvider.java	Wed Jul 05 21:10:50 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,8 @@
 
 package com.sun.media.sound;
 
+import java.util.Objects;
+
 import javax.sound.midi.MidiDevice;
 import javax.sound.midi.spi.MidiDeviceProvider;
 
@@ -42,6 +44,7 @@
 
     @Override
     public MidiDevice getDevice(final MidiDevice.Info info) {
+        Objects.requireNonNull(info);
         if (RealTimeSequencer.info.equals(info)) {
             return new RealTimeSequencer();
         }
--- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftProvider.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftProvider.java	Wed Jul 05 21:10:50 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,8 @@
 
 package com.sun.media.sound;
 
+import java.util.Objects;
+
 import javax.sound.midi.MidiDevice;
 import javax.sound.midi.spi.MidiDeviceProvider;
 
@@ -42,6 +44,7 @@
 
     @Override
     public MidiDevice getDevice(final MidiDevice.Info info) {
+        Objects.requireNonNull(info);
         if (SoftSynthesizer.info.equals(info)) {
             return new SoftSynthesizer();
         }
--- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileWriter.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileWriter.java	Wed Jul 05 21:10:50 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,21 +25,22 @@
 
 package com.sun.media.sound;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.DataOutputStream;
-import java.io.PipedInputStream;
-import java.io.PipedOutputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.ByteArrayInputStream;
-import java.io.SequenceInputStream;
 import java.io.File;
 import java.io.FileOutputStream;
+import java.io.IOException;
 import java.io.InputStream;
-import java.io.IOException;
 import java.io.OutputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.io.SequenceInputStream;
+import java.util.Objects;
 
 import javax.sound.midi.InvalidMidiDataException;
+import javax.sound.midi.MetaMessage;
 import javax.sound.midi.MidiEvent;
-import javax.sound.midi.MetaMessage;
 import javax.sound.midi.Sequence;
 import javax.sound.midi.ShortMessage;
 import javax.sound.midi.SysexMessage;
@@ -115,24 +116,16 @@
         return typesArray;
     }
 
-    public boolean isFileTypeSupported(int type) {
-        for(int i=0; i<types.length; i++) {
-            if( type == types[i] ) {
-                return true;
-            }
+    public int write(Sequence in, int type, OutputStream out) throws IOException {
+        Objects.requireNonNull(out);
+        if (!isFileTypeSupported(type, in)) {
+            throw new IllegalArgumentException("Could not write MIDI file");
         }
-        return false;
-    }
-
-    public int write(Sequence in, int type, OutputStream out) throws IOException {
         byte [] buffer = null;
 
         int bytesRead = 0;
         long bytesWritten = 0;
 
-        if( !isFileTypeSupported(type,in) ) {
-            throw new IllegalArgumentException("Could not write MIDI file");
-        }
         // First get the fileStream from this sequence
         InputStream fileStream = getFileStream(type,in);
         if (fileStream == null) {
@@ -149,6 +142,7 @@
     }
 
     public int write(Sequence in, int type, File out) throws IOException {
+        Objects.requireNonNull(in);
         FileOutputStream fos = new FileOutputStream(out); // throws IOException
         int bytesWritten = write( in, type, fos );
         fos.close();
--- a/jdk/src/java.desktop/share/classes/java/awt/TextComponent.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/java/awt/TextComponent.java	Wed Jul 05 21:10:50 2017 +0200
@@ -229,15 +229,21 @@
      * @see         java.awt.TextComponent#getText
      */
     public synchronized void setText(String t) {
-        boolean skipTextEvent = (text == null || text.isEmpty())
-                && (t == null || t.isEmpty());
-        text = (t != null) ? t : "";
+        if (t == null) {
+            t = "";
+        }
         TextComponentPeer peer = (TextComponentPeer)this.peer;
-        // Please note that we do not want to post an event
-        // if TextArea.setText() or TextField.setText() replaces an empty text
-        // by an empty text, that is, if component's text remains unchanged.
-        if (peer != null && !skipTextEvent) {
-            peer.setText(text);
+        if (peer != null) {
+            text = peer.getText();
+            // Please note that we do not want to post an event
+            // if TextArea.setText() or TextField.setText() replaces text
+            // by same text, that is, if component's text remains unchanged.
+            if (!t.equals(text)) {
+                text = t;
+                peer.setText(text);
+            }
+        } else {
+            text = t;
         }
     }
 
--- a/jdk/src/java.desktop/share/classes/java/awt/TextField.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/java/awt/TextField.java	Wed Jul 05 21:10:50 2017 +0200
@@ -198,7 +198,7 @@
      * @see java.awt.GraphicsEnvironment#isHeadless
      */
     public TextField(String text, int columns) throws HeadlessException {
-        super(text);
+        super(replaceEOL(text));
         this.columns = (columns >= 0) ? columns : 0;
     }
 
@@ -297,13 +297,32 @@
      * @see         java.awt.TextComponent#getText
      */
     public void setText(String t) {
-        super.setText(t);
+        super.setText(replaceEOL(t));
 
         // This could change the preferred size of the Component.
         invalidateIfValid();
     }
 
     /**
+     * Replaces EOL characters from the text variable with a space character.
+     * @param       text   the new text.
+     * @return      Returns text after replacing EOL characters.
+     */
+    private static String replaceEOL(String text) {
+        if (text == null) {
+            return text;
+        }
+        String[] strEOLs = {System.lineSeparator(), "\n"};
+        for (String eol : strEOLs) {
+            if (text.contains(eol)) {
+                text = text.replace(eol, " ");
+            }
+        }
+        return text;
+    }
+
+
+    /**
      * Indicates whether or not this text field has a
      * character set for echoing.
      * <p>
@@ -704,6 +723,7 @@
     {
         // HeadlessException will be thrown by TextComponent's readObject
         s.defaultReadObject();
+        text = replaceEOL(text);
 
         // Make sure the state we just read in for columns has legal values
         if (columns < 0) {
--- a/jdk/src/java.desktop/share/classes/javax/imageio/ImageIO.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/javax/imageio/ImageIO.java	Wed Jul 05 21:10:50 2017 +0200
@@ -564,9 +564,12 @@
                 if (stream != null) {
                     stream.mark();
                 }
-                canDecode = spi.canDecodeInput(input);
-                if (stream != null) {
-                    stream.reset();
+                try {
+                    canDecode = spi.canDecodeInput(input);
+                } finally {
+                    if (stream != null) {
+                        stream.reset();
+                    }
                 }
 
                 return canDecode;
--- a/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiSystem.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/MidiSystem.java	Wed Jul 05 21:10:50 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,6 +35,7 @@
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Objects;
 import java.util.Properties;
 import java.util.Set;
 
@@ -179,10 +180,12 @@
      *         due to resource restrictions
      * @throws IllegalArgumentException if the info object does not represent a
      *         MIDI device installed on the system
+     * @throws NullPointerException if {@code info} is {@code null}
      * @see #getMidiDeviceInfo
      */
     public static MidiDevice getMidiDevice(final MidiDevice.Info info)
             throws MidiUnavailableException {
+        Objects.requireNonNull(info);
         for (final MidiDeviceProvider provider : getMidiDeviceProviders()) {
             if (provider.isDeviceSupported(info)) {
                 return provider.getDevice(info);
@@ -447,11 +450,13 @@
      * @throws InvalidMidiDataException if the stream does not point to valid
      *         MIDI soundbank data recognized by the system
      * @throws IOException if an I/O error occurred when loading the soundbank
+     * @throws NullPointerException if {@code stream} is {@code null}
      * @see InputStream#markSupported
      * @see InputStream#mark
      */
-    public static Soundbank getSoundbank(InputStream stream)
-        throws InvalidMidiDataException, IOException {
+    public static Soundbank getSoundbank(final InputStream stream)
+            throws InvalidMidiDataException, IOException {
+        Objects.requireNonNull(stream);
 
         SoundbankReader sp = null;
         Soundbank s = null;
@@ -479,9 +484,11 @@
      * @throws InvalidMidiDataException if the URL does not point to valid MIDI
      *         soundbank data recognized by the system
      * @throws IOException if an I/O error occurred when loading the soundbank
+     * @throws NullPointerException if {@code url} is {@code null}
      */
-    public static Soundbank getSoundbank(URL url)
-        throws InvalidMidiDataException, IOException {
+    public static Soundbank getSoundbank(final URL url)
+            throws InvalidMidiDataException, IOException {
+        Objects.requireNonNull(url);
 
         SoundbankReader sp = null;
         Soundbank s = null;
@@ -509,9 +516,11 @@
      * @throws InvalidMidiDataException if the {@code File} does not point to
      *         valid MIDI soundbank data recognized by the system
      * @throws IOException if an I/O error occurred when loading the soundbank
+     * @throws NullPointerException if {@code file} is {@code null}
      */
-    public static Soundbank getSoundbank(File file)
-        throws InvalidMidiDataException, IOException {
+    public static Soundbank getSoundbank(final File file)
+            throws InvalidMidiDataException, IOException {
+        Objects.requireNonNull(file);
 
         SoundbankReader sp = null;
         Soundbank s = null;
@@ -556,13 +565,15 @@
      *         MIDI file data recognized by the system
      * @throws IOException if an I/O exception occurs while accessing the
      *         stream
+     * @throws NullPointerException if {@code stream} is {@code null}
      * @see #getMidiFileFormat(URL)
      * @see #getMidiFileFormat(File)
      * @see InputStream#markSupported
      * @see InputStream#mark
      */
-    public static MidiFileFormat getMidiFileFormat(InputStream stream)
-        throws InvalidMidiDataException, IOException {
+    public static MidiFileFormat getMidiFileFormat(final InputStream stream)
+            throws InvalidMidiDataException, IOException {
+        Objects.requireNonNull(stream);
 
         List<MidiFileReader> providers = getMidiFileReaders();
         MidiFileFormat format = null;
@@ -602,11 +613,13 @@
      * @throws InvalidMidiDataException if the URL does not point to valid MIDI
      *         file data recognized by the system
      * @throws IOException if an I/O exception occurs while accessing the URL
+     * @throws NullPointerException if {@code url} is {@code null}
      * @see #getMidiFileFormat(InputStream)
      * @see #getMidiFileFormat(File)
      */
-    public static MidiFileFormat getMidiFileFormat(URL url)
-        throws InvalidMidiDataException, IOException {
+    public static MidiFileFormat getMidiFileFormat(final URL url)
+            throws InvalidMidiDataException, IOException {
+        Objects.requireNonNull(url);
 
         List<MidiFileReader> providers = getMidiFileReaders();
         MidiFileFormat format = null;
@@ -646,11 +659,13 @@
      * @throws InvalidMidiDataException if the {@code File} does not point to
      *         valid MIDI file data recognized by the system
      * @throws IOException if an I/O exception occurs while accessing the file
+     * @throws NullPointerException if {@code file} is {@code null}
      * @see #getMidiFileFormat(InputStream)
      * @see #getMidiFileFormat(URL)
      */
-    public static MidiFileFormat getMidiFileFormat(File file)
-        throws InvalidMidiDataException, IOException {
+    public static MidiFileFormat getMidiFileFormat(final File file)
+            throws InvalidMidiDataException, IOException {
+        Objects.requireNonNull(file);
 
         List<MidiFileReader> providers = getMidiFileReaders();
         MidiFileFormat format = null;
@@ -699,11 +714,13 @@
      * @throws InvalidMidiDataException if the stream does not point to valid
      *         MIDI file data recognized by the system
      * @throws IOException if an I/O exception occurs while accessing the stream
+     * @throws NullPointerException if {@code stream} is {@code null}
      * @see InputStream#markSupported
      * @see InputStream#mark
      */
-    public static Sequence getSequence(InputStream stream)
-        throws InvalidMidiDataException, IOException {
+    public static Sequence getSequence(final InputStream stream)
+            throws InvalidMidiDataException, IOException {
+        Objects.requireNonNull(stream);
 
         List<MidiFileReader> providers = getMidiFileReaders();
         Sequence sequence = null;
@@ -743,9 +760,11 @@
      * @throws InvalidMidiDataException if the URL does not point to valid MIDI
      *         file data recognized by the system
      * @throws IOException if an I/O exception occurs while accessing the URL
+     * @throws NullPointerException if {@code url} is {@code null}
      */
-    public static Sequence getSequence(URL url)
-        throws InvalidMidiDataException, IOException {
+    public static Sequence getSequence(final URL url)
+            throws InvalidMidiDataException, IOException {
+        Objects.requireNonNull(url);
 
         List<MidiFileReader> providers = getMidiFileReaders();
         Sequence sequence = null;
@@ -787,9 +806,11 @@
      * @throws InvalidMidiDataException if the File does not point to valid MIDI
      *         file data recognized by the system
      * @throws IOException if an I/O exception occurs
+     * @throws NullPointerException if {@code file} is {@code null}
      */
-    public static Sequence getSequence(File file)
-        throws InvalidMidiDataException, IOException {
+    public static Sequence getSequence(final File file)
+            throws InvalidMidiDataException, IOException {
+        Objects.requireNonNull(file);
 
         List<MidiFileReader> providers = getMidiFileReaders();
         Sequence sequence = null;
@@ -870,8 +891,10 @@
      * @param  sequence the sequence for which MIDI file type support is queried
      * @return the set of unique supported file types. If no file types are
      *         supported, returns an array of length 0.
+     * @throws NullPointerException if {@code sequence} is {@code null}
      */
-    public static int[] getMidiFileTypes(Sequence sequence) {
+    public static int[] getMidiFileTypes(final Sequence sequence) {
+        Objects.requireNonNull(sequence);
 
         List<MidiFileWriter> providers = getMidiFileWriters();
         Set<Integer> allTypes = new HashSet<>();
@@ -903,8 +926,11 @@
      * @param  sequence the sequence for which file writing support is queried
      * @return {@code true} if the file type is supported for this sequence,
      *         otherwise {@code false}
+     * @throws NullPointerException if {@code sequence} is {@code null}
      */
-    public static boolean isFileTypeSupported(int fileType, Sequence sequence) {
+    public static boolean isFileTypeSupported(final int fileType,
+                                              final Sequence sequence) {
+        Objects.requireNonNull(sequence);
 
         List<MidiFileWriter> providers = getMidiFileWriters();
 
@@ -929,10 +955,15 @@
      * @throws IOException if an I/O exception occurs
      * @throws IllegalArgumentException if the file format is not supported by
      *         the system
+     * @throws NullPointerException if {@code in} or {@code out} are
+     *         {@code null}
      * @see #isFileTypeSupported(int, Sequence)
      * @see #getMidiFileTypes(Sequence)
      */
-    public static int write(Sequence in, int fileType, OutputStream out) throws IOException {
+    public static int write(final Sequence in, final int fileType,
+                            final OutputStream out) throws IOException {
+        Objects.requireNonNull(in);
+        Objects.requireNonNull(out);
 
         List<MidiFileWriter> providers = getMidiFileWriters();
         //$$fb 2002-04-17: Fix for 4635287: Standard MidiFileWriter cannot write empty Sequences
@@ -963,10 +994,15 @@
      * @throws IOException if an I/O exception occurs
      * @throws IllegalArgumentException if the file type is not supported by the
      *         system
+     * @throws NullPointerException if {@code in} or {@code out} are
+     *         {@code null}
      * @see #isFileTypeSupported(int, Sequence)
      * @see #getMidiFileTypes(Sequence)
      */
-    public static int write(Sequence in, int type, File out) throws IOException {
+    public static int write(final Sequence in, final int type, final File out)
+            throws IOException {
+        Objects.requireNonNull(in);
+        Objects.requireNonNull(out);
 
         List<MidiFileWriter> providers = getMidiFileWriters();
         //$$fb 2002-04-17: Fix for 4635287: Standard MidiFileWriter cannot write empty Sequences
--- a/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/MidiDeviceProvider.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/MidiDeviceProvider.java	Wed Jul 05 21:10:50 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
 package javax.sound.midi.spi;
 
 import java.util.Arrays;
+import java.util.Objects;
 
 import javax.sound.midi.MidiDevice;
 
@@ -46,8 +47,10 @@
      *         is queried
      * @return {@code true} if the specified device is supported, otherwise
      *         {@code false}
+     * @throws NullPointerException if {@code info} is {@code null}
      */
     public boolean isDeviceSupported(final MidiDevice.Info info) {
+        Objects.requireNonNull(info);
         return Arrays.asList(getDeviceInfo()).contains(info);
     }
 
@@ -67,6 +70,7 @@
      * @throws IllegalArgumentException if the info object specified does not
      *         match the info object for a device supported by this
      *         {@code MidiDeviceProvider}
+     * @throws NullPointerException if {@code info} is {@code null}
      */
     public abstract MidiDevice getDevice(MidiDevice.Info info);
 }
--- a/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/MidiFileReader.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/MidiFileReader.java	Wed Jul 05 21:10:50 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -60,6 +60,7 @@
      * @throws InvalidMidiDataException if the stream does not point to valid
      *         MIDI file data recognized by the system
      * @throws IOException if an I/O exception occurs
+     * @throws NullPointerException if {@code stream} is {@code null}
      * @see InputStream#markSupported
      * @see InputStream#mark
      */
@@ -76,6 +77,7 @@
      * @throws InvalidMidiDataException if the URL does not point to valid MIDI
      *         file data recognized by the system
      * @throws IOException if an I/O exception occurs
+     * @throws NullPointerException if {@code url} is {@code null}
      */
     public abstract MidiFileFormat getMidiFileFormat(URL url)
             throws InvalidMidiDataException, IOException;
@@ -90,6 +92,7 @@
      * @throws InvalidMidiDataException if the {@code File} does not point to
      *         valid MIDI file data recognized by the system
      * @throws IOException if an I/O exception occurs
+     * @throws NullPointerException if {@code file} is {@code null}
      */
     public abstract MidiFileFormat getMidiFileFormat(File file)
             throws InvalidMidiDataException, IOException;
@@ -110,6 +113,7 @@
      * @throws InvalidMidiDataException if the stream does not point to valid
      *         MIDI file data recognized by the system
      * @throws IOException if an I/O exception occurs
+     * @throws NullPointerException if {@code stream} is {@code null}
      * @see InputStream#markSupported
      * @see InputStream#mark
      */
@@ -126,6 +130,7 @@
      * @throws InvalidMidiDataException if the URL does not point to valid MIDI
      *         file data recognized by the system
      * @throws IOException if an I/O exception occurs
+     * @throws NullPointerException if {@code url} is {@code null}
      */
     public abstract Sequence getSequence(URL url)
             throws InvalidMidiDataException, IOException;
@@ -141,6 +146,7 @@
      * @throws InvalidMidiDataException if the {@code File} does not point to
      *         valid MIDI file data recognized by the system
      * @throws IOException if an I/O exception occurs
+     * @throws NullPointerException if {@code file} is {@code null}
      */
     public abstract Sequence getSequence(File file)
             throws InvalidMidiDataException, IOException;
--- a/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/MidiFileWriter.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/MidiFileWriter.java	Wed Jul 05 21:10:50 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -58,6 +58,7 @@
      *         queried
      * @return array of file types. If no file types are supported, returns an
      *         array of length 0.
+     * @throws NullPointerException if {@code sequence} is {@code null}
      */
     public abstract int[] getMidiFileTypes(Sequence sequence);
 
@@ -88,6 +89,7 @@
      * @param  sequence the sequence for which file writing support is queried
      * @return {@code true} if the file type is supported for this sequence,
      *         otherwise {@code false}
+     * @throws NullPointerException if {@code sequence} is {@code null}
      */
     public boolean isFileTypeSupported(int fileType, Sequence sequence) {
 
@@ -111,6 +113,8 @@
      * @throws IOException if an I/O exception occurs
      * @throws IllegalArgumentException if the file type is not supported by
      *         this file writer
+     * @throws NullPointerException if {@code in} or {@code out} are
+     *         {@code null}
      * @see #isFileTypeSupported(int, Sequence)
      * @see #getMidiFileTypes(Sequence)
      */
@@ -129,6 +133,8 @@
      * @throws IOException if an I/O exception occurs
      * @throws IllegalArgumentException if the file type is not supported by
      *         this file writer
+     * @throws NullPointerException if {@code in} or {@code out} are
+     *         {@code null}
      * @see #isFileTypeSupported(int, Sequence)
      * @see #getMidiFileTypes(Sequence)
      */
--- a/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/SoundbankReader.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/SoundbankReader.java	Wed Jul 05 21:10:50 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -52,6 +52,7 @@
      * @throws InvalidMidiDataException if the URL does not point to valid MIDI
      *         soundbank data recognized by this soundbank reader
      * @throws IOException if an I/O error occurs
+     * @throws NullPointerException if {@code url} is {@code null}
      */
     public abstract Soundbank getSoundbank(URL url)
             throws InvalidMidiDataException, IOException;
@@ -64,6 +65,7 @@
      * @throws InvalidMidiDataException if the stream does not point to valid
      *         MIDI soundbank data recognized by this soundbank reader
      * @throws IOException if an I/O error occurs
+     * @throws NullPointerException if {@code stream} is {@code null}
      */
     public abstract Soundbank getSoundbank(InputStream stream)
             throws InvalidMidiDataException, IOException;
@@ -76,6 +78,7 @@
      * @throws InvalidMidiDataException if the file does not point to valid MIDI
      *         soundbank data recognized by this soundbank reader
      * @throws IOException if an I/O error occurs
+     * @throws NullPointerException if {@code file} is {@code null}
      */
     public abstract Soundbank getSoundbank(File file)
             throws InvalidMidiDataException, IOException;
--- a/jdk/src/java.desktop/share/classes/javax/swing/JComponent.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/javax/swing/JComponent.java	Wed Jul 05 21:10:50 2017 +0200
@@ -618,6 +618,7 @@
      * @return the {@code ComponentUI} object that renders this component
      * @since 1.9
      */
+    @Transient
     public ComponentUI getUI() {
         return ui;
     }
--- a/jdk/src/java.desktop/share/classes/javax/swing/filechooser/FileSystemView.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/javax/swing/filechooser/FileSystemView.java	Wed Jul 05 21:10:50 2017 +0200
@@ -663,7 +663,9 @@
         if(newFolder.exists()) {
             throw new IOException("Directory already exists:" + newFolder.getAbsolutePath());
         } else {
-            newFolder.mkdirs();
+            if(!newFolder.mkdirs()) {
+                throw new IOException(newFolder.getAbsolutePath());
+            }
         }
 
         return newFolder;
@@ -773,7 +775,9 @@
         if(newFolder.exists()) {
             throw new IOException("Directory already exists:" + newFolder.getAbsolutePath());
         } else {
-            newFolder.mkdirs();
+            if(!newFolder.mkdirs()) {
+                throw new IOException(newFolder.getAbsolutePath());
+            }
         }
 
         return newFolder;
@@ -842,9 +846,10 @@
         if(newFolder.exists()) {
             throw new IOException("Directory already exists:" + newFolder.getAbsolutePath());
         } else {
-            newFolder.mkdirs();
+            if(!newFolder.mkdirs()) {
+                throw new IOException(newFolder.getAbsolutePath());
+            }
         }
-
         return newFolder;
     }
 
--- a/jdk/src/java.desktop/share/classes/javax/swing/text/AbstractDocument.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/javax/swing/text/AbstractDocument.java	Wed Jul 05 21:10:50 2017 +0200
@@ -36,6 +36,7 @@
 
 import sun.font.BidiUtils;
 import sun.swing.SwingUtilities2;
+import sun.swing.text.UndoableEditLockSupport;
 
 /**
  * An implementation of the document interface to serve as a
@@ -275,6 +276,11 @@
      * @see EventListenerList
      */
     protected void fireUndoableEditUpdate(UndoableEditEvent e) {
+        if (e.getEdit() instanceof DefaultDocumentEvent) {
+            e = new UndoableEditEvent(e.getSource(),
+                    new DefaultDocumentEventUndoableWrapper(
+                            (DefaultDocumentEvent)e.getEdit()));
+        }
         // Guaranteed to return a non-null array
         Object[] listeners = listenerList.getListenerList();
         // Process the listeners last to first, notifying
@@ -2952,6 +2958,88 @@
 
     }
 
+    static class DefaultDocumentEventUndoableWrapper implements
+            UndoableEdit, UndoableEditLockSupport
+    {
+        final DefaultDocumentEvent dde;
+        public DefaultDocumentEventUndoableWrapper(DefaultDocumentEvent dde) {
+            this.dde = dde;
+        }
+
+        @Override
+        public void undo() throws CannotUndoException {
+            dde.undo();
+        }
+
+        @Override
+        public boolean canUndo() {
+            return dde.canUndo();
+        }
+
+        @Override
+        public void redo() throws CannotRedoException {
+            dde.redo();
+        }
+
+        @Override
+        public boolean canRedo() {
+            return dde.canRedo();
+        }
+
+        @Override
+        public void die() {
+            dde.die();
+        }
+
+        @Override
+        public boolean addEdit(UndoableEdit anEdit) {
+            return dde.addEdit(anEdit);
+        }
+
+        @Override
+        public boolean replaceEdit(UndoableEdit anEdit) {
+            return dde.replaceEdit(anEdit);
+        }
+
+        @Override
+        public boolean isSignificant() {
+            return dde.isSignificant();
+        }
+
+        @Override
+        public String getPresentationName() {
+            return dde.getPresentationName();
+        }
+
+        @Override
+        public String getUndoPresentationName() {
+            return dde.getUndoPresentationName();
+        }
+
+        @Override
+        public String getRedoPresentationName() {
+            return dde.getRedoPresentationName();
+        }
+
+        /**
+         * {@inheritDoc}
+         * @since 1.9
+         */
+        @Override
+        public void lockEdit() {
+            ((AbstractDocument)dde.getDocument()).writeLock();
+        }
+
+        /**
+         * {@inheritDoc}
+         * @since 1.9
+         */
+        @Override
+        public void unlockEdit() {
+            ((AbstractDocument)dde.getDocument()).writeUnlock();
+        }
+    }
+
     /**
      * This event used when firing document changes while Undo/Redo
      * operations. It just wraps DefaultDocumentEvent and delegates
--- a/jdk/src/java.desktop/share/classes/javax/swing/undo/UndoManager.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/javax/swing/undo/UndoManager.java	Wed Jul 05 21:10:50 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,6 +28,7 @@
 import javax.swing.event.*;
 import javax.swing.UIManager;
 import java.util.*;
+import sun.swing.text.UndoableEditLockSupport;
 
 /**
  * {@code UndoManager} manages a list of {@code UndoableEdits},
@@ -134,6 +135,11 @@
  */
 @SuppressWarnings("serial") // Same-version serialization only
 public class UndoManager extends CompoundEdit implements UndoableEditListener {
+    private enum Action {
+        UNDO,
+        REDO,
+        ANY
+    }
     int indexOfNextAdd;
     int limit;
 
@@ -369,13 +375,8 @@
      * @throws CannotRedoException if one of the edits throws
      *         <code>CannotRedoException</code>
      */
-    public synchronized void undoOrRedo() throws CannotRedoException,
-        CannotUndoException {
-        if (indexOfNextAdd == edits.size()) {
-            undo();
-        } else {
-            redo();
-        }
+    public void undoOrRedo() throws CannotRedoException, CannotUndoException {
+        tryUndoOrRedo(Action.ANY);
     }
 
     /**
@@ -407,16 +408,8 @@
      * @see #canUndo
      * @see #editToBeUndone
      */
-    public synchronized void undo() throws CannotUndoException {
-        if (inProgress) {
-            UndoableEdit edit = editToBeUndone();
-            if (edit == null) {
-                throw new CannotUndoException();
-            }
-            undoTo(edit);
-        } else {
-            super.undo();
-        }
+    public void undo() throws CannotUndoException {
+        tryUndoOrRedo(Action.UNDO);
     }
 
     /**
@@ -452,16 +445,90 @@
      * @see #canRedo
      * @see #editToBeRedone
      */
-    public synchronized void redo() throws CannotRedoException {
-        if (inProgress) {
-            UndoableEdit edit = editToBeRedone();
-            if (edit == null) {
-                throw new CannotRedoException();
+    public void redo() throws CannotRedoException {
+        tryUndoOrRedo(Action.REDO);
+    }
+
+    private void tryUndoOrRedo(Action action) {
+        UndoableEditLockSupport lockSupport = null;
+        boolean undo;
+        synchronized (this) {
+            if (action == Action.ANY) {
+                undo = indexOfNextAdd == edits.size();
+            } else {
+                undo = action == Action.UNDO;
+            }
+            if (inProgress) {
+                UndoableEdit edit = undo ? editToBeUndone() : editToBeRedone();
+                if (edit == null) {
+                    throw undo ? new CannotUndoException() :
+                            new CannotRedoException();
+                }
+                lockSupport = getEditLockSupport(edit);
+                if (lockSupport == null) {
+                    if (undo) {
+                        undoTo(edit);
+                    } else {
+                        redoTo(edit);
+                    }
+                    return;
+                }
+            } else {
+                if (undo) {
+                    super.undo();
+                } else {
+                    super.redo();
+                }
+                return;
             }
-            redoTo(edit);
-        } else {
-            super.redo();
         }
+        // the edit synchronization is required
+        while (true) {
+            lockSupport.lockEdit();
+            UndoableEditLockSupport editLockSupport = null;
+            try {
+                synchronized (this) {
+                    if (action == Action.ANY) {
+                        undo = indexOfNextAdd == edits.size();
+                    }
+                    if (inProgress) {
+                        UndoableEdit edit = undo ? editToBeUndone() :
+                                editToBeRedone();
+                        if (edit == null) {
+                            throw undo ? new CannotUndoException() :
+                                    new CannotRedoException();
+                        }
+                        editLockSupport = getEditLockSupport(edit);
+                        if (editLockSupport == null ||
+                                editLockSupport == lockSupport) {
+                            if (undo) {
+                                undoTo(edit);
+                            } else {
+                                redoTo(edit);
+                            }
+                            return;
+                        }
+                    } else {
+                        if (undo) {
+                            super.undo();
+                        } else {
+                            super.redo();
+                        }
+                        return;
+                    }
+                }
+            } finally {
+                if (lockSupport != null) {
+                    lockSupport.unlockEdit();
+                }
+                lockSupport = editLockSupport;
+            }
+        }
+    }
+
+    private UndoableEditLockSupport getEditLockSupport(UndoableEdit anEdit) {
+        return anEdit instanceof UndoableEditLockSupport ?
+                (UndoableEditLockSupport)anEdit : null;
     }
 
     /**
--- a/jdk/src/java.desktop/share/classes/sun/awt/image/SunVolatileImage.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/sun/awt/image/SunVolatileImage.java	Wed Jul 05 21:10:50 2017 +0200
@@ -70,6 +70,10 @@
     {
         this.comp = comp;
         this.graphicsConfig = graphicsConfig;
+        if (width <= 0 || height <= 0) {
+            throw new IllegalArgumentException("Width (" + width + ")" +
+                              " and height (" + height + ") cannot be <= 0");
+        }
         this.width = width;
         this.height = height;
         this.forcedAccelSurfaceType = accType;
--- a/jdk/src/java.desktop/share/classes/sun/font/StandardGlyphVector.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/sun/font/StandardGlyphVector.java	Wed Jul 05 21:10:50 2017 +0200
@@ -445,13 +445,19 @@
     }
 
     public void setGlyphPosition(int ix, Point2D pos) {
+        if (ix < 0 || ix > glyphs.length) {
+            throw new IndexOutOfBoundsException("ix = " + ix);
+        }
+
         initPositions();
 
         int ix2 = ix << 1;
         positions[ix2] = (float)pos.getX();
         positions[ix2 + 1] = (float)pos.getY();
 
-        clearCaches(ix);
+        if (ix < glyphs.length) {
+            clearCaches(ix);
+        }
         addFlags(FLAG_HAS_POSITION_ADJUSTMENTS);
     }
 
--- a/jdk/src/java.desktop/share/classes/sun/font/TrueTypeFont.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/sun/font/TrueTypeFont.java	Wed Jul 05 21:10:50 2017 +0200
@@ -176,6 +176,13 @@
     private String localeFamilyName;
     private String localeFullName;
 
+    public TrueTypeFont(String platname, Object nativeNames, int fIndex,
+                 boolean javaRasterizer)
+        throws FontFormatException
+    {
+        this(platname, nativeNames, fIndex, javaRasterizer, true);
+    }
+
     /**
      * - does basic verification of the file
      * - reads the header table for this font (within a collection)
@@ -186,14 +193,17 @@
      * or fails verification,  or there's no usable cmap
      */
     public TrueTypeFont(String platname, Object nativeNames, int fIndex,
-                 boolean javaRasterizer)
+                 boolean javaRasterizer, boolean useFilePool)
         throws FontFormatException {
         super(platname, nativeNames);
         useJavaRasterizer = javaRasterizer;
         fontRank = Font2D.TTF_RANK;
         try {
-            verify();
+            verify(useFilePool);
             init(fIndex);
+            if (!useFilePool) {
+               close();
+            }
         } catch (Throwable t) {
             close();
             if (t instanceof FontFormatException) {
@@ -280,6 +290,10 @@
     }
 
 
+    private synchronized FileChannel open() throws FontFormatException {
+        return open(true);
+     }
+
     /* This is intended to be called, and the returned value used,
      * from within a block synchronized on this font object.
      * ie the channel returned may be nulled out at any time by "close()"
@@ -287,7 +301,8 @@
      * Deadlock warning: FontManager.addToPool(..) acquires a global lock,
      * which means nested locks may be in effect.
      */
-    private synchronized FileChannel open() throws FontFormatException {
+    private synchronized FileChannel open(boolean usePool)
+                                     throws FontFormatException {
         if (disposerRecord.channel == null) {
             if (FontUtilities.isLogging()) {
                 FontUtilities.getLogger().info("open TTF: " + platName);
@@ -306,9 +321,11 @@
                 });
                 disposerRecord.channel = raf.getChannel();
                 fileSize = (int)disposerRecord.channel.size();
-                FontManager fm = FontManagerFactory.getInstance();
-                if (fm instanceof SunFontManager) {
-                    ((SunFontManager) fm).addToPool(this);
+                if (usePool) {
+                    FontManager fm = FontManagerFactory.getInstance();
+                    if (fm instanceof SunFontManager) {
+                        ((SunFontManager) fm).addToPool(this);
+                    }
                 }
             } catch (NullPointerException e) {
                 close();
@@ -492,8 +509,8 @@
         }
     }
 
-    private void verify() throws FontFormatException {
-        open();
+    private void verify(boolean usePool) throws FontFormatException {
+        open(usePool);
     }
 
     /* sizes, in bytes, of TT/TTC header records */
--- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/ArrayCache.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/ArrayCache.java	Wed Jul 05 21:10:50 2017 +0200
@@ -166,18 +166,31 @@
      * @return new array size
      */
     public static int getNewSize(final int curSize, final int needSize) {
+        // check if needSize is negative or integer overflow:
+        if (needSize < 0) {
+            // hard overflow failure - we can't even accommodate
+            // new items without overflowing
+            throw new ArrayIndexOutOfBoundsException(
+                          "array exceeds maximum capacity !");
+        }
+        assert curSize >= 0;
         final int initial = (curSize & MASK_CLR_1);
         int size;
         if (initial > THRESHOLD_ARRAY_SIZE) {
             size = initial + (initial >> 1); // x(3/2)
         } else {
-            size = (initial) << 1; // x2
+            size = (initial << 1); // x2
         }
         // ensure the new size is >= needed size:
         if (size < needSize) {
-            // align to 4096:
+            // align to 4096 (may overflow):
             size = ((needSize >> 12) + 1) << 12;
         }
+        // check integer overflow:
+        if (size < 0) {
+            // resize to maximum capacity:
+            size = Integer.MAX_VALUE;
+        }
         return size;
     }
 
@@ -188,26 +201,29 @@
      * @return new array size
      */
     public static long getNewLargeSize(final long curSize, final long needSize) {
+        // check if needSize is negative or integer overflow:
+        if ((needSize >> 31L) != 0L) {
+            // hard overflow failure - we can't even accommodate
+            // new items without overflowing
+            throw new ArrayIndexOutOfBoundsException(
+                          "array exceeds maximum capacity !");
+        }
+        assert curSize >= 0L;
         long size;
         if (curSize > THRESHOLD_HUGE_ARRAY_SIZE) {
             size = curSize + (curSize >> 2L); // x(5/4)
         } else  if (curSize > THRESHOLD_LARGE_ARRAY_SIZE) {
             size = curSize + (curSize >> 1L); // x(3/2)
         } else {
-            size = curSize << 1L; // x2
+            size = (curSize << 1L); // x2
         }
         // ensure the new size is >= needed size:
         if (size < needSize) {
             // align to 4096:
-            size = ((needSize >> 12) + 1) << 12;
+            size = ((needSize >> 12L) + 1L) << 12L;
         }
-        if (size >= Integer.MAX_VALUE) {
-            if (curSize >= Integer.MAX_VALUE) {
-                // hard overflow failure - we can't even accommodate
-                // new items without overflowing
-                throw new ArrayIndexOutOfBoundsException(
-                              "array exceeds maximum capacity !");
-            }
+        // check integer overflow:
+        if (size > Integer.MAX_VALUE) {
             // resize to maximum capacity:
             size = Integer.MAX_VALUE;
         }
--- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/ByteArrayCache.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/ByteArrayCache.java	Wed Jul 05 21:10:50 2017 +0200
@@ -74,7 +74,7 @@
     void putDirtyArray(final byte[] array, final int length) {
         if (length != arraySize) {
             if (doChecks) {
-                System.out.println("ArrayCache: bad length = " + length);
+                MarlinUtils.logInfo("ArrayCache: bad length = " + length);
             }
             return;
         }
@@ -98,7 +98,7 @@
     {
         if (length != arraySize) {
             if (doChecks) {
-                System.out.println("ArrayCache: bad length = " + length);
+                MarlinUtils.logInfo("ArrayCache: bad length = " + length);
             }
             return;
         }
--- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/FloatArrayCache.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/FloatArrayCache.java	Wed Jul 05 21:10:50 2017 +0200
@@ -75,7 +75,7 @@
     void putDirtyArray(final float[] array, final int length) {
         if (length != arraySize) {
             if (doChecks) {
-                System.out.println("ArrayCache: bad length = " + length);
+                MarlinUtils.logInfo("ArrayCache: bad length = " + length);
             }
             return;
         }
@@ -99,7 +99,7 @@
     {
         if (length != arraySize) {
             if (doChecks) {
-                System.out.println("ArrayCache: bad length = " + length);
+                MarlinUtils.logInfo("ArrayCache: bad length = " + length);
             }
             return;
         }
--- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/FloatMath.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/FloatMath.java	Wed Jul 05 21:10:50 2017 +0200
@@ -24,8 +24,8 @@
  */
 package sun.java2d.marlin;
 
-import sun.misc.DoubleConsts;
-import sun.misc.FloatConsts;
+import jdk.internal.math.DoubleConsts;
+import jdk.internal.math.FloatConsts;
 
 /**
  * Faster Math ceil / floor routines derived from StrictMath
--- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/IntArrayCache.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/IntArrayCache.java	Wed Jul 05 21:10:50 2017 +0200
@@ -74,7 +74,7 @@
     void putDirtyArray(final int[] array, final int length) {
         if (length != arraySize) {
             if (doChecks) {
-                System.out.println("ArrayCache: bad length = " + length);
+                MarlinUtils.logInfo("ArrayCache: bad length = " + length);
             }
             return;
         }
@@ -98,7 +98,7 @@
     {
         if (length != arraySize) {
             if (doChecks) {
-                System.out.println("ArrayCache: bad length = " + length);
+                MarlinUtils.logInfo("ArrayCache: bad length = " + length);
             }
             return;
         }
--- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinConst.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinConst.java	Wed Jul 05 21:10:50 2017 +0200
@@ -30,8 +30,8 @@
  */
 interface MarlinConst {
     // enable Logs (logger or stdout)
-    static final boolean enableLogs = false;
-    // enable Logger
+    static final boolean enableLogs = MarlinProperties.isLoggingEnabled();
+    // use Logger instead of stdout
     static final boolean useLogger = enableLogs && MarlinProperties.isUseLogger();
 
     // log new RendererContext
@@ -47,9 +47,10 @@
     static final boolean doStats = enableLogs && MarlinProperties.isDoStats();
     // do monitors
     // disabled to reduce byte-code size a bit...
-    static final boolean doMonitors = enableLogs && false; // MarlinProperties.isDoMonitors();
+    static final boolean doMonitors = false;
+//    static final boolean doMonitors = enableLogs && MarlinProperties.isDoMonitors();
     // do checks
-    static final boolean doChecks = false; // MarlinProperties.isDoChecks();
+    static final boolean doChecks = enableLogs && MarlinProperties.isDoChecks();
 
     // do AA range checks: disable when algorithm / code is stable
     static final boolean DO_AA_RANGE_CHECK = false;
--- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinProperties.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinProperties.java	Wed Jul 05 21:10:50 2017 +0200
@@ -136,6 +136,10 @@
 
     // logging parameters
 
+    public static boolean isLoggingEnabled() {
+        return getBoolean("sun.java2d.renderer.log", "false");
+    }
+
     public static boolean isUseLogger() {
         return getBoolean("sun.java2d.renderer.useLogger", "false");
     }
--- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinUtils.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinUtils.java	Wed Jul 05 21:10:50 2017 +0200
@@ -27,12 +27,12 @@
 
 
 public final class MarlinUtils {
-    // TODO: use sun.util.logging.PlatformLogger once in JDK9
-    private static final java.util.logging.Logger log;
+    // Marlin logger
+    private static final sun.util.logging.PlatformLogger log;
 
     static {
         if (MarlinConst.useLogger) {
-            log = java.util.logging.Logger.getLogger("sun.java2d.marlin");
+            log = sun.util.logging.PlatformLogger.getLogger("sun.java2d.marlin");
         } else {
             log = null;
         }
@@ -53,25 +53,11 @@
 
     public static void logException(final String msg, final Throwable th) {
         if (MarlinConst.useLogger) {
-//            log.warning(msg, th);
-            log.log(java.util.logging.Level.WARNING, msg, th);
+            log.warning(msg, th);
         } else if (MarlinConst.enableLogs) {
             System.out.print("WARNING: ");
             System.out.println(msg);
             th.printStackTrace(System.err);
         }
     }
-
-    // Returns the caller's class and method's name; best effort
-    // if cannot infer, return the logger's name.
-    static String getCallerInfo(String className) {
-        String sourceClassName = null;
-        String sourceMethodName = null;
-
-        if (sourceClassName != null) {
-            return sourceClassName + " " + sourceMethodName;
-        } else {
-            return "unknown";
-        }
-    }
 }
--- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Renderer.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Renderer.java	Wed Jul 05 21:10:50 2017 +0200
@@ -629,6 +629,13 @@
         }
 
         if (edgeMinY != Float.POSITIVE_INFINITY) {
+            // if context is maked as DIRTY:
+            if (rdrCtx.dirty) {
+                // may happen if an exception if thrown in the pipeline processing:
+                // clear completely buckets arrays:
+                buckets_minY = 0;
+                buckets_maxY = boundsMaxY - boundsMinY;
+            }
             // clear used part
             if (edgeBuckets == edgeBuckets_initial) {
                 // fill only used part
--- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/RendererContext.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/RendererContext.java	Wed Jul 05 21:10:50 2017 +0200
@@ -31,7 +31,6 @@
 import java.util.concurrent.atomic.AtomicInteger;
 import static sun.java2d.marlin.ArrayCache.*;
 import sun.java2d.marlin.MarlinRenderingEngine.NormalizingPathIterator;
-import static sun.java2d.marlin.MarlinUtils.getCallerInfo;
 import static sun.java2d.marlin.MarlinUtils.logInfo;
 
 /**
@@ -39,7 +38,6 @@
  */
 final class RendererContext implements MarlinConst {
 
-    private static final String className = RendererContext.class.getName();
     // RendererContext creation counter
     private static final AtomicInteger contextCount = new AtomicInteger(1);
     // RendererContext statistics
@@ -214,8 +212,7 @@
         }
 
         if (doLogOverSize) {
-            logInfo("getDirtyByteArray[oversize]: length=\t" + length
-                    + "\tfrom=\t" + getCallerInfo(className));
+            logInfo("getDirtyByteArray[oversize]: length=\t" + length);
         }
 
         return new byte[length];
@@ -254,7 +251,7 @@
         if (doLogWidenArray) {
             logInfo("widenDirtyByteArray[" + res.length + "]: usedSize=\t"
                     + usedSize + "\tlength=\t" + length + "\tneeded length=\t"
-                    + needSize + "\tfrom=\t" + getCallerInfo(className));
+                    + needSize);
         }
         return res;
     }
@@ -275,8 +272,7 @@
         }
 
         if (doLogOverSize) {
-            logInfo("getIntArray[oversize]: length=\t" + length + "\tfrom=\t"
-                    + getCallerInfo(className));
+            logInfo("getIntArray[oversize]: length=\t" + length);
         }
 
         return new int[length];
@@ -306,7 +302,7 @@
         if (doLogWidenArray) {
             logInfo("widenIntArray[" + res.length + "]: usedSize=\t"
                     + usedSize + "\tlength=\t" + length + "\tneeded length=\t"
-                    + needSize + "\tfrom=\t" + getCallerInfo(className));
+                    + needSize);
         }
         return res;
     }
@@ -338,8 +334,7 @@
         }
 
         if (doLogOverSize) {
-            logInfo("getDirtyIntArray[oversize]: length=\t" + length
-                    + "\tfrom=\t" + getCallerInfo(className));
+            logInfo("getDirtyIntArray[oversize]: length=\t" + length);
         }
 
         return new int[length];
@@ -369,7 +364,7 @@
         if (doLogWidenArray) {
             logInfo("widenDirtyIntArray[" + res.length + "]: usedSize=\t"
                     + usedSize + "\tlength=\t" + length + "\tneeded length=\t"
-                    + needSize + "\tfrom=\t" + getCallerInfo(className));
+                    + needSize);
         }
         return res;
     }
@@ -399,8 +394,7 @@
         }
 
         if (doLogOverSize) {
-            logInfo("getDirtyFloatArray[oversize]: length=\t" + length
-                    + "\tfrom=\t" + getCallerInfo(className));
+            logInfo("getDirtyFloatArray[oversize]: length=\t" + length);
         }
 
         return new float[length];
@@ -430,7 +424,7 @@
         if (doLogWidenArray) {
             logInfo("widenDirtyFloatArray[" + res.length + "]: usedSize=\t"
                     + usedSize + "\tlength=\t" + length + "\tneeded length=\t"
-                    + needSize + "\tfrom=\t" + getCallerInfo(className));
+                    + needSize);
         }
         return res;
     }
--- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/RendererStats.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/RendererStats.java	Wed Jul 05 21:10:50 2017 +0200
@@ -25,6 +25,8 @@
 
 package sun.java2d.marlin;
 
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.util.Timer;
 import java.util.TimerTask;
 import java.util.concurrent.ConcurrentLinkedQueue;
@@ -32,6 +34,7 @@
 import sun.java2d.marlin.stats.Histogram;
 import sun.java2d.marlin.stats.Monitor;
 import sun.java2d.marlin.stats.StatLong;
+import sun.awt.util.ThreadGroupUtils;
 
 /**
  * This class gathers global rendering statistics for debugging purposes only
@@ -237,22 +240,33 @@
     private RendererStats() {
         super();
 
-        Runtime.getRuntime().addShutdownHook(new Thread() {
-            @Override
-            public void run() {
-                dump();
-            }
-        });
+        AccessController.doPrivileged(
+            (PrivilegedAction<Void>) () -> {
+                final Thread hook = new Thread(
+                    ThreadGroupUtils.getRootThreadGroup(),
+                    new Runnable() {
+                        @Override
+                        public void run() {
+                            dump();
+                        }
+                    },
+                    "MarlinStatsHook"
+                );
+                hook.setContextClassLoader(null);
+                Runtime.getRuntime().addShutdownHook(hook);
 
-        if (useDumpThread) {
-            final Timer statTimer = new Timer("RendererStats");
-            statTimer.scheduleAtFixedRate(new TimerTask() {
-                @Override
-                public void run() {
-                    dump();
+                if (useDumpThread) {
+                    final Timer statTimer = new Timer("RendererStats");
+                    statTimer.scheduleAtFixedRate(new TimerTask() {
+                        @Override
+                        public void run() {
+                            dump();
+                        }
+                    }, statDump, statDump);
                 }
-            }, statDump, statDump);
-        }
+                return null;
+            }
+        );
     }
 
     void dump() {
--- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Stroker.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Stroker.java	Wed Jul 05 21:10:50 2017 +0200
@@ -1265,14 +1265,15 @@
         }
 
         private void ensureSpace(final int n) {
-            if (end + n > curves.length) {
+            // use substraction to avoid integer overflow:
+            if (curves.length - end < n) {
                 if (doStats) {
                     RendererContext.stats.stat_array_stroker_polystack_curves
                         .add(end + n);
                 }
                 curves = rdrCtx.widenDirtyFloatArray(curves, end, end + n);
             }
-            if (numCurves + 1 > curveTypes.length) {
+            if (curveTypes.length <= numCurves) {
                 if (doStats) {
                     RendererContext.stats.stat_array_stroker_polystack_curveTypes
                         .add(numCurves + 1);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.desktop/share/classes/sun/swing/text/UndoableEditLockSupport.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package sun.swing.text;
+
+import javax.swing.undo.UndoableEdit;
+
+/**
+ * UndoableEdit support for undo/redo actions synchronization
+ * @since 1.9
+ */
+public interface UndoableEditLockSupport extends UndoableEdit {
+    /**
+     * lock the UndoableEdit for threadsafe undo/redo
+     */
+    void lockEdit();
+
+    /**
+     * unlock the UndoableEdit
+     */
+    void unlockEdit();
+}
--- a/jdk/src/java.desktop/share/native/libfontmanager/FontInstanceAdapter.cpp	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/native/libfontmanager/FontInstanceAdapter.cpp	Wed Jul 05 21:10:50 2017 +0200
@@ -67,12 +67,6 @@
 };
 
 
-const void *FontInstanceAdapter::getFontTable(LETag tableTag) const
-{
-  size_t ignored = 0;
-  return getFontTable(tableTag, ignored);
-}
-
 static const LETag cacheMap[LAYOUTCACHE_ENTRIES] = {
   GPOS_TAG, GDEF_TAG, GSUB_TAG, MORT_TAG, MORX_TAG, KERN_TAG
 };
--- a/jdk/src/java.desktop/share/native/libfontmanager/FontInstanceAdapter.h	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/native/libfontmanager/FontInstanceAdapter.h	Wed Jul 05 21:10:50 2017 +0200
@@ -85,7 +85,6 @@
 
     // tables are cached with the native font scaler data
     // only supports gsub, gpos, gdef, mort tables at present
-    virtual const void *getFontTable(LETag tableTag) const;
     virtual const void *getFontTable(LETag tableTag, size_t &len) const;
 
     virtual void *getKernPairs() const {
--- a/jdk/src/java.desktop/share/native/libfontmanager/HBShaper.c	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/native/libfontmanager/HBShaper.c	Wed Jul 05 21:10:50 2017 +0200
@@ -80,15 +80,18 @@
     float scale = 1.0f/64.0f;
     unsigned int* glyphs;
     float* positions;
+    int initialCount, glyphArrayLen, posArrayLen, maxGlyphs, storeadv;
+    unsigned int* indices;
+    jarray glyphArray, posArray, inxArray;
 
     if (!init_JNI_IDs(env)) {
         return 0;
     }
 
-    int initialCount = (*env)->GetIntField(env, gvdata, gvdCountFID);
-    jarray glyphArray =
+    initialCount = (*env)->GetIntField(env, gvdata, gvdCountFID);
+    glyphArray =
        (jarray)(*env)->GetObjectField(env, gvdata, gvdGlyphsFID);
-    jarray posArray =
+    posArray =
         (jarray)(*env)->GetObjectField(env, gvdata, gvdPositionsFID);
 
     if (glyphArray == NULL || posArray == NULL)
@@ -101,9 +104,9 @@
     // and re-invokes layout. I suppose this is expected to be rare
     // because at least in a single threaded case there should be
     // re-use of the same container, but it is a little wasteful/distateful.
-    int glyphArrayLen = (*env)->GetArrayLength(env, glyphArray);
-    int posArrayLen = (*env)->GetArrayLength(env, posArray);
-    int maxGlyphs = glyphCount + initialCount;
+    glyphArrayLen = (*env)->GetArrayLength(env, glyphArray);
+    posArrayLen = (*env)->GetArrayLength(env, posArray);
+    maxGlyphs = glyphCount + initialCount;
     if ((maxGlyphs >  glyphArrayLen) ||
         (maxGlyphs * 2 + 2 >  posArrayLen))
     {
@@ -125,7 +128,7 @@
         x += glyphPos[i].x_advance * scale;
         y += glyphPos[i].y_advance * scale;
     }
-    int storeadv = initialCount+glyphCount;
+    storeadv = initialCount+glyphCount;
     // The final slot in the positions array is important
     // because when the GlyphVector is created from this
     // data it determines the overall advance of the glyphvector
@@ -138,11 +141,10 @@
     (*env)->ReleasePrimitiveArrayCritical(env, glyphArray, glyphs, 0);
     (*env)->ReleasePrimitiveArrayCritical(env, posArray, positions, 0);
     putFloat(env, startPt,positions[(storeadv*2)],positions[(storeadv*2)+1] );
-    jarray inxArray =
+    inxArray =
         (jarray)(*env)->GetObjectField(env, gvdata, gvdIndicesFID);
-    unsigned int* indices =
+    indices =
         (unsigned int*)(*env)->GetPrimitiveArrayCritical(env, inxArray, NULL);
-    int prevCluster = -1;
     for (i = 0; i < glyphCount; i++) {
         int cluster = glyphInfo[i].cluster;
         if (direction == HB_DIRECTION_LTR) {
--- a/jdk/src/java.desktop/share/native/libfontmanager/freetypeScaler.c	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/native/libfontmanager/freetypeScaler.c	Wed Jul 05 21:10:50 2017 +0200
@@ -258,7 +258,7 @@
                                               scalerInfo->fontData,
                                               scalerInfo->fontDataLength);
             if (bBuffer != NULL) {
-                (*env)->CallObjectMethod(env, font2D,
+                (*env)->CallVoidMethod(env, font2D,
                                    sunFontIDs.readFileMID, bBuffer);
 
                 error = FT_New_Memory_Face(scalerInfo->library,
--- a/jdk/src/java.desktop/share/native/libfontmanager/layout/LEFontInstance.h	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/native/libfontmanager/layout/LEFontInstance.h	Wed Jul 05 21:10:50 2017 +0200
@@ -181,28 +181,6 @@
      *
      * Subclasses which represent composite fonts should always return <code>NULL</code>.
      *
-     * Note that implementing this function does not allow for range checking.
-     * Subclasses that desire the safety of range checking must implement the
-     * variation which has a length parameter.
-     *
-     * @param tableTag - the four byte table tag. (e.g. 'cmap')
-     *
-     * @return the address of the table in memory, or <code>NULL</code>
-     *         if the table doesn't exist.
-     *
-     * @stable ICU 2.8
-     */
-    virtual const void *getFontTable(LETag tableTag) const = 0;
-
-    /**
-     * This method reads a table from the font. Note that in general,
-     * it only makes sense to call this method on an <code>LEFontInstance</code>
-     * which represents a physical font - i.e. one which has been returned by
-     * <code>getSubFont()</code>. This is because each subfont in a composite font
-     * will have different tables, and there's no way to know which subfont to access.
-     *
-     * Subclasses which represent composite fonts should always return <code>NULL</code>.
-     *
      * This version sets a length, for range checking.
      * Note that range checking can only be accomplished if this function is
      * implemented in subclasses.
@@ -213,7 +191,7 @@
      *         if the table doesn't exist.
      * @internal
      */
-    virtual const void* getFontTable(LETag tableTag, size_t &length) const { length=-1; return getFontTable(tableTag); }  /* -1 = unknown length */
+    virtual const void* getFontTable(LETag tableTag, size_t &length) const = 0;
 
     virtual void *getKernPairs() const = 0;
     virtual void  setKernPairs(void *pairs) const = 0;
--- a/jdk/src/java.desktop/share/native/libjavajpeg/imageioJPEG.c	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/share/native/libjavajpeg/imageioJPEG.c	Wed Jul 05 21:10:50 2017 +0200
@@ -1610,6 +1610,7 @@
     int ret;
     int h_samp0, h_samp1, h_samp2;
     int v_samp0, v_samp1, v_samp2;
+    int cid0, cid1, cid2;
     jboolean retval = JNI_FALSE;
     imageIODataPtr data = (imageIODataPtr)jlong_to_ptr(ptr);
     j_decompress_ptr cinfo;
@@ -1711,17 +1712,15 @@
                 }
             } else if (!cinfo->saw_JFIF_marker && !IS_EXIF(cinfo)) {
                 /*
-                 * IJG assumes all unidentified 3-channels are YCbCr.
-                 * We assume that only if the second two channels are
-                 * subsampled (either horizontally or vertically).  If not,
-                 * we assume RGB.
-                 *
-                 * 4776576: Some digital cameras output YCbCr JPEG images
-                 * that do not contain a JFIF APP0 marker but are only
-                 * vertically subsampled (no horizontal subsampling).
-                 * We should only assume this is RGB data if the subsampling
-                 * factors for the second two channels are the same as the
-                 * first (check both horizontal and vertical factors).
+                 * In the absence of certain markers, IJG has interpreted
+                 * component id's of [1,2,3] as meaning YCbCr.We follow that
+                 * interpretation, which is additionally described in the Image
+                 * I/O JPEG metadata spec.If that condition is not met here the
+                 * next step will be to examine the subsampling factors, if
+                 * there is any difference in subsampling factors we also assume
+                 * YCbCr, only if both horizontal and vertical subsampling
+                 * is same we assume JPEG color space as RGB.
+                 * This is also described in the Image I/O JPEG metadata spec.
                  */
                 h_samp0 = cinfo->comp_info[0].h_samp_factor;
                 h_samp1 = cinfo->comp_info[1].h_samp_factor;
@@ -1731,8 +1730,13 @@
                 v_samp1 = cinfo->comp_info[1].v_samp_factor;
                 v_samp2 = cinfo->comp_info[2].v_samp_factor;
 
-                if ((h_samp1 == h_samp0) && (h_samp2 == h_samp0) &&
-                    (v_samp1 == v_samp0) && (v_samp2 == v_samp0))
+                cid0 = cinfo->comp_info[0].component_id;
+                cid1 = cinfo->comp_info[1].component_id;
+                cid2 = cinfo->comp_info[2].component_id;
+
+                if ((!(cid0 == 1 && cid1 == 2 && cid2 == 3)) &&
+                    ((h_samp1 == h_samp0) && (h_samp2 == h_samp0) &&
+                    (v_samp1 == v_samp0) && (v_samp2 == v_samp0)))
                 {
                     cinfo->jpeg_color_space = JCS_RGB;
                     /* output is already RGB, so it stays the same */
--- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTrayIconPeer.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTrayIconPeer.java	Wed Jul 05 21:10:50 2017 +0200
@@ -413,6 +413,7 @@
     void addListeners() {
         canvas.addMouseListener(eventProxy);
         canvas.addMouseMotionListener(eventProxy);
+        eframe.addMouseListener(eventProxy);
     }
 
     long getWindow() {
--- a/jdk/src/java.desktop/unix/classes/sun/print/IPPPrintService.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/unix/classes/sun/print/IPPPrintService.java	Wed Jul 05 21:10:50 2017 +0200
@@ -926,7 +926,10 @@
                 return copyflavors;
             }
         }
-        return null;
+        DocFlavor[] flavor = new DocFlavor[2];
+        flavor[0] = DocFlavor.SERVICE_FORMATTED.PAGEABLE;
+        flavor[1] = DocFlavor.SERVICE_FORMATTED.PRINTABLE;
+        return flavor;
     }
 
 
--- a/jdk/src/java.desktop/unix/native/common/java2d/x11/X11SurfaceData.c	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/unix/native/common/java2d/x11/X11SurfaceData.c	Wed Jul 05 21:10:50 2017 +0200
@@ -438,6 +438,15 @@
         xsdo->drawable = drawable;
         xsdo->isPixmap = JNI_FALSE;
     } else {
+        /*
+         * width , height must be nonzero otherwise XCreatePixmap
+         * generates BadValue in error_handler
+         */
+        if (width <= 0 || height <= 0) {
+            JNU_ThrowOutOfMemoryError(env,
+                                  "Can't create offscreen surface");
+            return JNI_FALSE;
+        }
         xsdo->isPixmap = JNI_TRUE;
         /* REMIND: workaround for bug 4420220 on pgx32 boards:
            don't use DGA with pixmaps unless USE_DGA_PIXMAPS is set.
--- a/jdk/src/java.desktop/windows/classes/sun/awt/Win32FontManager.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/java.desktop/windows/classes/sun/awt/Win32FontManager.java	Wed Jul 05 21:10:50 2017 +0200
@@ -61,7 +61,7 @@
                              * enumerate (allow direct use) of EUDC fonts.
                              */
                             eudcFont = new TrueTypeFont(eudcFile, null, 0,
-                                                        true);
+                                                        true, false);
                         } catch (FontFormatException e) {
                         }
                     }
--- a/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AWTEventMonitor.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AWTEventMonitor.java	Wed Jul 05 21:10:50 2017 +0200
@@ -48,8 +48,6 @@
 @jdk.Exported
 public class AWTEventMonitor {
 
-    static private boolean runningOnJDK1_4 = false;
-
     /**
      * The current component with keyboard focus.
      *
@@ -638,15 +636,9 @@
          * @see AWTEventMonitor
          */
         public AWTEventsListener() {
-            String version = System.getProperty("java.version");
-            if (version != null) {
-                runningOnJDK1_4 = (version.compareTo("1.4") >= 0);
-            }
             initializeIntrospection();
             installListeners();
-            if (runningOnJDK1_4) {
-                MenuSelectionManager.defaultManager().addChangeListener(this);
-            }
+            MenuSelectionManager.defaultManager().addChangeListener(this);
             EventQueueMonitor.addTopLevelWindowListener(this);
         }
 
@@ -848,15 +840,7 @@
             case EventID.FOCUS:
                 c.removeFocusListener(this);
                 c.addFocusListener(this);
-
-                if (runningOnJDK1_4) {
-                    processFocusGained();
-
-                } else {        // not runningOnJDK1_4
-                    if ((c != componentWithFocus_private) && c.hasFocus()) {
-                        componentWithFocus_private = c;
-                    }
-                }
+                processFocusGained();
                 break;
 
             case EventID.ITEM:
--- a/jdk/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java	Wed Jul 05 21:10:50 2017 +0200
@@ -140,10 +140,6 @@
         // initialize AccessibleRole map
         initAccessibleRoleMap();
 
-        // determine which version of the JDK is running
-        String version = getJavaVersionProperty();
-        debugString("JDK version = "+version);
-
         // initialize the methods that map HWNDs and Java top-level
         // windows
         initHWNDcalls();
@@ -215,9 +211,7 @@
         } catch (Exception e) {}
 
     /*
-      Build the extendedVirtualNameSearchRoles array list.  I chose this method
-      because some of the Accessible Roles that need to be added to it are not
-      available in all versions of the J2SE that we want to support.
+      Build the extendedVirtualNameSearchRoles array list.
     */
     extendedVirtualNameSearchRoles.add (AccessibleRole.COMBO_BOX);
     try {
@@ -5919,7 +5913,7 @@
      */
     AccessibleRole.UNKNOWN,
 
-    // These roles are only available in JDK 1.4
+    // These roles are available since JDK 1.4
 
     /**
      * A STATUS_BAR is an simple component that can contain
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.zipfs/share/classes/jdk/nio/zipfs/JarFileSystem.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nio.zipfs;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+
+/**
+ * Adds aliasing to ZipFileSystem to support multi-release jar files.  An alias map
+ * is created by {@link JarFileSystem#createVersionedLinks(int)}.  The map is then
+ * consulted when an entry is looked up in {@link JarFileSystem#getEntry(byte[])}
+ * to determine if the entry has a corresponding versioned entry.  If so, the
+ * versioned entry is returned.
+ *
+ * @author Steve Drach
+ */
+
+class JarFileSystem extends ZipFileSystem {
+    private Function<byte[],byte[]> lookup;
+
+    @Override
+    Entry getEntry(byte[] path) throws IOException {
+        // check for an alias to a versioned entry
+        byte[] versionedPath = lookup.apply(path);
+        return versionedPath == null ? super.getEntry(path) : super.getEntry(versionedPath);
+    }
+
+    JarFileSystem(ZipFileSystemProvider provider, Path zfpath, Map<String,?> env)
+            throws IOException {
+        super(provider, zfpath, env);
+        lookup = path -> path;  // lookup needs to be set before isMultiReleaseJar is called
+                                // because it eventually calls getEntry
+        if (isMultiReleaseJar()) {
+            int version;
+            Object o = env.get("multi-release");
+            if (o instanceof String) {
+                String s = (String)o;
+                if (s.equals("runtime")) {
+                    version = sun.misc.Version.jdkMajorVersion();  // fixme waiting for jdk.util.Version
+                } else {
+                    version = Integer.parseInt(s);
+                }
+            } else if (o instanceof Integer) {
+                version = (Integer)o;
+            } else if (false /*o instanceof Version*/) {  // fixme waiting for jdk.util.Version
+//                version = ((Version)o).major();
+            } else {
+                throw new IllegalArgumentException("env parameter must be String, Integer, "
+                        + "or Version");
+            }
+            lookup = createVersionedLinks(version < 0 ? 0 : version);
+            setReadOnly();
+        }
+    }
+
+    private boolean isMultiReleaseJar() {
+        try (InputStream is = newInputStream(getBytes("META-INF/MANIFEST.MF"))) {
+            return (new Manifest(is)).getMainAttributes()
+                    .containsKey(new Attributes.Name("Multi-Release"));
+            // fixme change line above after JarFile integration to contain Attributes.Name.MULTI_RELEASE
+        } catch (IOException x) {
+            return false;
+        }
+    }
+
+    /**
+     * create a map of aliases for versioned entries, for example:
+     *   version/PackagePrivate.class -> META-INF/versions/9/version/PackagePrivate.class
+     *   version/PackagePrivate.java -> META-INF/versions/9/version/PackagePrivate.java
+     *   version/Version.class -> META-INF/versions/10/version/Version.class
+     *   version/Version.java -> META-INF/versions/10/version/Version.java
+     *
+     * then wrap the map in a function that getEntry can use to override root
+     * entry lookup for entries that have corresponding versioned entries
+     */
+    private Function<byte[],byte[]> createVersionedLinks(int version) {
+        HashMap<IndexNode,byte[]> aliasMap = new HashMap<>();
+        getVersionMap(version, getInode(getBytes("META-INF/versions"))).values()
+                .forEach(versionNode -> {   // for each META-INF/versions/{n} directory
+                    // put all the leaf inodes, i.e. entries, into the alias map
+                    // possibly shadowing lower versioned entries
+                    walk(versionNode, entryNode -> {
+                        byte[] rootName = getRootName(versionNode, entryNode);
+                        if (rootName != null) {
+                            IndexNode rootNode = getInode(rootName);
+                            if (rootNode == null) { // no matching root node, make a virtual one
+                                rootNode = IndexNode.keyOf(rootName);
+                            }
+                            aliasMap.put(rootNode, entryNode.name);
+                        }
+                    });
+                });
+        return path -> aliasMap.get(IndexNode.keyOf(path));
+    }
+
+    /**
+     * create a sorted version map of version -> inode, for inodes <= max version
+     *   9 -> META-INF/versions/9
+     *  10 -> META-INF/versions/10
+     */
+    private TreeMap<Integer, IndexNode> getVersionMap(int version, IndexNode metaInfVersions) {
+        TreeMap<Integer,IndexNode> map = new TreeMap<>();
+        IndexNode child = metaInfVersions.child;
+        while (child != null) {
+            Integer key = getVersion(child.name, metaInfVersions.name.length);
+            if (key != null && key <= version) {
+                map.put(key, child);
+            }
+            child = child.sibling;
+        }
+        return map;
+    }
+
+    /**
+     * extract the integer version number -- META-INF/versions/9 returns 9
+     */
+    private Integer getVersion(byte[] name, int offset) {
+        try {
+            return Integer.parseInt(getString(Arrays.copyOfRange(name, offset, name.length-1)));
+        } catch (NumberFormatException x) {
+            // ignore this even though it might indicate issues with the JAR structure
+            return null;
+        }
+    }
+
+    /**
+     * walk the IndexNode tree processing all leaf nodes
+     */
+    private void walk(IndexNode inode, Consumer<IndexNode> process) {
+        if (inode == null) return;
+        if (inode.isDir()) {
+            walk(inode.child, process);
+        } else {
+            process.accept(inode);
+            walk(inode.sibling, process);
+        }
+    }
+
+    /**
+     * extract the root name from a versioned entry name
+     *   given inode for META-INF/versions/9/foo/bar.class
+     *   and prefix META-INF/versions/9/
+     *   returns foo/bar.class
+     */
+    private byte[] getRootName(IndexNode prefix, IndexNode inode) {
+        int offset = prefix.name.length;
+        byte[] fullName = inode.name;
+        return Arrays.copyOfRange(fullName, offset, fullName.length);
+    }
+}
--- a/jdk/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java	Wed Jul 05 21:10:50 2017 +0200
@@ -155,6 +155,10 @@
             throw new ReadOnlyFileSystemException();
     }
 
+    void setReadOnly() {
+        this.readOnly = true;
+    }
+
     @Override
     public Iterable<Path> getRootDirectories() {
         ArrayList<Path> pathArr = new ArrayList<>();
@@ -320,7 +324,7 @@
         beginRead();
         try {
             ensureOpen();
-            e = getEntry0(path);
+            e = getEntry(path);
             if (e == null) {
                 IndexNode inode = getInode(path);
                 if (inode == null)
@@ -342,7 +346,7 @@
         beginWrite();
         try {
             ensureOpen();
-            Entry e = getEntry0(path);    // ensureOpen checked
+            Entry e = getEntry(path);    // ensureOpen checked
             if (e == null)
                 throw new NoSuchFileException(getString(path));
             if (e.type == Entry.CEN)
@@ -445,7 +449,7 @@
         beginWrite();
         try {
             ensureOpen();
-            Entry eSrc = getEntry0(src);  // ensureOpen checked
+            Entry eSrc = getEntry(src);  // ensureOpen checked
             if (eSrc == null)
                 throw new NoSuchFileException(getString(src));
             if (eSrc.isDir()) {    // spec says to create dst dir
@@ -460,7 +464,7 @@
                 else if (opt == COPY_ATTRIBUTES)
                     hasCopyAttrs = true;
             }
-            Entry eDst = getEntry0(dst);
+            Entry eDst = getEntry(dst);
             if (eDst != null) {
                 if (!hasReplace)
                     throw new FileAlreadyExistsException(getString(dst));
@@ -521,7 +525,7 @@
         beginRead();                 // only need a readlock, the "update()" will
         try {                        // try to obtain a writelock when the os is
             ensureOpen();            // being closed.
-            Entry e = getEntry0(path);
+            Entry e = getEntry(path);
             if (e != null) {
                 if (e.isDir() || hasCreateNew)
                     throw new FileAlreadyExistsException(getString(path));
@@ -550,7 +554,7 @@
         beginRead();
         try {
             ensureOpen();
-            Entry e = getEntry0(path);
+            Entry e = getEntry(path);
             if (e == null)
                 throw new NoSuchFileException(getString(path));
             if (e.isDir())
@@ -592,7 +596,7 @@
                     newOutputStream(path, options.toArray(new OpenOption[0])));
                 long leftover = 0;
                 if (options.contains(StandardOpenOption.APPEND)) {
-                    Entry e = getEntry0(path);
+                    Entry e = getEntry(path);
                     if (e != null && e.size >= 0)
                         leftover = e.size;
                 }
@@ -644,7 +648,7 @@
             beginRead();
             try {
                 ensureOpen();
-                Entry e = getEntry0(path);
+                Entry e = getEntry(path);
                 if (e == null || e.isDir())
                     throw new NoSuchFileException(getString(path));
                 final ReadableByteChannel rbc =
@@ -714,7 +718,7 @@
         beginRead();
         try {
             ensureOpen();
-            Entry e = getEntry0(path);
+            Entry e = getEntry(path);
             if (forWrite) {
                 checkWritable();
                 if (e == null) {
@@ -855,7 +859,7 @@
     private Path getTempPathForEntry(byte[] path) throws IOException {
         Path tmpPath = createTempFileInSameDirectoryAs(zfpath);
         if (path != null) {
-            Entry e = getEntry0(path);
+            Entry e = getEntry(path);
             if (e != null) {
                 try (InputStream is = newInputStream(path)) {
                     Files.copy(is, tmpPath, REPLACE_EXISTING);
@@ -939,7 +943,7 @@
 
     private long getDataPos(Entry e) throws IOException {
         if (e.locoff == -1) {
-            Entry e2 = getEntry0(e.name);
+            Entry e2 = getEntry(e.name);
             if (e2 == null)
                 throw new ZipException("invalid loc for entry <" + e.name + ">");
             e.locoff = e2.locoff;
@@ -1325,7 +1329,7 @@
         //System.out.printf("->sync(%s) done!%n", toString());
     }
 
-    private IndexNode getInode(byte[] path) {
+    IndexNode getInode(byte[] path) {
         if (path == null)
             throw new NullPointerException("path");
         IndexNode key = IndexNode.keyOf(path);
@@ -1340,7 +1344,7 @@
         return inode;
     }
 
-    private Entry getEntry0(byte[] path) throws IOException {
+    Entry getEntry(byte[] path) throws IOException {
         IndexNode inode = getInode(path);
         if (inode instanceof Entry)
             return (Entry)inode;
@@ -2096,7 +2100,7 @@
             pos += (LOCHDR + nlen + elen);
             if ((flag & FLAG_DATADESCR) != 0) {
                 // Data Descriptor
-                Entry e = zipfs.getEntry0(name);  // get the size/csize from cen
+                Entry e = zipfs.getEntry(name);  // get the size/csize from cen
                 if (e == null)
                     throw new ZipException("loc: name not found in cen");
                 size = e.size;
--- a/jdk/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystemProvider.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystemProvider.java	Wed Jul 05 21:10:50 2017 +0200
@@ -100,7 +100,11 @@
             }
             ZipFileSystem zipfs = null;
             try {
-                zipfs = new ZipFileSystem(this, path, env);
+                if (env.containsKey("multi-release")) {
+                    zipfs = new JarFileSystem(this, path, env);
+                } else {
+                    zipfs = new ZipFileSystem(this, path, env);
+                }
             } catch (ZipException ze) {
                 String pname = path.toString();
                 if (pname.endsWith(".zip") || pname.endsWith(".jar"))
@@ -124,8 +128,14 @@
             throw new UnsupportedOperationException();
         }
         ensureFile(path);
-        try {
-            return new ZipFileSystem(this, path, env);
+         try {
+             ZipFileSystem zipfs;
+             if (env.containsKey("multi-release")) {
+                 zipfs = new JarFileSystem(this, path, env);
+             } else {
+                 zipfs = new ZipFileSystem(this, path, env);
+             }
+            return zipfs;
         } catch (ZipException ze) {
             String pname = path.toString();
             if (pname.endsWith(".zip") || pname.endsWith(".jar"))
--- a/jdk/test/ProblemList.txt	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/test/ProblemList.txt	Wed Jul 05 21:10:50 2017 +0200
@@ -310,8 +310,6 @@
 
 # jdk_imageio
 
-javax/imageio/plugins/shared/WriteAfterAbort.java               generic-all
-
 ############################################################################
 
 # jdk_swing
--- a/jdk/test/java/awt/List/SetFontTest/SetFontTest.html	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/test/java/awt/List/SetFontTest/SetFontTest.html	Wed Jul 05 21:10:50 2017 +0200
@@ -38,6 +38,6 @@
 
 <p> See the dialog box (usually in upper left corner) for instructions</p>
 
-<APPLET CODE="SetFontTest.class" WIDTH=200 HEIGHT=200></APPLET>
+<APPLET CODE="SetFontTest.class" WIDTH=200 HEIGHT=220></APPLET>
 </body>
 </html>
--- a/jdk/test/java/awt/Mouse/MaximizedFrameTest/MaximizedFrameTest.html	Thu Dec 24 10:33:21 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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 6176814
-  @summary Metalworks frame maximizes after the move
-  @author Andrei.Dmitriev.Com area=Event
-  @run applet MaximizedFrameTest.html
-  -->
-<head>
-<title>  </title>
-</head>
-<body>
-
-<h1>bug 6176814<br>Bug ID:  6176814 </h1>
-
-<p> This is an AUTOMATIC test, simply wait for completion </p>
-
-<APPLET CODE="MaximizedFrameTest.class" WIDTH=200 HEIGHT=200></APPLET>
-</body>
-</html>
--- a/jdk/test/java/awt/Mouse/MaximizedFrameTest/MaximizedFrameTest.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/test/java/awt/Mouse/MaximizedFrameTest/MaximizedFrameTest.java	Wed Jul 05 21:10:50 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2015 Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,91 +22,149 @@
  */
 
 /*
-  test
-  @bug 6176814
-  @summary  Metalworks frame maximizes after the move
-  @author Andrei.Dmitriev area=Event
-  @run applet MaximizedFrameTest.html
-*/
+ @test
+ @bug 6176814 8132766
+ @summary Metalworks frame maximizes after the move
+ @run main MaximizedFrameTest
+ */
 
-import java.applet.Applet;
-import javax.swing.*;
-import java.awt.event.*;
-import java.awt.*;
+import java.awt.AWTException;
+import java.awt.Component;
+import java.awt.Point;
+import java.awt.Robot;
+import java.awt.event.InputEvent;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.swing.JFrame;
+import javax.swing.JLayeredPane;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.UnsupportedLookAndFeelException;
 
-public class MaximizedFrameTest extends Applet
-{
-    final int ITERATIONS_COUNT = 20;
-    Robot robot;
-    Point framePosition;
-    Point newFrameLocation;
-    JFrame  frame;
-    Rectangle gcBounds;
-    public static Object LOCK = new Object();
+public class MaximizedFrameTest {
+
+    final static int ITERATIONS_COUNT = 5;
+    private static JFrame frame;
+    private static Point tempMousePosition;
+    private static Component titleComponent;
 
-    public void init()
-    {
-        String[] instructions =
-        {
-            "This is an AUTOMATIC test",
-            "simply wait until it is done"
-        };
+    public void init() {
         JFrame.setDefaultLookAndFeelDecorated(true);
+
+        try {
+            UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
+        } catch (ClassNotFoundException | InstantiationException |
+                IllegalAccessException | UnsupportedLookAndFeelException ex) {
+            throw new RuntimeException("Test Failed. MetalLookAndFeel not set "
+                    + "for frame");
+        }
+
         frame = new JFrame("JFrame Maximization Test");
         frame.pack();
         frame.setSize(450, 260);
-    }//End  init()
+        frame.setVisible(true);
+    }
+
+    public void getTitleComponent() throws Exception {
+
+        SwingUtilities.invokeAndWait(new Runnable() {
+
+            @Override
+            public void run() {
+                JLayeredPane lPane = frame.getLayeredPane();
+                boolean titleFound = false;
+
+                for (int j = 0; j < lPane.getComponentsInLayer(
+                    JLayeredPane.FRAME_CONTENT_LAYER.intValue()).length; j++) {
+
+                    titleComponent = lPane.getComponentsInLayer(
+                    JLayeredPane.FRAME_CONTENT_LAYER.intValue())[j];
 
-    public void start ()
-    {
-        frame.setVisible(true);
-        validate();
-        JLayeredPane lPane = frame.getLayeredPane();
-        //        System.out.println("JFrame's LayeredPane " + lPane );
-        Component titleComponent = null;
-        boolean titleFound = false;
-        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;
+                    if (titleComponent.getClass().getName().equals(
+                        "javax.swing.plaf.metal.MetalTitlePane")) {
+
+                        titleFound = true;
+                        break;
+                    }
+                }
+
+                if (!titleFound) {
+                    try {
+                        dispose();
+                    } catch (Exception ex) {
+                        Logger.getLogger(MaximizedFrameTest.class.getName())
+                                .log(Level.SEVERE, null, ex);
+                    }
+                    throw new RuntimeException("Test Failed. Unable to "
+                            + "determine title component");
+                }
             }
-        }
-        if ( !titleFound ){
-            throw new RuntimeException("Test Failed. Unable to determine title's size.");
-        }
-        //--------------------------------
-        // it is sufficient to get maximized Frame only once.
-        Point tempMousePosition;
-        framePosition = frame.getLocationOnScreen();
+        });
+    }
+
+    public void doMaximizeFrameTest() throws Exception {
+
+        SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
+            public void run() {
+                Point framePosition = frame.getLocationOnScreen();
+
+                tempMousePosition = new Point(framePosition.x
+                        + frame.getWidth() / 2, framePosition.y
+                                + titleComponent.getHeight() / 2);
+            }
+        });
+
         try {
-            robot = new Robot();
-            tempMousePosition = new Point(framePosition.x +
-                                          frame.getWidth()/2,
-                                          framePosition.y +
-                                          titleComponent.getHeight()/2);
+            Robot robot = new Robot();
             robot.mouseMove(tempMousePosition.x, tempMousePosition.y);
-            for (int iteration=0; iteration < ITERATIONS_COUNT; iteration++){
+            robot.waitForIdle();
+
+            for (int iteration = 0; iteration < ITERATIONS_COUNT; iteration++) {
                 robot.mousePress(InputEvent.BUTTON1_MASK);
-                gcBounds =
-                    GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()[0].getConfigurations()[0].getBounds();
-                //Moving a mouse pointer less than a few pixels
-                //leads to rising a double click event.
-                //We have to use exceeded the AWT_MULTICLICK_SMUDGE
-                //const value (which is 4 by default on GNOME) to test that.
+                robot.waitForIdle();
+
+                // Moving a mouse pointer less than a few pixels
+                // leads to rising a double click event.
+                // We have to use exceeded the AWT_MULTICLICK_SMUDGE
+                // const value (which is 4 by default on GNOME) to test that.
                 tempMousePosition.x += 5;
                 robot.mouseMove(tempMousePosition.x, tempMousePosition.y);
-                robot.delay(70);
+                robot.waitForIdle();
                 robot.mouseRelease(InputEvent.BUTTON1_MASK);
-                if ( frame.getExtendedState() != 0 ){
-                    throw new RuntimeException ("Test failed. JFrame was maximized. ExtendedState is : "+frame.getExtendedState());
+                robot.waitForIdle();
+
+                if (frame.getExtendedState() != 0) {
+                    dispose();
+                    throw new RuntimeException("Test failed. JFrame was "
+                            + "maximized. ExtendedState is : "
+                            + frame.getExtendedState());
                 }
-                robot.delay(500);
-            } //for iteration
+            }
+        } catch (AWTException e) {
+            dispose();
+            throw new RuntimeException("Test Failed. AWTException thrown.");
+        }
+        System.out.println("Test passed.");
+    }
 
-            }catch(AWTException e) {
-                throw new RuntimeException("Test Failed. AWTException thrown.");
+    private void dispose() throws Exception {
+        SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
+            public void run() {
+                if (null != frame) {
+                    frame.dispose();
+                }
             }
-        System.out.println("Test passed.");
-    }// start()
-}// class
+        });
+    }
+
+    public static void main(String[] args) throws Exception {
+
+        MaximizedFrameTest maximizedFrameTest = new MaximizedFrameTest();
+        maximizedFrameTest.init();
+        maximizedFrameTest.getTitleComponent();
+        maximizedFrameTest.doMaximizeFrameTest();
+        maximizedFrameTest.dispose();
+    }
+}
--- a/jdk/test/java/awt/TextArea/TextAreaEditing/TextAreaEditing.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/test/java/awt/TextArea/TextAreaEditing/TextAreaEditing.java	Wed Jul 05 21:10:50 2017 +0200
@@ -23,16 +23,23 @@
 
 /*
  @test
- @bug 8040322
+ @bug 8040322 8060137
+ @library ../../regtesthelpers
+ @build Util
  @summary Test TextArea APIs replaceRange, insert, append & setText
  @run main TextAreaEditing
  */
 
 import java.awt.Frame;
+import java.awt.Robot;
 import java.awt.TextArea;
+import java.awt.AWTException;
+import java.awt.event.KeyEvent;
+import test.java.awt.regtesthelpers.Util;
 
 public class TextAreaEditing {
 
+    final static Robot robot = Util.createRobot();
     private int testFailCount;
     private boolean isTestFail;
     private StringBuilder testFailMessage;
@@ -61,6 +68,7 @@
         textArea.testReplaceRange();
         textArea.testInsert();
         textArea.testAppend();
+        textArea.testSetText();
         textArea.checkFailures();
         textArea.dispose();
     }
@@ -119,6 +127,24 @@
         checkTest("");
     }
 
+    private void testSetText() {
+        textArea.setText(null);
+        textArea.requestFocus();
+        Util.clickOnComp(textArea, robot);
+        Util.waitForIdle(robot);
+        robot.keyPress(KeyEvent.VK_A);
+        robot.delay(5);
+        robot.keyRelease(KeyEvent.VK_A);
+        Util.waitForIdle(robot);
+        textArea.setText(null);
+        checkTest("");
+        textArea.setText("CaseSensitive");
+        checkTest("CaseSensitive");
+        textArea.setText("caseSensitive");
+        checkTest("caseSensitive");
+
+    }
+
     private void checkTest(String str) {
         if (str != null && !str.equals(textArea.getText())) {
             testFailMessage.append("TestFail line : ");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/TextField/EOLTest/EOLTest.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ @test
+ @bug 8055197 7186036
+ @summary TextField should replace EOL character with space character
+ @run main EOLTest
+ */
+
+import java.awt.Frame;
+import java.awt.TextField;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+
+public class EOLTest {
+
+    private Frame mainFrame;
+    private TextField textField;
+    private String testStrEOL;
+    private boolean isTestFail;
+    private int testFailCount;
+    StringBuilder testFailMessage;
+    private String expectedString = "Row1 Row2 Row3";
+
+    public EOLTest() {
+        mainFrame = new Frame();
+        mainFrame.setSize(200, 200);
+        mainFrame.setVisible(true);
+        testFailMessage = new StringBuilder();
+        testStrEOL = "Row1" + System.lineSeparator() + "Row2\nRow3";
+    }
+
+    private void testConstructor1() {
+        textField = new TextField(testStrEOL);
+        textField.setSize(200, 100);
+        mainFrame.add(textField);
+        checkTest();
+        mainFrame.remove(textField);
+    }
+
+    private void testConstructor2() {
+        textField = new TextField(30);
+        textField.setSize(200, 100);
+        mainFrame.add(textField);
+        textField.setText(testStrEOL);
+        checkTest();
+        mainFrame.remove(textField);
+    }
+
+    private void testConstructor3() {
+        textField = new TextField(testStrEOL, 30);
+        textField.setSize(200, 100);
+        mainFrame.add(textField);
+        checkTest();
+        mainFrame.remove(textField);
+    }
+
+    private void testSetText() {
+        textField = new TextField();
+        textField.setSize(200, 100);
+        textField.setText(testStrEOL);
+        mainFrame.add(textField);
+        checkTest();
+        mainFrame.remove(textField);
+    }
+
+    private void testDeserialization() {
+        TextField textFieldToSerialize = new TextField(testStrEOL);
+        textFieldToSerialize.setSize(200, 100);
+        mainFrame.add(textFieldToSerialize);
+        try {
+            // Serialize TextField object "textFieldToSerialize".
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            ObjectOutput outStream = new ObjectOutputStream(baos);
+            outStream.writeObject(textFieldToSerialize);
+
+            // Search the text variable data through serialized object stream.
+            byte[] streamedBytes = baos.toByteArray();
+            int foundLoc = 0;
+            for (int i = 0; i < streamedBytes.length; ++i) {
+                if (streamedBytes[i] == expectedString.charAt(0)) {
+                    foundLoc = i;
+                    int j = 1;
+                    for (; j < expectedString.length(); ++j) {
+                        if (streamedBytes[i+j] != expectedString.charAt(j)) {
+                            break;
+                        }
+                    }
+                    if (j == expectedString.length()) {
+                        break;
+                    }
+                }
+                foundLoc = -1;
+            }
+
+            if (foundLoc == -1) {
+                // Could not find text data in serialized object stream.
+                throw new Exception("Could not find text data in serialized "
+                    + "object stream.");
+            }
+            // Replace space character from serialized stream with
+            // EOL character for testing de-serialization.
+            String EOLChar = System.lineSeparator();
+            String newExpectedString = "";
+            for (int i = foundLoc, j = 0; j < expectedString.length(); ++i, ++j) {
+                newExpectedString += (char)(streamedBytes[i]);
+                if (streamedBytes[i] == ' ') {
+                    int k = 0;
+                    for (; k < EOLChar.length(); ++k) {
+                        streamedBytes[i + k] = (byte) EOLChar.charAt(k);
+                    }
+                    i += k-1;
+                    j += k-1;
+                }
+            }
+            // New line character varies with platform,
+            // ex. For windows '\r\n', for linux '\n'.
+            // While replacing space from serialized object stream, the length
+            // of EOL character will affect the expected string as well.
+            expectedString = newExpectedString;
+
+            // De-serialize TextField object stream.
+            ByteArrayInputStream bais = new ByteArrayInputStream(streamedBytes);
+            ObjectInput inStream = new ObjectInputStream(bais);
+            textField = (TextField) inStream.readObject();
+        } catch (Exception ex) {
+            // Serialization or De-serialization failed.
+            // Create textField with empty string to show failure.
+            ex.printStackTrace();
+            textField = new TextField();
+        }
+
+        checkTest();
+        mainFrame.remove(textFieldToSerialize);
+    }
+
+    private void checkTest() {
+        if (!textField.getText().equals(expectedString)) {
+            testFailMessage.append("TestFail line : ");
+            testFailMessage.append(Thread.currentThread().getStackTrace()[2].
+                    getLineNumber());
+            testFailMessage.append(" TextField.getText() : \"");
+            testFailMessage.append(textField.getText());
+            testFailMessage.append("\" does not match expected string : \"");
+            testFailMessage.append(expectedString).append("\"");
+            testFailMessage.append(System.getProperty("line.separator"));
+            testFailCount++;
+            isTestFail = true;
+        }
+    }
+
+    private void checkFailures() {
+        if (isTestFail) {
+            testFailMessage.insert(0, "Test Fail count : " + testFailCount
+                    + System.getProperty("line.separator"));
+            dispose();
+            throw new RuntimeException(testFailMessage.toString());
+        }
+    }
+
+    private void dispose() {
+        if (mainFrame != null) {
+            mainFrame.dispose();
+        }
+    }
+
+    public static void main(String[] args) {
+        EOLTest testEOL = new EOLTest();
+        testEOL.testConstructor1();
+        testEOL.testConstructor2();
+        testEOL.testConstructor3();
+        testEOL.testSetText();
+        testEOL.testDeserialization();
+        testEOL.checkFailures();
+        testEOL.dispose();
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/TextField/TextFieldEditing/TextFieldEditing.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ @test
+ @bug 8060137
+ @library ../../regtesthelpers
+ @build Util
+ @summary Test TextField setText API
+ @run main TextFieldEditing
+ */
+
+import java.awt.Frame;
+import java.awt.Robot;
+import java.awt.TextField;
+import java.awt.AWTException;
+import java.awt.event.KeyEvent;
+import test.java.awt.regtesthelpers.Util;
+
+public class TextFieldEditing {
+
+    final static Robot robot = Util.createRobot();
+    private int testFailCount;
+    private boolean isTestFail;
+    private StringBuilder testFailMessage;
+
+    private Frame mainFrame;
+    private TextField textField;
+
+    private TextFieldEditing() {
+        testFailMessage = new StringBuilder();
+        mainFrame = new Frame();
+        mainFrame.setSize(200, 200);
+
+        textField = new TextField();
+        mainFrame.add(textField);
+        mainFrame.setVisible(true);
+    }
+
+    private void dispose() {
+        if (mainFrame != null) {
+            mainFrame.dispose();
+        }
+    }
+
+    public static void main(String[] s) {
+        TextFieldEditing textField = new TextFieldEditing();
+        textField.testSetText();
+        textField.checkFailures();
+        textField.dispose();
+    }
+
+    private void testSetText() {
+        textField.setText(null);
+        textField.requestFocus();
+        Util.clickOnComp(textField, robot);
+        Util.waitForIdle(robot);
+        robot.keyPress(KeyEvent.VK_A);
+        robot.delay(5);
+        robot.keyRelease(KeyEvent.VK_A);
+        Util.waitForIdle(robot);
+        textField.setText(null);
+        checkTest("");
+        textField.setText("CaseSensitive");
+        checkTest("CaseSensitive");
+        textField.setText("caseSensitive");
+        checkTest("caseSensitive");
+    }
+
+    private void checkTest(String str) {
+        if (str != null && !str.equals(textField.getText())) {
+            testFailMessage.append("TestFail line : ");
+            testFailMessage.append(Thread.currentThread().getStackTrace()[2].
+                    getLineNumber());
+            testFailMessage.append(" TextField string : \"");
+            testFailMessage.append(textField.getText());
+            testFailMessage.append("\" does not match expected string : \"");
+            testFailMessage.append(str).append("\"");
+            testFailMessage.append(System.getProperty("line.separator"));
+            testFailCount++;
+            isTestFail = true;
+        }
+    }
+
+    private void checkFailures() {
+        if (isTestFail) {
+            testFailMessage.insert(0, "Test Fail count : " + testFailCount
+                    + System.getProperty("line.separator"));
+            dispose();
+            throw new RuntimeException(testFailMessage.toString());
+        }
+    }
+}
--- a/jdk/test/java/awt/TrayIcon/ActionCommand/ActionCommand.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/test/java/awt/TrayIcon/ActionCommand/ActionCommand.java	Wed Jul 05 21:10:50 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -59,8 +59,11 @@
                         "and rerun test.");
             } else  if (System.getProperty("os.name").toLowerCase().startsWith("mac")){
                 isMacOS = true;
+            } else if (SystemTrayIconHelper.isOel7()) {
+                System.out.println("OEL 7 doesn't support double click in " +
+                        "systray. Skipped");
+                return;
             }
-
             new ActionCommand().doTest();
         }
     }
--- a/jdk/test/java/awt/TrayIcon/ActionEventMask/ActionEventMask.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/test/java/awt/TrayIcon/ActionEventMask/ActionEventMask.java	Wed Jul 05 21:10:50 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -66,6 +66,10 @@
         } else {
             if (System.getProperty("os.name").toLowerCase().startsWith("mac")) {
                 isMacOS = true;
+            } else if (SystemTrayIconHelper.isOel7()) {
+                System.out.println("OEL 7 doesn't support double click in " +
+                        "systray. Skipped");
+                return;
             }
             new ActionEventMask().doTest();
         }
--- a/jdk/test/java/awt/TrayIcon/ModalityTest/ModalityTest.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/test/java/awt/TrayIcon/ModalityTest/ModalityTest.java	Wed Jul 05 21:10:50 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,6 +35,7 @@
  */
 public class ModalityTest {
 
+    private static boolean isOEL7;
     TrayIcon icon;
     ExtendedRobot robot;
     Dialog d;
@@ -80,7 +81,7 @@
                         "\"Always show all icons and notifications on the taskbar\" true " +
                         "to avoid this problem. Or change behavior only for Java SE tray " +
                         "icon and rerun test.");
-
+            isOEL7 = SystemTrayIconHelper.isOel7();
             new ModalityTest().doTest();
         }
     }
@@ -225,6 +226,12 @@
         Point iconPosition = SystemTrayIconHelper.getTrayIconLocation(icon);
         if (iconPosition == null)
             throw new RuntimeException("Unable to find the icon location!");
+        if (isOEL7) {
+            // close tray
+            robot.mouseMove(100,100);
+            robot.click(InputEvent.BUTTON1_MASK);
+            robot.waitForIdle(2000);
+        }
 
         if (! d.isVisible())
             throw new RuntimeException("FAIL: The modal dialog is not yet visible");
@@ -232,27 +239,35 @@
         robot.mouseMove(iconPosition.x, iconPosition.y);
         robot.waitForIdle(2000);
 
-        SystemTrayIconHelper.doubleClick(robot);
+        if(!isOEL7) {
+            SystemTrayIconHelper.doubleClick(robot);
 
-        if (! actionPerformed) {
-            synchronized (actionLock) {
-                try {
-                    actionLock.wait(3000);
-                } catch (Exception e) {
+            if (!actionPerformed) {
+                synchronized (actionLock) {
+                    try {
+                        actionLock.wait(3000);
+                    } catch (Exception e) {
+                    }
                 }
             }
+            if (!actionPerformed)
+                throw new RuntimeException("FAIL: ActionEvent not triggered when TrayIcon is double clicked");
         }
-        if (! actionPerformed)
-            throw new RuntimeException("FAIL: ActionEvent not triggered when TrayIcon is double clicked");
 
         for (int i = 0; i < buttonTypes.length; i++) {
             mousePressed = false;
-            robot.mousePress(buttonTypes[i]);
+            if(isOEL7) {
+                SystemTrayIconHelper.openTrayIfNeeded(robot);
+                robot.mouseMove(iconPosition.x, iconPosition.y);
+                robot.click(buttonTypes[i]);
+            } else {
+                robot.mousePress(buttonTypes[i]);
+            }
 
             if (! mousePressed) {
                 synchronized (pressLock) {
                     try {
-                        pressLock.wait(3000);
+                        pressLock.wait(6000);
                     } catch (Exception e) {
                     }
                 }
@@ -264,12 +279,18 @@
 
             mouseReleased = false;
             mouseClicked = false;
-            robot.mouseRelease(buttonTypes[i]);
+            if(isOEL7) {
+                SystemTrayIconHelper.openTrayIfNeeded(robot);
+                robot.mouseMove(iconPosition.x, iconPosition.y);
+                robot.click(buttonTypes[i]);
+            } else {
+                robot.mouseRelease(buttonTypes[i]);
+            }
 
             if (! mouseReleased) {
                 synchronized (releaseLock) {
                     try {
-                        releaseLock.wait(3000);
+                        releaseLock.wait(6000);
                     } catch (Exception e) {
                     }
                 }
@@ -281,7 +302,7 @@
             if (! mouseClicked) {
                 synchronized (clickLock) {
                     try {
-                        clickLock.wait(3000);
+                        clickLock.wait(6000);
                     } catch (Exception e) {
                     }
                 }
@@ -290,13 +311,14 @@
                 throw new RuntimeException("FAIL: mouseClicked not triggered when " +
                         buttonNames[i] + " pressed & released");
         }
+        if (!isOEL7) {
+            mouseMoved = false;
+            robot.mouseMove(iconPosition.x, iconPosition.y);
+            robot.glide(iconPosition.x + 100, iconPosition.y);
 
-        mouseMoved = false;
-        robot.mouseMove(iconPosition.x, iconPosition.y);
-        robot.glide(iconPosition.x + 100, iconPosition.y);
-
-        if (! mouseMoved)
-            if (! SystemTrayIconHelper.skip(0) )
-                throw new RuntimeException("FAIL: mouseMoved not triggered even when mouse moved over the icon");
+            if (!mouseMoved)
+                if (!SystemTrayIconHelper.skip(0))
+                    throw new RuntimeException("FAIL: mouseMoved not triggered even when mouse moved over the icon");
+        }
     }
 }
--- a/jdk/test/java/awt/TrayIcon/MouseEventMask/MouseEventMaskTest.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/test/java/awt/TrayIcon/MouseEventMask/MouseEventMaskTest.java	Wed Jul 05 21:10:50 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -71,6 +71,8 @@
                         "\"Always show all icons and notifications on the taskbar\" true " +
                         "to avoid this problem. Or change behavior only for Java SE tray " +
                         "icon and rerun test.");
+            } else if (SystemTrayIconHelper.isOel7()) {
+                return;
             }
             new MouseEventMaskTest().doTest();
         }
--- a/jdk/test/java/awt/TrayIcon/MouseMovedTest/MouseMovedTest.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/test/java/awt/TrayIcon/MouseMovedTest/MouseMovedTest.java	Wed Jul 05 21:10:50 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,7 +31,7 @@
  * @summary Check for mouseMoved event for java.awt.TrayIcon
  * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com)
  * @library ../../../../lib/testlibrary
- * @build ExtendedRobot
+ * @build ExtendedRobot SystemTrayIconHelper
  * @run main MouseMovedTest
  */
 
@@ -39,6 +39,14 @@
     static volatile boolean moved;
 
     public static void main(String[] args) throws Exception {
+        if (!SystemTray.isSupported()) {
+            return;
+        }
+
+        if (SystemTrayIconHelper.isOel7()) {
+            return;
+        }
+
         moved = false;
 
         TrayIcon icon = new TrayIcon(new BufferedImage(20, 20, BufferedImage.TYPE_INT_RGB), "Test icon");
--- a/jdk/test/java/awt/TrayIcon/SecurityCheck/FunctionalityCheck/FunctionalityCheck.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/test/java/awt/TrayIcon/SecurityCheck/FunctionalityCheck/FunctionalityCheck.java	Wed Jul 05 21:10:50 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -51,6 +51,7 @@
     boolean mouseReleased = false;
     boolean mouseClicked = false;
     boolean mouseMoved = false;
+    static boolean isOEL7;
 
     static final int[] buttonTypes = {
         InputEvent.BUTTON1_MASK,
@@ -69,6 +70,7 @@
             System.out.println("SystemTray not supported on the platform under test. " +
                                "Marking the test passed");
         } else {
+            isOEL7 = SystemTrayIconHelper.isOel7();
             new FunctionalityCheck().doTest();
         }
     }
@@ -188,31 +190,44 @@
         Point iconPosition = SystemTrayIconHelper.getTrayIconLocation(icon);
         if (iconPosition == null)
             throw new RuntimeException("Unable to find the icon location!");
+        if (isOEL7) {
+            // close tray
+            robot.mouseMove(100,100);
+            robot.click(InputEvent.BUTTON1_MASK);
+            robot.waitForIdle(2000);
+        }
 
         robot.mouseMove(iconPosition.x, iconPosition.y);
-        robot.waitForIdle(2000);
-
-        SystemTrayIconHelper.doubleClick(robot);
+        robot.waitForIdle();
+        if(!isOEL7) {
+            SystemTrayIconHelper.doubleClick(robot);
 
-        if (! actionPerformed) {
-            synchronized (actionLock) {
-                try {
-                    actionLock.wait(3000);
-                } catch (Exception e) {
+            if (!actionPerformed) {
+                synchronized (actionLock) {
+                    try {
+                        actionLock.wait(3000);
+                    } catch (Exception e) {
+                    }
                 }
             }
+            if (!actionPerformed)
+                throw new RuntimeException("FAIL: ActionEvent not triggered when TrayIcon is double clicked");
         }
-        if (! actionPerformed)
-            throw new RuntimeException("FAIL: ActionEvent not triggered when TrayIcon is double clicked");
 
         for (int i = 0; i < buttonTypes.length; i++) {
             mousePressed = false;
-            robot.mousePress(buttonTypes[i]);
+            if(isOEL7) {
+                SystemTrayIconHelper.openTrayIfNeeded(robot);
+                robot.mouseMove(iconPosition.x, iconPosition.y);
+                robot.click(buttonTypes[i]);
+            } else {
+                robot.mousePress(buttonTypes[i]);
+            }
 
             if (! mousePressed) {
                 synchronized (pressLock) {
                     try {
-                        pressLock.wait(3000);
+                        pressLock.wait(6000);
                     } catch (Exception e) {
                     }
                 }
@@ -224,12 +239,17 @@
 
             mouseReleased = false;
             mouseClicked = false;
-            robot.mouseRelease(buttonTypes[i]);
-
+            if(isOEL7) {
+                SystemTrayIconHelper.openTrayIfNeeded(robot);
+                robot.mouseMove(iconPosition.x, iconPosition.y);
+                robot.click(buttonTypes[i]);
+            } else {
+                robot.mouseRelease(buttonTypes[i]);
+            }
             if (! mouseReleased) {
                 synchronized (releaseLock) {
                     try {
-                        releaseLock.wait(3000);
+                        releaseLock.wait(6000);
                     } catch (Exception e) {
                     }
                 }
@@ -242,7 +262,7 @@
             if (! mouseClicked) {
                 synchronized (clickLock) {
                     try {
-                        clickLock.wait(3000);
+                        clickLock.wait(6000);
                     } catch (Exception e) {
                     }
                 }
@@ -251,13 +271,14 @@
                 throw new RuntimeException("FAIL: mouseClicked not triggered when " +
                         buttonNames[i] + " pressed & released");
         }
+        if(!isOEL7) {
+            mouseMoved = false;
+            robot.mouseMove(iconPosition.x + 100, iconPosition.y);
+            robot.glide(iconPosition.x, iconPosition.y);
 
-        mouseMoved = false;
-        robot.mouseMove(iconPosition.x + 100, iconPosition.y);
-        robot.glide(iconPosition.x, iconPosition.y);
-
-        if (! mouseMoved)
-            if (! SystemTrayIconHelper.skip(0) )
-                throw new RuntimeException("FAIL: mouseMoved not triggered even when mouse moved over the icon");
+            if (!mouseMoved)
+                if (!SystemTrayIconHelper.skip(0))
+                    throw new RuntimeException("FAIL: mouseMoved not triggered even when mouse moved over the icon");
+        }
     }
 }
--- a/jdk/test/java/awt/TrayIcon/SecurityCheck/FunctionalityCheck/tray.policy	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/test/java/awt/TrayIcon/SecurityCheck/FunctionalityCheck/tray.policy	Wed Jul 05 21:10:50 2017 +0200
@@ -5,6 +5,7 @@
   permission java.util.PropertyPermission "resultsDir", "read";
   permission java.util.PropertyPermission "user.home", "read";
   permission java.util.PropertyPermission "os.name", "read";
+  permission java.util.PropertyPermission "os.version", "read";
   permission java.awt.AWTPermission "accessEventQueue";
   permission java.lang.RuntimePermission "setIO";
   permission java.lang.RuntimePermission "accessDeclaredMembers";
@@ -17,5 +18,6 @@
   permission java.util.PropertyPermission "java.class.path", "read";
   permission java.awt.AWTPermission "readDisplayPixels";
   permission java.awt.AWTPermission "watchMousePointer";
+
 };
 
--- a/jdk/test/java/awt/TrayIcon/SystemTrayIconHelper.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/test/java/awt/TrayIcon/SystemTrayIconHelper.java	Wed Jul 05 21:10:50 2017 +0200
@@ -66,7 +66,9 @@
                 for (int x = (int) (screenSize.getWidth()-width); x > 0; x--) {
                     for (int y = (int) (screenSize.getHeight()-height); y > (screenSize.getHeight()-50); y--) {
                         if (imagesEquals(((BufferedImage)icon.getImage()).getSubimage(0, 0, width, height), screen.getSubimage(x, y, width, height))) {
-                            return new Point(x+5, y+5);
+                            Point point = new Point(x + 5, y + 5);
+                            System.out.println("Icon location " + point);
+                            return point;
                         }
                     }
                 }
@@ -91,6 +93,7 @@
                 point2d = (Point2D)m_getLocation.invoke(peer, new Object[]{model});
                 Point po = new Point((int)(point2d.getX()), (int)(point2d.getY()));
                 po.translate(10, -5);
+                System.out.println("Icon location " + po);
                 return po;
             }catch(Exception e) {
                 e.printStackTrace();
@@ -101,12 +104,15 @@
                 // sun.awt.X11.XTrayIconPeer
                 Field f_peer = getField(java.awt.TrayIcon.class, "peer");
 
+                SystemTrayIconHelper.openTrayIfNeeded(robot);
+
                 Object peer = f_peer.get(icon);
                 Method m_getLOS = peer.getClass().getDeclaredMethod(
                         "getLocationOnScreen", new Class[]{});
                 m_getLOS.setAccessible(true);
                 Point point = (Point)m_getLOS.invoke(peer, new Object[]{});
                 point.translate(5, 5);
+                System.out.println("Icon location " + point);
                 return point;
             } catch (Exception e) {
                 e.printStackTrace();
@@ -169,4 +175,38 @@
         }
         return false;
     }
+
+    public static boolean openTrayIfNeeded(Robot robot) {
+        String sysv = System.getProperty("os.version");
+        System.out.println("System version is " + sysv);
+        //Additional step to raise the system try in Gnome 3 in OEL 7
+        if(isOel7()) {
+            System.out.println("OEL 7 detected");
+            GraphicsConfiguration gc = GraphicsEnvironment.
+                    getLocalGraphicsEnvironment().getDefaultScreenDevice().
+                    getDefaultConfiguration();
+            Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(gc);
+            if(insets.bottom > 0) {
+                Dimension screenSize = Toolkit.getDefaultToolkit()
+                        .getScreenSize();
+                robot.mouseMove(screenSize.width - insets.bottom / 2,
+                        screenSize.height - insets.bottom / 2);
+                robot.delay(50);
+                robot.mousePress(InputEvent.BUTTON1_MASK);
+                robot.delay(50);
+                robot.mouseRelease(InputEvent.BUTTON1_MASK);
+                robot.waitForIdle();
+                robot.delay(1000);
+                System.out.println("Tray is opened");
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static boolean isOel7() {
+        return System.getProperty("os.name").toLowerCase()
+                .contains("linux") && System.getProperty("os.version")
+                .toLowerCase().contains("el7");
+    }
 }
--- a/jdk/test/java/awt/TrayIcon/TrayIconEventModifiers/TrayIconEventModifiersTest.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/test/java/awt/TrayIcon/TrayIconEventModifiers/TrayIconEventModifiersTest.java	Wed Jul 05 21:10:50 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -121,6 +121,12 @@
                 };
             }
 
+            if (SystemTrayIconHelper.isOel7()) {
+                System.out.println("OEL 7 doesn't support click modifiers in " +
+                        "systray. Skipped");
+                return;
+            }
+
             new TrayIconEventModifiersTest().doTest();
         }
     }
--- a/jdk/test/java/awt/TrayIcon/TrayIconEvents/TrayIconEventsTest.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/test/java/awt/TrayIcon/TrayIconEvents/TrayIconEventsTest.java	Wed Jul 05 21:10:50 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -37,6 +37,7 @@
 
 public class TrayIconEventsTest {
 
+    private static boolean isOEL7;
     TrayIcon icon;
     ExtendedRobot robot;
 
@@ -77,6 +78,7 @@
                         "\"Always show all icons and notifications on the taskbar\" true " +
                         "to avoid this problem. Or change behavior only for Java SE " +
                         "tray icon.");
+            isOEL7 = SystemTrayIconHelper.isOel7();
             new TrayIconEventsTest().doTest();
         }
     }
@@ -195,31 +197,44 @@
         Point iconPosition = SystemTrayIconHelper.getTrayIconLocation(icon);
         if (iconPosition == null)
             throw new RuntimeException("Unable to find the icon location!");
+        if (isOEL7) {
+            // close tray
+            robot.mouseMove(100,100);
+            robot.click(InputEvent.BUTTON1_MASK);
+            robot.waitForIdle(2000);
+        }
 
         robot.mouseMove(iconPosition.x, iconPosition.y);
-        robot.waitForIdle(2000);
-
-        SystemTrayIconHelper.doubleClick(robot);
+        robot.waitForIdle();
+        if(!isOEL7) {
+            SystemTrayIconHelper.doubleClick(robot);
 
-        if (! actionPerformed) {
-            synchronized (actionLock) {
-                try {
-                    actionLock.wait(10000);
-                } catch (Exception e) {
+            if (!actionPerformed) {
+                synchronized (actionLock) {
+                    try {
+                        actionLock.wait(10000);
+                    } catch (Exception e) {
+                    }
                 }
             }
+            if (!actionPerformed)
+                throw new RuntimeException("FAIL: ActionEvent not triggered when TrayIcon is double clicked");
         }
-        if (! actionPerformed)
-            throw new RuntimeException("FAIL: ActionEvent not triggered when TrayIcon is double clicked");
 
         for (int i = 0; i < buttonTypes.length; i++) {
             mousePressed = false;
-            robot.mousePress(buttonTypes[i]);
+            if(isOEL7) {
+                SystemTrayIconHelper.openTrayIfNeeded(robot);
+                robot.mouseMove(iconPosition.x, iconPosition.y);
+                robot.click(buttonTypes[i]);
+            } else {
+                robot.mousePress(buttonTypes[i]);
+            }
 
             if (! mousePressed) {
                 synchronized (pressLock) {
                     try {
-                        pressLock.wait(3000);
+                        pressLock.wait(6000);
                     } catch (Exception e) {
                     }
                 }
@@ -231,12 +246,18 @@
 
             mouseReleased = false;
             mouseClicked = false;
-            robot.mouseRelease(buttonTypes[i]);
+            if(isOEL7) {
+                SystemTrayIconHelper.openTrayIfNeeded(robot);
+                robot.mouseMove(iconPosition.x, iconPosition.y);
+                robot.click(buttonTypes[i]);
+            } else {
+                robot.mouseRelease(buttonTypes[i]);
+            }
 
             if (! mouseReleased) {
                 synchronized (releaseLock) {
                     try {
-                        releaseLock.wait(3000);
+                        releaseLock.wait(6000);
                     } catch (Exception e) {
                     }
                 }
@@ -248,7 +269,7 @@
             if (! mouseClicked) {
                 synchronized (clickLock) {
                     try {
-                        clickLock.wait(3000);
+                        clickLock.wait(6000);
                     } catch (Exception e) {
                     }
                 }
@@ -258,12 +279,14 @@
                         buttonNames[i] + " pressed & released");
         }
 
-        mouseMoved = false;
-        robot.mouseMove(iconPosition.x + 100, iconPosition.y);
-        robot.glide(iconPosition.x, iconPosition.y);
+        if (!isOEL7) {
+            mouseMoved = false;
+            robot.mouseMove(iconPosition.x + 100, iconPosition.y);
+            robot.glide(iconPosition.x, iconPosition.y);
 
-        if (! mouseMoved)
-            if (! SystemTrayIconHelper.skip(0) )
-                throw new RuntimeException("FAIL: mouseMoved not triggered even when mouse moved over the icon");
+            if (!mouseMoved)
+                if (!SystemTrayIconHelper.skip(0))
+                    throw new RuntimeException("FAIL: mouseMoved not triggered even when mouse moved over the icon");
+        }
     }
 }
--- a/jdk/test/java/awt/TrayIcon/TrayIconMouseTest/TrayIconMouseTest.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/test/java/awt/TrayIcon/TrayIconMouseTest/TrayIconMouseTest.java	Wed Jul 05 21:10:50 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -66,6 +66,10 @@
         } else {
             if (System.getProperty("os.name").toLowerCase().startsWith("mac")) {
                 isMacOS = true;
+            } else if (SystemTrayIconHelper.isOel7()) {
+                System.out.println("OEL 7 doesn't support double click in " +
+                        "systray. Skipped");
+                return;
             }
             new TrayIconMouseTest().doTest();
         }
@@ -108,7 +112,7 @@
         for (int i = 0; i < buttonTypes.length; i++) {
             actionPerformed = false;
             robot.click(buttonTypes[i]);
-            robot.waitForIdle(2000);
+            robot.waitForIdle(6000);
 
             if (isMacOS && actionPerformed && i == 2) {
 
@@ -155,7 +159,7 @@
                     if (! actionPerformed) {
                         synchronized (actionLock) {
                             try {
-                                actionLock.wait(3000);
+                                actionLock.wait(6000);
                             } catch (Exception e) {
                             }
                         }
--- a/jdk/test/java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/test/java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java	Wed Jul 05 21:10:50 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -127,7 +127,7 @@
         robot.mousePress(InputEvent.BUTTON3_MASK);
         robot.delay(50);
         robot.mouseRelease(InputEvent.BUTTON3_MASK);
-        robot.delay(1000);
+        robot.delay(6000);
 
         robot.mouseMove(window.getLocation().x + 10, window.getLocation().y + 10);
         robot.mousePress(InputEvent.BUTTON3_MASK);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/font/GlyphVector/TestStandardGlyphVectorBug.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.awt.Font;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+
+/**
+ * @test
+ * @bug 7160052
+ * @run main TestStandardGlyphVectorBug
+ * @summary GlyphVector.setGlyphPosition should not throw an exception on valid input
+ */
+public class TestStandardGlyphVectorBug
+{
+    public static void main(String[] args)
+    {
+        Font defaultFont = new Font(null);
+        FontRenderContext defaultFrc = new FontRenderContext(new AffineTransform(),
+                                                             true, true);
+        GlyphVector gv = defaultFont.createGlyphVector(defaultFrc, "test");
+
+        //this causes the bounds to be cached
+        //which is necessary to trigger the bug
+        gv.getGlyphLogicalBounds(0);
+
+        //this correctly gets the position of the overall advance
+        Point2D glyphPosition = gv.getGlyphPosition(gv.getNumGlyphs());
+
+        // this sets the position of the overall advance,
+        // but also incorrectly tries to clear the bounds cache
+        // of a specific glyph indexed by the glyphIndex parameter
+        // even if the glyphIndex represents the overall advance
+        // (i.e. if glyphIndex == getNumGlyphs())
+        gv.setGlyphPosition(gv.getNumGlyphs(), glyphPosition);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/image/VolatileImage/VolatileImageBug.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsEnvironment;
+import java.awt.image.VolatileImage;
+
+/**
+ * @test
+ * @bug 8140530
+ * @run main VolatileImageBug
+ * @summary Creating volatileimage(0,0) should throw IAE
+ */
+public class VolatileImageBug {
+    public static void main(String[] args) {
+
+        boolean iaeThrown = false;
+        GraphicsEnvironment ge = GraphicsEnvironment.
+                                      getLocalGraphicsEnvironment();
+        GraphicsConfiguration gc = ge.getDefaultScreenDevice().
+                                           getDefaultConfiguration();
+        try {
+            VolatileImage volatileImage = gc.createCompatibleVolatileImage(0, 0);
+        } catch (IllegalArgumentException iae) {
+            iaeThrown = true;
+        }
+        if (!iaeThrown) {
+            throw new RuntimeException ("IllegalArgumentException not thrown " +
+                                        "for createCompatibleVolatileImage(0,0)");
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/beans/XMLEncoder/javax_swing_JComponent.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import javax.swing.JComponent;
+import javax.swing.plaf.ComponentUI;
+
+/*
+ * @test
+ * @bug 8131754
+ * @summary Tests JComponent encoding
+ */
+public final class javax_swing_JComponent extends AbstractTest<JComponent> {
+
+    public static void main(final String[] args) {
+        new javax_swing_JComponent().test(true);
+    }
+
+    protected JComponent getObject() {
+        return new SimpleJComponent();
+    }
+
+    protected JComponent getAnotherObject() {
+        return new CustomJComponent();
+    }
+
+    public static final class SimpleJComponent extends JComponent {
+
+    }
+
+    public static final class CustomJComponent extends JComponent {
+
+        public CustomJComponent() {
+            ui = new CustomUI();
+        }
+
+        @Override
+        public ComponentUI getUI() {
+            return ui;
+        }
+
+        @Override
+        public void setUI(final ComponentUI newUI) {
+            ui = newUI;
+        }
+    }
+
+    public static final class CustomUI extends ComponentUI {
+
+        public boolean getFlag() {
+            throw new Error();
+        }
+
+        public void setFlag(final boolean flag) {
+            throw new Error();
+        }
+    }
+}
--- a/jdk/test/java/lang/ProcessHandle/InfoTest.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/test/java/lang/ProcessHandle/InfoTest.java	Wed Jul 05 21:10:50 2017 +0200
@@ -49,7 +49,7 @@
 
 /*
  * @test
- * @bug 8077350 8081566 8081567 8098852
+ * @bug 8077350 8081566 8081567 8098852 8136597
  * @build jdk.testlibrary.*
  * @library /lib/testlibrary
  * @summary Functions of ProcessHandle.Info
@@ -210,10 +210,12 @@
                             Assert.assertTrue(commandLine.contains(allArgs.get(i)),
                                               "commandLine() must contain argument: " + allArgs.get(i));
                         }
-                    } else if (info.commandLine().isPresent()) {
+                    } else if (info.commandLine().isPresent() &&
+                            command.isPresent() &&
+                            command.get().length() < info.commandLine().get().length()) {
                         // If we only have the commandLine() we can only do some basic checks...
                         String commandLine = info.commandLine().get();
-                        String javaExe = "java" + (Platform.isWindows() ? ".exe": "");
+                        String javaExe = "java" + (Platform.isWindows() ? ".exe" : "");
                         int pos = commandLine.indexOf(javaExe);
                         Assert.assertTrue(pos > 0, "commandLine() should at least contain 'java'");
 
--- a/jdk/test/java/lang/ref/CleanerTest.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/test/java/lang/ref/CleanerTest.java	Wed Jul 05 21:10:50 2017 +0200
@@ -28,9 +28,9 @@
 import java.lang.ref.SoftReference;
 import java.lang.ref.WeakReference;
 import java.util.Objects;
-import java.util.Vector;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
 import java.util.function.Consumer;
 import java.util.function.Supplier;
 
@@ -38,15 +38,21 @@
 import jdk.internal.misc.CleanerImpl.WeakCleanable;
 import jdk.internal.misc.CleanerImpl.SoftCleanable;
 
+import sun.hotspot.WhiteBox;
+
 import org.testng.Assert;
 import org.testng.TestNG;
 import org.testng.annotations.Test;
 
 /*
  * @test
- * @library /lib/testlibrary
+ * @library /lib/testlibrary /test/lib
+ * @build sun.hotspot.WhiteBox
  * @modules java.base/jdk.internal.misc
- * @run testng/othervm -Xmx4m CleanerTest
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * @run testng/othervm
+ *      -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *      -verbose:gc -Xmx4m CleanerTest
  */
 
 @Test
@@ -54,6 +60,9 @@
     // A common CleaningService used by the test for notifications
     static final Cleaner COMMON = Cleaner.create();
 
+    // Access to WhiteBox utilities
+    static final WhiteBox whitebox = WhiteBox.getWhiteBox();
+
     /**
      * Test that sequences of the various actions on a Reference
      * and on the Cleanable instance have the desired result.
@@ -265,50 +274,29 @@
     }
 
     /**
-     * Check a set of semaphores having been released by cleanup handlers.
+     * Check a semaphore having been released by cleanup handler.
      * Force a number of GC cycles to give the GC a chance to process
-     * all the References and for the cleanup actions to be run.
+     * the Reference and for the cleanup action to be run.
      *
-     * @param semaphore a varargs list of Semaphores
-     * @return true if all of the semaphores have at least 1 permit,
-     *      false otherwise.
+     * @param semaphore a Semaphore
+     * @return true if the semaphores has 1 permit, false otherwise.
      */
-    static boolean checkCleaned(Semaphore... semaphore) {
-        long[] cycles = new long[semaphore.length];
-        long total = 0;
-        for (int cycle = 0; cycle < 20; cycle++) {
-            for (int i = 0; i < semaphore.length; i++) {
-                long count = semaphore[i].availablePermits();
-                if (count > 0 && cycles[i] == 0) {
-                    System.out.printf(" Cleanable[%d] cleaned in cycle: %d%n", i, cycle);
-                    cycles[i] = cycle;
-                    total += 1;
+    static boolean checkCleaned(Semaphore semaphore) {
+        int cycle = 0;
+        for (; cycle < 3; cycle++) {
+            try {
+                if (semaphore.tryAcquire(10L, TimeUnit.MILLISECONDS)) {
+                    System.out.printf(" Cleanable cleaned in cycle: %d%n", cycle);
+                    return true;
                 }
-            }
-
-            if (total == semaphore.length) {
-                System.out.printf(" All cleanups done in cycle: %d, total: %d%n",
-                        cycle, total);
-                for (int i = 0; i < semaphore.length; i++) {
-                    long count = semaphore[i].availablePermits();
-                    Assert.assertEquals(count, 1,
-                            "Cleanable invoked more than once, semaphore " + i);
-                }
-                return true;          // all references freed
+            } catch (InterruptedException ie) {
+                // retry in outer loop
             }
             // Force GC
-            memoryPressure();
+            whitebox.fullGC();
         }
-        // Not all objects have been cleaned
-
-        for (int i = 0; i < semaphore.length; i++) {
-            if (cycles[i] != 0) {
-                System.out.printf(" Cleanable[%d] cleaned in cycle: %d%n", i, cycles[i]);
-            } else {
-                System.out.printf(" Cleanable[%d] not cleaned%n", i);
-            }
-        }
-
+        // Object has not been cleaned
+        System.out.printf(" Cleanable not cleaned%n");
         return false;   // Failing result
     }
 
@@ -457,24 +445,6 @@
     }
 
     /**
-     * MemoryPressure allocates memory to force a gc and to clear SoftReferences.
-     */
-    static void memoryPressure() {
-        SoftReference<Object> soft = new SoftReference<>(new Object(), null);
-        Vector<Object> root = new Vector<>();
-        try {
-            long free = 0;
-            while (soft.get() != null) {
-                long[] extra = new long[50_000];
-                root.addElement(extra);
-            }
-        } catch (OutOfMemoryError mem) {
-            // ignore
-            root = null;
-        }
-    }
-
-    /**
      * CleanableCase encapsulates the objects used for a test.
      * The reference to the object is not held directly,
      * but in a Reference object that can be cleared.
--- a/jdk/test/java/net/NetworkInterface/NetworkInterfaceStreamTest.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/test/java/net/NetworkInterface/NetworkInterfaceStreamTest.java	Wed Jul 05 21:10:50 2017 +0200
@@ -85,13 +85,15 @@
     }
 
     private Stream<NetworkInterface> allNetworkInterfaces() throws SocketException {
-        return NetworkInterface.networkInterfaces().flatMap(this::allSubNetworkInterfaces);
+        return NetworkInterface.networkInterfaces()
+                .filter(ni -> isIncluded(ni))
+                .flatMap(this::allSubNetworkInterfaces);
     }
 
     private Stream<NetworkInterface> allSubNetworkInterfaces(NetworkInterface ni) {
         return Stream.concat(
                 Stream.of(ni),
-                ni.subInterfaces().flatMap(this::allSubNetworkInterfaces));
+                ni.subInterfaces().filter(sni -> isIncluded(sni)).flatMap(this::allSubNetworkInterfaces));
     }
 
     @Test
@@ -129,7 +131,9 @@
         Collection<NetworkInterface> nis = Collections.list(NetworkInterface.getNetworkInterfaces());
         Collection<InetAddress> expected = new ArrayList<>();
         for (NetworkInterface ni : nis) {
-            expected.addAll(Collections.list(ni.getInetAddresses()));
+            if (isIncluded(ni)) {
+                expected.addAll(Collections.list(ni.getInetAddresses()));
+            }
         }
         withData(TestData.Factory.ofSupplier("All inet addresses", ss))
                 .stream(s -> s)
--- a/jdk/test/java/net/URL/TestPort.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/test/java/net/URL/TestPort.java	Wed Jul 05 21:10:50 2017 +0200
@@ -23,28 +23,33 @@
 
 /*
  * @test
- * @bug 4101492 4444213
+ * @bug 4101492 4444213 4906983
  * @summary The java.net.URL constructor allows port < 0 and port > 65535
  */
 
 import java.net.*;
 
 public class TestPort {
-    public static void main(String[] args) {
-        URL url = null;
+    public static void main(String[] args) throws MalformedURLException {
+        // URLs are able to have port bigger than TCP-Port 65535 and
+        // to have no port (-1) at all.:
+        URL url = new URL("http","server",Integer.MAX_VALUE,"/path");
+        url = new URL("http://server:"+Integer.MAX_VALUE+"/path");
+        url = new URL("http://server/path");
+        url = new URL("http","server",-1,"/path");
+
         try {
             url = new URL("ftp", "java.sun.com", -20, "/pub/");
+            throw new RuntimeException("MalformedURLException not thrown!");
         } catch (MalformedURLException e) {
-            url = null;
+            // Everything fine. MalformedURLException expected
         }
-        if (url != null)
-            throw new RuntimeException("MalformedURLException not thrown!");
+
         try {
             url = new URL("ftp://java.sun.com:-20/pub/");
+            throw new RuntimeException("MalformedURLException not thrown!");
         } catch (MalformedURLException e) {
-            url = null;
+            // Everything fine. MalformedURLException expected
         }
-        if (url != null)
-            throw new RuntimeException("MalformedURLException not thrown!");
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/WatchService/UpdateInterference.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 8145981
+ * @summary LinuxWatchService sometimes reports inotify events against wrong directory
+ * @run main UpdateInterference
+ */
+import java.io.IOException;
+import java.nio.file.*;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import static java.nio.file.StandardWatchEventKinds.*;
+
+public class UpdateInterference {
+    public static void main(String[] args) throws IOException, InterruptedException {
+        final Path root = Files.createTempDirectory("test");
+        final Path foo = root.resolve("foo");
+        final Path bar = root.resolve("bar");
+        final Path baz = root.resolve("baz");
+
+        Files.createDirectory(foo);
+        Files.createDirectory(bar);
+        Files.createDirectory(baz);
+
+        final WatchService watcher = root.getFileSystem().newWatchService();
+        final WatchKey fooKey = foo.register(watcher, ENTRY_CREATE);
+        final WatchKey barKey = bar.register(watcher, ENTRY_CREATE);
+
+        new Thread() {
+            { setDaemon(true); }
+
+            @Override
+            public void run() {
+                while (true) {
+                    try {
+                        final Path temp = Files.createTempFile(foo, "temp", ".tmp");
+                        Files.delete(temp);
+                        Thread.sleep(10);
+                    } catch (IOException | InterruptedException e) {
+                        throw new RuntimeException(e);
+                    }
+                }
+            }
+        }.start();
+
+        new Thread() {
+            { setDaemon(true); }
+
+            @Override
+            public void run() {
+                WatchKey bazKeys[] = new WatchKey[32];
+                while (true) {
+                    try {
+                        for( int i = 0; i < bazKeys.length; i++) {
+                            bazKeys[i] = baz.register(watcher, ENTRY_CREATE);
+                        }
+                        for( int i = 0; i < bazKeys.length; i++) {
+                            bazKeys[i].cancel();
+                        }
+                        Thread.sleep(1);
+                    } catch (IOException | InterruptedException e) {
+                        throw new RuntimeException(e);
+                    }
+                }
+            }
+        }.start();
+
+        long time = System.currentTimeMillis();
+        while ((System.currentTimeMillis() - time) < 15000) {
+            final WatchKey key = watcher.poll(60, TimeUnit.SECONDS);
+            if (key == null) continue;
+
+            if (key != fooKey) {
+                List<WatchEvent<?>> pollEvents = key.pollEvents();
+                for (WatchEvent<?> watchEvent : pollEvents) {
+                    System.out.println(watchEvent.count() + " " +
+                                       watchEvent.kind() + " " +
+                                       watchEvent.context());
+                }
+                throw new RuntimeException("Event received for unexpected key");
+            }
+            key.reset();
+        }
+    }
+}
+
--- a/jdk/test/java/time/tck/java/time/TCKLocalDate.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/test/java/time/tck/java/time/TCKLocalDate.java	Wed Jul 05 21:10:50 2017 +0200
@@ -2157,6 +2157,31 @@
     }
 
     //-----------------------------------------------------------------------
+    // toEpochSecond
+    //-----------------------------------------------------------------------
+    @DataProvider(name="epochSecond")
+    Object[][] provider_toEpochSecond() {
+        return new Object[][] {
+            {LocalDate.of(1858, 11, 17).toEpochSecond(LocalTime.MIDNIGHT, OFFSET_PONE), -3506720400L},
+            {LocalDate.of(1, 1, 1).toEpochSecond(LocalTime.NOON, OFFSET_PONE), -62135557200L},
+            {LocalDate.of(1995, 9, 27).toEpochSecond(LocalTime.of(5, 30), OFFSET_PTWO), 812172600L},
+            {LocalDate.of(1970, 1, 1).toEpochSecond(LocalTime.MIDNIGHT, OFFSET_MTWO), 7200L},
+            {LocalDate.of(-1, 12, 31).toEpochSecond(LocalTime.NOON, OFFSET_PONE), -62167266000L},
+            {LocalDate.of(1, 1, 1).toEpochSecond(LocalTime.MIDNIGHT, OFFSET_PONE),
+                    Instant.ofEpochSecond(-62135600400L).getEpochSecond()},
+            {LocalDate.of(1995, 9, 27).toEpochSecond(LocalTime.NOON, OFFSET_PTWO),
+                    Instant.ofEpochSecond(812196000L).getEpochSecond()},
+            {LocalDate.of(1995, 9, 27).toEpochSecond(LocalTime.of(5, 30), OFFSET_MTWO),
+                    LocalDateTime.of(1995, 9, 27, 5, 30).toEpochSecond(OFFSET_MTWO)},
+        };
+    }
+
+    @Test(dataProvider="epochSecond")
+    public void test_toEpochSecond(long actual, long expected) {
+        assertEquals(actual, expected);
+    }
+
+    //-----------------------------------------------------------------------
     // compareTo()
     //-----------------------------------------------------------------------
     @Test
--- a/jdk/test/java/time/tck/java/time/TCKLocalTime.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/test/java/time/tck/java/time/TCKLocalTime.java	Wed Jul 05 21:10:50 2017 +0200
@@ -2433,6 +2433,32 @@
         }
     }
 
+    //-----------------------------------------------------------------------
+    // toEpochSecond()
+    //--------------------------------------------------------------------------
+    @DataProvider(name="epochSecond")
+    Object[][] provider__toEpochSecond() {
+        return new Object[][] {
+        {LocalTime.of(0, 0).toEpochSecond(LocalDate.of(1970, 1, 1), OFFSET_PTWO), -7200L},
+        {LocalTime.of(11, 30).toEpochSecond(LocalDate.of(1965, 12, 31), OFFSET_PTWO), -126282600L},
+        {LocalTime.of(11, 30).toEpochSecond(LocalDate.of(1995, 5, 3), OFFSET_MTWO), 799507800L},
+        {LocalTime.of(0, 0).toEpochSecond(LocalDate.of(1970, 1, 1), OFFSET_PTWO),
+                Instant.ofEpochSecond(-7200).getEpochSecond()},
+        {LocalTime.of(11, 30).toEpochSecond(LocalDate.of(1969, 12, 31), OFFSET_MTWO),
+                Instant.ofEpochSecond(-37800L).getEpochSecond()},
+        {LocalTime.of(11, 30).toEpochSecond(LocalDate.of(1970, 1, 1), OFFSET_PTWO),
+                LocalDateTime.of(1970, 1, 1, 11, 30).toEpochSecond(OFFSET_PTWO)},
+        };
+    }
+
+    @Test(dataProvider="epochSecond")
+    public void test_toEpochSecond(long actual, long expected) {
+        assertEquals(actual, expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // toSecondOfDay_fromNanoOfDay_symmetry()
+    //-----------------------------------------------------------------------
     @Test
     public void test_toSecondOfDay_fromNanoOfDay_symmetry() {
         LocalTime t = LocalTime.of(0, 0);
--- a/jdk/test/java/time/tck/java/time/TCKOffsetTime.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/test/java/time/tck/java/time/TCKOffsetTime.java	Wed Jul 05 21:10:50 2017 +0200
@@ -134,6 +134,7 @@
     private static final ZoneId ZONE_GAZA = ZoneId.of("Asia/Gaza");
     private static final ZoneOffset OFFSET_PONE = ZoneOffset.ofHours(1);
     private static final ZoneOffset OFFSET_PTWO = ZoneOffset.ofHours(2);
+    private static final ZoneOffset OFFSET_MTWO = ZoneOffset.ofHours(-2);
     private static final LocalDate DATE = LocalDate.of(2008, 12, 3);
     private OffsetTime TEST_11_30_59_500_PONE;
 
@@ -1149,6 +1150,29 @@
     }
 
     //-----------------------------------------------------------------------
+    // toEpochSecond()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="epochSecond")
+    Object[][] provider_toEpochSecond() {
+        return new Object[][] {
+        {OffsetTime.of(0, 0, 0, 0, OFFSET_PTWO).toEpochSecond(LocalDate.of(1970, 1, 1)), -7200L},
+        {OffsetTime.of(11, 30, 0, 0, OFFSET_MTWO).toEpochSecond(LocalDate.of(1995, 9, 27)), 812208600L},
+        {OffsetTime.of(0, 0, 0, 0, OFFSET_PONE).toEpochSecond(LocalDate.of(1970, 1, 1)),
+                Instant.ofEpochSecond(-3600).getEpochSecond()},
+        {OffsetTime.of(11, 30, 0, 0, OFFSET_PTWO).toEpochSecond(LocalDate.of(1965, 12, 31)),
+                Instant.ofEpochSecond(-126282600L).getEpochSecond()},
+        {OffsetTime.of(11, 30, 0, 0, OFFSET_MTWO).toEpochSecond(LocalDate.of(1970, 1, 1)),
+                OffsetDateTime.of(LocalDate.of(1970, 1, 1), LocalTime.of(11, 30), OFFSET_MTWO)
+                              .toEpochSecond()},
+        };
+    }
+
+    @Test(dataProvider="epochSecond")
+    public void test_toEpochSecond(long actual, long expected) {
+        assertEquals(actual, expected);
+    }
+
+    //-----------------------------------------------------------------------
     // compareTo()
     //-----------------------------------------------------------------------
     @Test
--- a/jdk/test/java/time/tck/java/time/TCKZonedDateTime.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/test/java/time/tck/java/time/TCKZonedDateTime.java	Wed Jul 05 21:10:50 2017 +0200
@@ -751,7 +751,7 @@
                 {"2012-06-30T12:30:40Z[GMT]", 2012, 6, 30, 12, 30, 40, 0, "GMT"},
                 {"2012-06-30T12:30:40Z[UT]", 2012, 6, 30, 12, 30, 40, 0, "UT"},
                 {"2012-06-30T12:30:40Z[UTC]", 2012, 6, 30, 12, 30, 40, 0, "UTC"},
-                {"2012-06-30T12:30:40+01:00[Z]", 2012, 6, 30, 12, 30, 40, 0, "Z"},
+                {"2012-06-30T12:30:40+01:00[Z]", 2012, 6, 30, 11, 30, 40, 0, "Z"},
                 {"2012-06-30T12:30:40+01:00[+01:00]", 2012, 6, 30, 12, 30, 40, 0, "+01:00"},
                 {"2012-06-30T12:30:40+01:00[GMT+01:00]", 2012, 6, 30, 12, 30, 40, 0, "GMT+01:00"},
                 {"2012-06-30T12:30:40+01:00[UT+01:00]", 2012, 6, 30, 12, 30, 40, 0, "UT+01:00"},
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/format/TCKDTFParsedInstant.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package tck.java.time.format;
+
+import static org.testng.AssertJUnit.assertEquals;
+
+import java.time.LocalDateTime;
+import java.time.OffsetDateTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Testing DateTimeFormatter Parsing with 4 different test conditions:
+ * 1. When Zone and Offset not provided
+ * 2. When Zone and Offset provided
+ * 3. When Offset is not provided and Zone is provided
+ * 4. When Zone is not provided and Offset is provided
+ */
+
+@Test
+public class TCKDTFParsedInstant {
+
+    private static final ZoneId EUROPE_BERLIN = ZoneId.of("Europe/Berlin");
+    private static final ZoneId ASIA_ISTANBUL = ZoneId.of("Asia/Istanbul");
+
+    private DateTimeFormatter dtFormatter;
+    private ZonedDateTime zdt1, zdt2;
+    private LocalDateTime ldt1;
+    private OffsetDateTime odt1;
+
+    @BeforeMethod
+    public void setUp() throws Exception {
+        dtFormatter = DateTimeFormatter.ISO_ZONED_DATE_TIME;
+    }
+
+    @DataProvider(name="parseWithoutZoneWithoutOffset")
+    Object[][] data_parse_WithoutOffset_WithoutZone() {
+        return new Object[][] {
+            {"1966-12-31T00:01:10", LocalDateTime.of(1966, 12, 31, 0, 1, 10)},
+            {"1970-01-01T00:00:00", LocalDateTime.of(1970, 1, 1, 0, 0, 0)},
+            {"2004-02-29T00:30:00", LocalDateTime.of(2004, 2, 29, 0, 30, 0)},
+            {"2015-12-31T23:59:59", LocalDateTime.of(2015, 12, 31, 23, 59, 59)}
+        };
+    }
+
+    @Test(dataProvider="parseWithoutZoneWithoutOffset")
+    public void testWithoutZoneWithoutOffset(String ldtString, LocalDateTime expectedLDT) {
+        dtFormatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
+        ldt1 = LocalDateTime.parse(ldtString, dtFormatter);
+        assertEquals(expectedLDT, ldt1);
+    }
+
+    @DataProvider(name="parseWithZoneWithOffset")
+    Object[][] data_parse_WithZone_WithOffset() {
+        return new Object[][] {
+            {"2012-10-28T01:45:00-02:30[Europe/Berlin]",
+                LocalDateTime.of(2012, 10, 28, 1, 45, 0, 0), ZoneOffset.of("-02:30"), EUROPE_BERLIN},
+            {"2012-10-28T01:45:00-01:00[Europe/Berlin]",
+                LocalDateTime.of(2012, 10, 28, 1, 45, 0, 0), ZoneOffset.of("-01:00"), EUROPE_BERLIN},
+            {"2012-10-28T01:45:00-00:00[Europe/Berlin]",
+                LocalDateTime.of(2012, 10, 28, 1, 45, 0, 0), ZoneOffset.of("-00:00"), EUROPE_BERLIN},
+            {"2012-10-28T01:45:00+00:00[Europe/Berlin]",
+                LocalDateTime.of(2012, 10, 28, 1, 45, 0, 0), ZoneOffset.of("+00:00"), EUROPE_BERLIN},
+            {"2012-10-28T01:45:00+01:00[Europe/Berlin]",
+                LocalDateTime.of(2012, 10, 28, 1, 45, 0, 0), ZoneOffset.of("+01:00"), EUROPE_BERLIN},
+            {"2012-10-28T01:45:00+02:00[Europe/Berlin]",
+                LocalDateTime.of(2012, 10, 28, 1, 45, 0, 0), ZoneOffset.of("+02:00"), EUROPE_BERLIN},
+            {"2012-10-28T01:45:00+03:00[Europe/Berlin]",
+                LocalDateTime.of(2012, 10, 28, 1, 45, 0, 0), ZoneOffset.of("+03:00"), EUROPE_BERLIN},
+            {"2012-10-28T02:45:00-02:30[Europe/Berlin]",
+                LocalDateTime.of(2012, 10, 28, 2, 45, 0, 0), ZoneOffset.of("-02:30"), EUROPE_BERLIN},
+            {"2012-10-28T02:45:00-01:00[Europe/Berlin]",
+                LocalDateTime.of(2012, 10, 28, 2, 45, 0, 0), ZoneOffset.of("-01:00"), EUROPE_BERLIN},
+            {"2012-10-28T02:45:00-00:00[Europe/Berlin]",
+                LocalDateTime.of(2012, 10, 28, 2, 45, 0, 0), ZoneOffset.of("-00:00"), EUROPE_BERLIN},
+            {"2012-10-28T02:45:00+00:00[Europe/Berlin]",
+                LocalDateTime.of(2012, 10, 28, 2, 45, 0, 0), ZoneOffset.of("+00:00"), EUROPE_BERLIN},
+            {"2012-10-28T02:45:00+01:00[Europe/Berlin]",
+                LocalDateTime.of(2012, 10, 28, 2, 45, 0, 0), ZoneOffset.of("+01:00"), EUROPE_BERLIN},
+            {"2012-10-28T02:45:00+02:00[Europe/Berlin]",
+                LocalDateTime.of(2012, 10, 28, 2, 45, 0, 0), ZoneOffset.of("+02:00"), EUROPE_BERLIN},
+            {"2012-10-28T02:45:00+03:00[Europe/Berlin]",
+                LocalDateTime.of(2012, 10, 28, 2, 45, 0, 0), ZoneOffset.of("+03:00"), EUROPE_BERLIN},
+            {"2012-10-28T03:45:00-02:30[Europe/Berlin]",
+                LocalDateTime.of(2012, 10, 28, 3, 45, 0, 0), ZoneOffset.of("-02:30"), EUROPE_BERLIN},
+            {"2012-10-28T03:45:00-01:00[Europe/Berlin]",
+                LocalDateTime.of(2012, 10, 28, 3, 45, 0, 0), ZoneOffset.of("-01:00"), EUROPE_BERLIN},
+            {"2012-10-28T03:45:00-00:00[Europe/Berlin]",
+                LocalDateTime.of(2012, 10, 28, 3, 45, 0, 0), ZoneOffset.of("-00:00"), EUROPE_BERLIN},
+            {"2012-10-28T03:45:00+00:00[Europe/Berlin]",
+                LocalDateTime.of(2012, 10, 28, 3, 45, 0, 0), ZoneOffset.of("+00:00"), EUROPE_BERLIN},
+            {"2012-10-28T03:45:00+01:00[Europe/Berlin]",
+                LocalDateTime.of(2012, 10, 28, 3, 45, 0, 0), ZoneOffset.of("+01:00"), EUROPE_BERLIN},
+            {"2012-10-28T03:45:00+02:00[Europe/Berlin]",
+                LocalDateTime.of(2012, 10, 28, 3, 45, 0, 0), ZoneOffset.of("+02:00"), EUROPE_BERLIN},
+            {"2012-10-28T03:45:00+03:00[Europe/Berlin]",
+                LocalDateTime.of(2012, 10, 28, 3, 45, 0, 0), ZoneOffset.of("+03:00"), EUROPE_BERLIN},
+
+            {"2012-10-28T02:45:00-02:30[Asia/Istanbul]",
+                LocalDateTime.of(2012, 10, 28, 2, 45, 0, 0), ZoneOffset.of("-02:30"), ASIA_ISTANBUL},
+            {"2012-10-28T02:45:00-01:00[Asia/Istanbul]",
+                LocalDateTime.of(2012, 10, 28, 2, 45, 0, 0), ZoneOffset.of("-01:00"), ASIA_ISTANBUL},
+            {"2012-10-28T02:45:00-00:00[Asia/Istanbul]",
+                LocalDateTime.of(2012, 10, 28, 2, 45, 0, 0), ZoneOffset.of("-00:00"), ASIA_ISTANBUL},
+            {"2012-10-28T02:45:00+00:00[Asia/Istanbul]",
+                LocalDateTime.of(2012, 10, 28, 2, 45, 0, 0), ZoneOffset.of("+00:00"), ASIA_ISTANBUL},
+            {"2012-10-28T02:45:00+01:00[Asia/Istanbul]",
+                LocalDateTime.of(2012, 10, 28, 2, 45, 0, 0), ZoneOffset.of("+01:00"), ASIA_ISTANBUL},
+            {"2012-10-28T02:45:00+02:00[Asia/Istanbul]",
+                LocalDateTime.of(2012, 10, 28, 2, 45, 0, 0), ZoneOffset.of("+02:00"), ASIA_ISTANBUL},
+            {"2012-10-28T02:45:00+03:00[Asia/Istanbul]",
+                LocalDateTime.of(2012, 10, 28, 2, 45, 0, 0), ZoneOffset.of("+03:00"), ASIA_ISTANBUL},
+            {"2012-10-28T03:45:00-02:30[Asia/Istanbul]",
+                LocalDateTime.of(2012, 10, 28, 3, 45, 0, 0), ZoneOffset.of("-02:30"), ASIA_ISTANBUL},
+            {"2012-10-28T03:45:00-01:00[Asia/Istanbul]",
+                LocalDateTime.of(2012, 10, 28, 3, 45, 0, 0), ZoneOffset.of("-01:00"), ASIA_ISTANBUL},
+            {"2012-10-28T03:45:00-00:00[Asia/Istanbul]",
+                LocalDateTime.of(2012, 10, 28, 3, 45, 0, 0), ZoneOffset.of("-00:00"), ASIA_ISTANBUL},
+            {"2012-10-28T03:45:00+00:00[Asia/Istanbul]",
+                LocalDateTime.of(2012, 10, 28, 3, 45, 0, 0), ZoneOffset.of("+00:00"), ASIA_ISTANBUL},
+            {"2012-10-28T03:45:00+01:00[Asia/Istanbul]",
+                LocalDateTime.of(2012, 10, 28, 3, 45, 0, 0), ZoneOffset.of("+01:00"), ASIA_ISTANBUL},
+            {"2012-10-28T03:45:00+02:00[Asia/Istanbul]",
+                LocalDateTime.of(2012, 10, 28, 3, 45, 0, 0), ZoneOffset.of("+02:00"), ASIA_ISTANBUL},
+            {"2012-10-28T03:45:00+03:00[Asia/Istanbul]",
+                LocalDateTime.of(2012, 10, 28, 3, 45, 0, 0), ZoneOffset.of("+03:00"), ASIA_ISTANBUL},
+            {"2012-10-28T04:45:00-02:30[Asia/Istanbul]",
+                LocalDateTime.of(2012, 10, 28, 4, 45, 0, 0), ZoneOffset.of("-02:30"), ASIA_ISTANBUL},
+            {"2012-10-28T04:45:00-01:00[Asia/Istanbul]",
+                LocalDateTime.of(2012, 10, 28, 4, 45, 0, 0), ZoneOffset.of("-01:00"), ASIA_ISTANBUL},
+            {"2012-10-28T04:45:00-00:00[Asia/Istanbul]",
+                LocalDateTime.of(2012, 10, 28, 4, 45, 0, 0), ZoneOffset.of("-00:00"), ASIA_ISTANBUL},
+            {"2012-10-28T04:45:00+00:00[Asia/Istanbul]",
+                LocalDateTime.of(2012, 10, 28, 4, 45, 0, 0), ZoneOffset.of("+00:00"), ASIA_ISTANBUL},
+            {"2012-10-28T04:45:00+01:00[Asia/Istanbul]",
+                LocalDateTime.of(2012, 10, 28, 4, 45, 0, 0), ZoneOffset.of("+01:00"), ASIA_ISTANBUL},
+            {"2012-10-28T04:45:00+02:00[Asia/Istanbul]",
+                LocalDateTime.of(2012, 10, 28, 4, 45, 0, 0), ZoneOffset.of("+02:00"), ASIA_ISTANBUL},
+            {"2012-10-28T04:45:00+03:00[Asia/Istanbul]",
+                LocalDateTime.of(2012, 10, 28, 4, 45, 0, 0), ZoneOffset.of("+03:00"), ASIA_ISTANBUL}
+        };
+    }
+
+    @Test(dataProvider="parseWithZoneWithOffset")
+    public void testWithZoneWithOffset(String zdtString, LocalDateTime ldt, ZoneOffset offset, ZoneId zone) {
+        dtFormatter = DateTimeFormatter.ISO_ZONED_DATE_TIME;
+        zdt1 = ZonedDateTime.ofInstant(ldt, offset, zone);
+        zdt2 = ZonedDateTime.parse(zdtString, dtFormatter);
+        assertEquals(zdt1, zdt2);
+    }
+
+    @DataProvider(name="parseWithZoneWithoutOffset")
+    Object[][] data_parse_WithZone_WithoutOffset() {
+        return new Object[][] {
+            {"28 Oct 00:45:00 2012 Europe/Berlin", ZonedDateTime.of(2012, 10, 28, 0, 45, 0, 0, EUROPE_BERLIN)},
+            {"28 Oct 01:45:00 2012 Europe/Berlin", ZonedDateTime.of(2012, 10, 28, 1, 45, 0, 0, EUROPE_BERLIN)},
+            {"28 Oct 02:45:00 2012 Europe/Berlin", ZonedDateTime.of(2012, 10, 28, 2, 45, 0, 0, EUROPE_BERLIN)},
+            {"28 Oct 03:45:00 2012 Europe/Berlin", ZonedDateTime.of(2012, 10, 28, 3, 45, 0, 0, EUROPE_BERLIN)},
+            {"28 Oct 04:45:00 2012 Europe/Berlin", ZonedDateTime.of(2012, 10, 28, 4, 45, 0, 0, EUROPE_BERLIN)},
+
+            {"28 Oct 01:45:00 2012 Asia/Istanbul", ZonedDateTime.of(2012, 10, 28, 1, 45, 0, 0, ASIA_ISTANBUL)},
+            {"28 Oct 02:45:00 2012 Asia/Istanbul", ZonedDateTime.of(2012, 10, 28, 2, 45, 0, 0, ASIA_ISTANBUL)},
+            {"28 Oct 03:45:00 2012 Asia/Istanbul", ZonedDateTime.of(2012, 10, 28, 3, 45, 0, 0, ASIA_ISTANBUL)},
+            {"28 Oct 04:45:00 2012 Asia/Istanbul", ZonedDateTime.of(2012, 10, 28, 4, 45, 0, 0, ASIA_ISTANBUL)},
+            {"28 Oct 05:45:00 2012 Asia/Istanbul", ZonedDateTime.of(2012, 10, 28, 5, 45, 0, 0, ASIA_ISTANBUL)}
+        };
+    }
+
+    @Test(dataProvider="parseWithZoneWithoutOffset")
+    public void testWithZoneWithoutOffset(String withZoneWithoutOffset, ZonedDateTime expectedZDT) {
+        dtFormatter = DateTimeFormatter.ofPattern("d MMM HH:mm:ss uuuu VV");
+        zdt1 = ZonedDateTime.parse(withZoneWithoutOffset, dtFormatter);
+        assertEquals(expectedZDT, zdt1);
+    }
+
+    @DataProvider(name="parseWithOffsetWithoutZone")
+    Object[][] data_parse_WithOffset_WithoutZone() {
+        return new Object[][] {
+            {"2015-12-14T00:45:00-11:30", OffsetDateTime.of(2015, 12, 14, 0, 45, 0, 0, ZoneOffset.of("-11:30"))},
+            {"2015-12-14T01:45:00-05:00", OffsetDateTime.of(2015, 12, 14, 1, 45, 0, 0, ZoneOffset.of("-05:00"))},
+            {"2015-12-14T02:45:00-00:00", OffsetDateTime.of(2015, 12, 14, 2, 45, 0, 0, ZoneOffset.of("-00:00"))},
+            {"2015-12-14T03:45:00+00:00", OffsetDateTime.of(2015, 12, 14, 3, 45, 0, 0, ZoneOffset.of("+00:00"))},
+            {"2015-12-14T04:45:00+03:30", OffsetDateTime.of(2015, 12, 14, 4, 45, 0, 0, ZoneOffset.of("+03:30"))},
+            {"2015-12-14T05:45:00+10:00", OffsetDateTime.of(2015, 12, 14, 5, 45, 0, 0, ZoneOffset.of("+10:00"))}
+        };
+    }
+
+    @Test(dataProvider="parseWithOffsetWithoutZone")
+    public void testWithOffsetWithoutZone(String odtString, OffsetDateTime expectedOTD) {
+        dtFormatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
+        odt1 = OffsetDateTime.parse(odtString, dtFormatter);
+        assertEquals(expectedOTD, odt1);
+    }
+}
--- a/jdk/test/java/util/Formatter/Basic-X.java.template	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/test/java/util/Formatter/Basic-X.java.template	Wed Jul 05 21:10:50 2017 +0200
@@ -36,7 +36,7 @@
 import java.text.DateFormatSymbols;
 import java.util.*;
 #if[double]
-import sun.misc.DoubleConsts;
+import jdk.internal.math.DoubleConsts;
 #end[double]
 
 import static java.util.Calendar.*;
--- a/jdk/test/java/util/Formatter/Basic.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/test/java/util/Formatter/Basic.java	Wed Jul 05 21:10:50 2017 +0200
@@ -28,7 +28,7 @@
  *      6344623 6369500 6534606 6282094 6286592 6476425 5063507 6469160 6476168
  *      8059175
  *
- * @modules java.base/sun.misc
+ * @modules java.base/jdk.internal.math
  * @run shell/timeout=240 Basic.sh
  */
 
--- a/jdk/test/java/util/Formatter/BasicDouble.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/test/java/util/Formatter/BasicDouble.java	Wed Jul 05 21:10:50 2017 +0200
@@ -36,7 +36,7 @@
 import java.text.DateFormatSymbols;
 import java.util.*;
 
-import sun.misc.DoubleConsts;
+import jdk.internal.math.DoubleConsts;
 
 
 import static java.util.Calendar.*;
@@ -1174,6 +1174,10 @@
 
 
 
+
+
+
+
         //---------------------------------------------------------------------
         // %f - float, double, Double, BigDecimal
         //---------------------------------------------------------------------
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/imageio/plugins/jpeg/JpegImageColorSpaceTest.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug     8041501
+ * @summary Test verifies if there is no JFIF & EXIF header
+ *          and sampling factor is same of JPEG image, then
+ *          imageIO should not override colorspace determined
+ *          in IJG library.
+ * @run     main JpegImageColorSpaceTest
+ */
+
+import java.awt.Color;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import javax.imageio.ImageIO;
+
+public class JpegImageColorSpaceTest {
+
+    public static void main(String args[]) throws Exception {
+
+        String fileName = "nomarkers.jpg";
+        String sep = System.getProperty("file.separator");
+        String dir = System.getProperty("test.src", ".");
+        String filePath = dir+sep+fileName;
+        System.out.println("Test file: " + filePath);
+        File imageFile = new File(filePath);
+
+        BufferedImage bufferedImage = ImageIO.read(imageFile);
+        int imageWidth = bufferedImage.getWidth();
+        int imageHeight = bufferedImage.getHeight();
+
+        for (int i = 0; i < imageWidth; i++) {
+            for(int j = 0; j < imageHeight; j++) {
+                /*
+                * Since image is white we check individual pixel values from
+                * BufferedImage to verify if ImageIO.read() is done with proper
+                * color space or not.
+                */
+                if (bufferedImage.getRGB(i, j) != Color.white.getRGB()) {
+                    // color space is not proper
+                    throw new RuntimeException("ColorSpace is not determined "
+                            + "properly by ImageIO");
+               }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/imageio/plugins/jpeg/JpegMetadataColorSpaceTest.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug     8074967
+ * @summary Test verifies if there is no JFIF & EXIF header
+ *          and sampling factor is same of JPEG image, then
+ *          JPEG colorspace should not be RGB.
+ * @run     main JpegMetadataColorSpaceTest
+ */
+
+import javax.imageio.ImageIO;
+import javax.imageio.ImageReader;
+import javax.imageio.metadata.IIOMetadata;
+import javax.imageio.metadata.IIOMetadataFormatImpl;
+import javax.imageio.metadata.IIOMetadataNode;
+import javax.imageio.stream.ImageInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.util.Iterator;
+
+public class JpegMetadataColorSpaceTest {
+    public static void main(String[] args) throws IOException {
+        String fileName = "nomarkers.jpg";
+        String sep = System.getProperty("file.separator");
+        String dir = System.getProperty("test.src", ".");
+        String filePath = dir+sep+fileName;
+        System.out.println("Test file: " + filePath);
+        File file = new File(filePath);
+        ImageInputStream stream = ImageIO.createImageInputStream(file);
+        Iterator<ImageReader> readers = ImageIO.getImageReaders(stream);
+
+        if(readers.hasNext()) {
+            ImageReader reader = readers.next();
+            reader.setInput(stream);
+            IIOMetadata metadata = reader.getImageMetadata(0);
+
+            IIOMetadataNode standardTree = (IIOMetadataNode)
+                metadata.getAsTree
+                (IIOMetadataFormatImpl.standardMetadataFormatName);
+            IIOMetadataNode colorSpaceType = (IIOMetadataNode)
+                standardTree.getElementsByTagName("ColorSpaceType").item(0);
+            String colorSpaceName = colorSpaceType.getAttribute("name");
+            if(colorSpaceName.equals("RGB"))
+                throw new RuntimeException("Identified incorrect ColorSpace");
+        }
+    }
+}
Binary file jdk/test/javax/imageio/plugins/jpeg/nomarkers.jpg has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/imageio/plugins/png/PngForceStopWritingTest.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug     6967419
+ * @summary Test verifies that when we force stop PNG writing to
+ *          ImageOutputStream, it should not cause IndexOutOfBoundException.
+ * @run     main PngForceStopWritingTest
+ */
+
+import java.awt.Color;
+import java.awt.GradientPaint;
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.io.OutputStream;
+import javax.imageio.ImageIO;
+import javax.imageio.stream.ImageOutputStream;
+
+public class PngForceStopWritingTest {
+
+    public static void main(String[] args) throws IOException {
+
+        OutputStream outputStream = new NullOutputStream();
+        ImageOutputStream imageOutputStream =
+            ImageIO.createImageOutputStream(outputStream);
+        try {
+            ImageIO.write(createImage(2048),"PNG", imageOutputStream);
+        } catch (IOException e) {
+            imageOutputStream.close();
+        }
+    }
+
+    private static BufferedImage createImage(int size) {
+
+        BufferedImage image = new
+            BufferedImage(size, size, BufferedImage.TYPE_3BYTE_BGR);
+        Graphics2D g = image.createGraphics();
+        g.setPaint(new GradientPaint(0, 0, Color.blue, size, size, Color.red));
+        g.fillRect(0, 0, size, size);
+        g.dispose();
+        return image;
+    }
+
+    static class NullOutputStream extends OutputStream {
+        long count = 0;
+        @Override
+        public void write(int b) throws IOException {
+            count++;
+            if (count > 30000L) {
+                throw new IOException("Force stop image writing");
+            }
+        }
+    }
+}
--- a/jdk/test/javax/imageio/plugins/shared/WriteAfterAbort.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/test/javax/imageio/plugins/shared/WriteAfterAbort.java	Wed Jul 05 21:10:50 2017 +0200
@@ -130,13 +130,25 @@
                 ImageWriterSpi.class, provider -> true, true);
 
         // Validates all supported ImageWriters
+        int numFailures = 0;
         while (iter.hasNext()) {
             final WriteAfterAbort writeAfterAbort = new WriteAfterAbort();
             final ImageWriter writer = iter.next().createWriterInstance();
             System.out.println("ImageWriter = " + writer);
-            writeAfterAbort.test(writer);
+            try {
+                writeAfterAbort.test(writer);
+            } catch (Exception e) {
+                System.err.println("Test failed for \""
+                    + writer.getOriginatingProvider().getFormatNames()[0]
+                    + "\" format.");
+                numFailures++;
+            }
         }
-        System.out.println("Test passed");
+        if (numFailures == 0) {
+            System.out.println("Test passed.");
+        } else {
+            throw new RuntimeException("Test failed.");
+        }
     }
 
     // Callbacks
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/imageio/plugins/tiff/WriteToSequenceAfterAbort.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,376 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import javax.imageio.ImageIO;
+import javax.imageio.ImageWriter;
+import javax.imageio.event.IIOWriteProgressListener;
+import javax.imageio.stream.ImageOutputStream;
+
+import static java.awt.image.BufferedImage.TYPE_BYTE_BINARY;
+import java.awt.image.ColorModel;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.awt.image.SampleModel;
+import java.awt.image.WritableRaster;
+import java.util.Vector;
+import javax.imageio.IIOImage;
+import javax.imageio.ImageReader;
+import javax.imageio.stream.ImageInputStream;
+
+/**
+ * @test
+ * @bug 8144245
+ * @summary Ensure aborting write works properly for a TIFF sequence.
+ */
+public final class WriteToSequenceAfterAbort implements IIOWriteProgressListener {
+
+    private volatile boolean abortFlag = true;
+    private volatile boolean isAbortCalled;
+    private volatile boolean isCompleteCalled;
+    private volatile boolean isProgressCalled;
+    private volatile boolean isStartedCalled;
+    private static final int WIDTH = 100;
+    private static final int HEIGHT = 100;
+    private static final int NUM_TILES_XY = 3;
+
+    private class TiledImage implements RenderedImage {
+        private final BufferedImage tile;
+        private final BufferedImage image;
+        private final int numXTiles, numYTiles;
+        private boolean isImageInitialized = false;
+
+        TiledImage(BufferedImage tile, int numXTiles, int numYTiles) {
+            this.tile = tile;
+            this.numXTiles = numXTiles;
+            this.numYTiles = numYTiles;
+            image = new BufferedImage(getWidth(), getHeight(), tile.getType());
+        }
+
+        @Override
+        public Vector<RenderedImage> getSources() {
+            return null;
+        }
+
+        @Override
+        public Object getProperty(String string) {
+            return java.awt.Image.UndefinedProperty;
+        }
+
+        @Override
+        public String[] getPropertyNames() {
+            return new String[0];
+        }
+
+        @Override
+        public ColorModel getColorModel() {
+            return tile.getColorModel();
+        }
+
+        @Override
+        public SampleModel getSampleModel() {
+            return tile.getSampleModel();
+        }
+
+        @Override
+        public int getWidth() {
+            return numXTiles*tile.getWidth();
+        }
+
+        @Override
+        public int getHeight() {
+            return numYTiles*tile.getHeight();
+        }
+
+        @Override
+        public int getMinX() {
+            return 0;
+        }
+
+        @Override
+        public int getMinY() {
+            return 0;
+        }
+
+        @Override
+        public int getNumXTiles() {
+            return numXTiles;
+        }
+
+        @Override
+        public int getNumYTiles() {
+            return numYTiles;
+        }
+
+        @Override
+        public int getMinTileX() {
+            return 0;
+        }
+
+        @Override
+        public int getMinTileY() {
+            return 0;
+        }
+
+        @Override
+        public int getTileWidth() {
+            return tile.getWidth();
+        }
+
+        @Override
+        public int getTileHeight() {
+            return tile.getHeight();
+        }
+
+        @Override
+        public int getTileGridXOffset() {
+            return 0;
+        }
+
+        @Override
+        public int getTileGridYOffset() {
+            return 0;
+        }
+
+        @Override
+        public Raster getTile(int x, int y) {
+            WritableRaster r = tile.getRaster();
+            return r.createWritableTranslatedChild(x*tile.getWidth(),
+                y*tile.getHeight());
+        }
+
+        @Override
+        public Raster getData() {
+            return getAsBufferedImage().getData();
+        }
+
+        @Override
+        public Raster getData(Rectangle r) {
+            return getAsBufferedImage().getData(r);
+        }
+
+        @Override
+        public WritableRaster copyData(WritableRaster wr) {
+            return getAsBufferedImage().copyData(wr);
+        }
+
+        public BufferedImage getAsBufferedImage() {
+            synchronized (image) {
+                if (!isImageInitialized) {
+                    int tx0 = getMinTileX(), ty0 = getMinTileY();
+                    int txN = tx0 + getNumXTiles(), tyN = ty0 + getNumYTiles();
+                    for (int j = ty0; j < tyN; j++) {
+                        for (int i = tx0; i < txN; i++) {
+                            image.setData(getTile(i, j));
+                        }
+                    }
+                }
+                isImageInitialized = true;
+            }
+            return image;
+        }
+    }
+
+    private void test(final ImageWriter writer) throws IOException {
+        String suffix = writer.getOriginatingProvider().getFileSuffixes()[0];
+
+        // Image initialization
+        BufferedImage imageUpperLeft =
+                new BufferedImage(WIDTH, HEIGHT, TYPE_BYTE_BINARY);
+        Graphics2D g = imageUpperLeft.createGraphics();
+        g.setColor(Color.WHITE);
+        g.fillRect(0, 0, WIDTH/2, HEIGHT/2);
+        g.dispose();
+        BufferedImage imageLowerRight =
+                new BufferedImage(WIDTH, HEIGHT, TYPE_BYTE_BINARY);
+        g = imageLowerRight.createGraphics();
+        g.setColor(Color.WHITE);
+        g.fillRect(WIDTH/2, HEIGHT/2, WIDTH/2, HEIGHT/2);
+        g.dispose();
+        TiledImage[] images = new TiledImage[] {
+            new TiledImage(imageUpperLeft, NUM_TILES_XY, NUM_TILES_XY),
+            new TiledImage(imageUpperLeft, NUM_TILES_XY, NUM_TILES_XY),
+            new TiledImage(imageLowerRight, NUM_TILES_XY, NUM_TILES_XY),
+            new TiledImage(imageLowerRight, NUM_TILES_XY, NUM_TILES_XY)
+        };
+
+        // File initialization
+        File file = File.createTempFile("temp", "." + suffix);
+        file.deleteOnExit();
+        FileOutputStream fos = new SkipWriteOnAbortOutputStream(file);
+        ImageOutputStream ios = ImageIO.createImageOutputStream(fos);
+        writer.setOutput(ios);
+        writer.addIIOWriteProgressListener(this);
+
+        writer.prepareWriteSequence(null);
+        boolean[] abortions = new boolean[] {true, false, true, false};
+        for (int i = 0; i < 4; i++) {
+            abortFlag = abortions[i];
+            isAbortCalled = false;
+            isCompleteCalled = false;
+            isProgressCalled = false;
+            isStartedCalled = false;
+
+            TiledImage image = images[i];
+            if (abortFlag) {
+                // This write will be aborted, and file will not be touched
+                writer.writeToSequence(new IIOImage(image, null, null), null);
+                if (!isStartedCalled) {
+                    throw new RuntimeException("Started should be called");
+                }
+                if (!isProgressCalled) {
+                    throw new RuntimeException("Progress should be called");
+                }
+                if (!isAbortCalled) {
+                    throw new RuntimeException("Abort should be called");
+                }
+                if (isCompleteCalled) {
+                    throw new RuntimeException("Complete should not be called");
+                }
+            } else {
+                // This write should be completed successfully and the file should
+                // contain correct image data.
+                writer.writeToSequence(new IIOImage(image, null, null), null);
+                if (!isStartedCalled) {
+                    throw new RuntimeException("Started should be called");
+                }
+                if (!isProgressCalled) {
+                    throw new RuntimeException("Progress should be called");
+                }
+                if (isAbortCalled) {
+                    throw new RuntimeException("Abort should not be called");
+                }
+                if (!isCompleteCalled) {
+                    throw new RuntimeException("Complete should be called");
+                }
+            }
+        }
+
+        writer.endWriteSequence();
+        writer.dispose();
+        ios.close();
+
+        // Validates content of the file.
+        ImageReader reader = ImageIO.getImageReader(writer);
+        ImageInputStream iis = ImageIO.createImageInputStream(file);
+        reader.setInput(iis);
+        for (int i = 0; i < 2; i++) {
+            System.out.println("Testing image " + i);
+            BufferedImage imageRead = reader.read(i);
+            BufferedImage imageWrite = images[2 * i].getAsBufferedImage();
+            for (int x = 0; x < WIDTH; ++x) {
+                for (int y = 0; y < HEIGHT; ++y) {
+                    if (imageRead.getRGB(x, y) != imageWrite.getRGB(x, y)) {
+                        throw new RuntimeException("Test failed for image " + i);
+                    }
+                }
+            }
+        }
+    }
+
+    public static void main(final String[] args) throws IOException {
+        WriteToSequenceAfterAbort writeAfterAbort = new WriteToSequenceAfterAbort();
+        ImageWriter writer = ImageIO.getImageWritersByFormatName("TIFF").next();
+        writeAfterAbort.test(writer);
+        System.out.println("Test passed.");
+    }
+
+    // Callbacks
+
+    @Override
+    public void imageComplete(ImageWriter source) {
+        isCompleteCalled = true;
+    }
+
+    @Override
+    public void imageProgress(ImageWriter source, float percentageDone) {
+        isProgressCalled = true;
+        if (percentageDone > 50 && abortFlag) {
+            source.abort();
+        }
+    }
+
+    @Override
+    public void imageStarted(ImageWriter source, int imageIndex) {
+        isStartedCalled = true;
+    }
+
+    @Override
+    public void writeAborted(final ImageWriter source) {
+        isAbortCalled = true;
+    }
+
+    @Override
+    public void thumbnailComplete(ImageWriter source) {
+    }
+
+    @Override
+    public void thumbnailProgress(ImageWriter source, float percentageDone) {
+    }
+
+    @Override
+    public void thumbnailStarted(ImageWriter source, int imageIndex,
+                                 int thumbnailIndex) {
+    }
+
+    /**
+     * We need to skip writes on abort, because content of the file after abort
+     * is undefined.
+     */
+    private class SkipWriteOnAbortOutputStream extends FileOutputStream {
+
+        SkipWriteOnAbortOutputStream(File file) throws FileNotFoundException {
+            super(file);
+        }
+
+        @Override
+        public void write(int b) throws IOException {
+            if (!abortFlag) {
+                super.write(b);
+            }
+        }
+
+        @Override
+        public void write(byte[] b) throws IOException {
+            if (!abortFlag) {
+                super.write(b);
+            }
+        }
+
+        @Override
+        public void write(byte[] b, int off, int len) throws IOException {
+            if (!abortFlag) {
+                super.write(b, off, len);
+            }
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/imageio/spi/MarkTryFinallyReproducer.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,367 @@
+/*
+ * Copyright 2015 Red Hat, Inc.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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 8144071
+ * @run main/othervm MarkTryFinallyReproducer
+ * @summary Test that call to canDecodeInput in ImageIO don't corrupt
+ *           mark/reset stack in ImageInputStream
+ * @author Jiri Vanek
+ */
+
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.nio.ByteOrder;
+import java.util.Locale;
+import javax.imageio.ImageIO;
+import javax.imageio.ImageReader;
+import javax.imageio.spi.IIORegistry;
+import javax.imageio.spi.ImageReaderSpi;
+import javax.imageio.stream.IIOByteBuffer;
+import javax.imageio.stream.ImageInputStream;
+
+
+public class MarkTryFinallyReproducer {
+
+    private static final byte[] bmp = new byte[]{
+        127,127, 66, 77, -86, 0, 0, 0, 0, 0, 0, 0,
+        122, 0, 0, 0, 108, 0, 0, 0, 4, 0, 0, 0, 4,
+        0, 0, 0, 1, 0, 24, 0, 0, 0, 0, 0, 48, 0, 0,
+        0, 19, 11, 0, 0, 19, 11, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 66, 71, 82, 115, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, -1, -1, -1,
+        -1, -1, -1, 0, -1, 0, -1, -1, -1, -1, 0, 0, 0, -17,
+        0, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, -1, -1, -1,
+        -1, 0, 0, 0, -1, -1, -1, -1, -1, -1, 0, 0, -1
+    };
+    //first two are evil, we are skipping them later. Others are normal BMP
+
+    private static class NotClosingImageInputStream implements ImageInputStream {
+
+        private final ImageInputStream src;
+
+        private NotClosingImageInputStream(ImageInputStream createImageInputStream) {
+            this.src = createImageInputStream;
+        }
+
+        @Override
+        public void setByteOrder(ByteOrder byteOrder) {
+            src.setByteOrder(byteOrder);
+        }
+
+        @Override
+        public ByteOrder getByteOrder() {
+            return src.getByteOrder();
+        }
+
+        @Override
+        public int read() throws IOException {
+            return src.read();
+        }
+
+        @Override
+        public int read(byte[] b) throws IOException {
+            return src.read(b);
+        }
+
+        @Override
+        public int read(byte[] b, int off, int len) throws IOException {
+            return src.read(b, off, len);
+        }
+
+        @Override
+        public void readBytes(IIOByteBuffer buf, int len) throws IOException {
+            src.readBytes(buf, len);
+        }
+
+        @Override
+        public boolean readBoolean() throws IOException {
+            return src.readBoolean();
+        }
+
+        @Override
+        public byte readByte() throws IOException {
+            return src.readByte();
+        }
+
+        @Override
+        public int readUnsignedByte() throws IOException {
+            return src.readUnsignedByte();
+        }
+
+        @Override
+        public short readShort() throws IOException {
+            return src.readShort();
+        }
+
+        @Override
+        public int readUnsignedShort() throws IOException {
+            return src.readUnsignedShort();
+        }
+
+        @Override
+        public char readChar() throws IOException {
+            return src.readChar();
+        }
+
+        @Override
+        public int readInt() throws IOException {
+            return src.readInt();
+        }
+
+        @Override
+        public long readUnsignedInt() throws IOException {
+            return src.readUnsignedInt();
+        }
+
+        @Override
+        public long readLong() throws IOException {
+            return src.readLong();
+        }
+
+        @Override
+        public float readFloat() throws IOException {
+            return src.readFloat();
+        }
+
+        @Override
+        public double readDouble() throws IOException {
+            return src.readDouble();
+        }
+
+        @Override
+        public String readLine() throws IOException {
+            return src.readLine();
+        }
+
+        @Override
+        public String readUTF() throws IOException {
+            return src.readUTF();
+        }
+
+        @Override
+        public void readFully(byte[] b, int off, int len) throws IOException {
+            src.readFully(b, off, len);
+        }
+
+        @Override
+        public void readFully(byte[] b) throws IOException {
+            src.readFully(b);
+        }
+
+        @Override
+        public void readFully(short[] s, int off, int len) throws IOException {
+            src.readFully(s, off, len);
+        }
+
+        @Override
+        public void readFully(char[] c, int off, int len) throws IOException {
+            src.readFully(c, off, len);
+        }
+
+        @Override
+        public void readFully(int[] i, int off, int len) throws IOException {
+            src.readFully(i, off, len);
+        }
+
+        @Override
+        public void readFully(long[] l, int off, int len) throws IOException {
+            src.readFully(l, off, len);
+        }
+
+        @Override
+        public void readFully(float[] f, int off, int len) throws IOException {
+            src.readFully(f, off, len);
+        }
+
+        @Override
+        public void readFully(double[] d, int off, int len) throws IOException {
+            src.readFully(d, off, len);
+        }
+
+        @Override
+        public long getStreamPosition() throws IOException {
+            return src.getStreamPosition();
+        }
+
+        @Override
+        public int getBitOffset() throws IOException {
+            return src.getBitOffset();
+        }
+
+        @Override
+        public void setBitOffset(int bitOffset) throws IOException {
+            src.setBitOffset(bitOffset);
+        }
+
+        @Override
+        public int readBit() throws IOException {
+            return src.readBit();
+        }
+
+        @Override
+        public long readBits(int numBits) throws IOException {
+            return src.readBits(numBits);
+        }
+
+        @Override
+        public long length() throws IOException {
+            return src.length();
+        }
+
+        @Override
+        public int skipBytes(int n) throws IOException {
+            return src.skipBytes(n);
+        }
+
+        @Override
+        public long skipBytes(long n) throws IOException {
+            return src.skipBytes(n);
+        }
+
+        @Override
+        public void seek(long pos) throws IOException {
+            src.seek(pos);
+        }
+
+        @Override
+        public void mark() {
+            src.mark();
+        }
+
+        @Override
+        public void reset() throws IOException {
+            src.reset();
+        }
+
+        @Override
+        public void flushBefore(long pos) throws IOException {
+            src.flushBefore(pos);
+        }
+
+        @Override
+        public void flush() throws IOException {
+            src.flush();
+        }
+
+        @Override
+        public long getFlushedPosition() {
+            return src.getFlushedPosition();
+        }
+
+        @Override
+        public boolean isCached() {
+            return src.isCached();
+        }
+
+        @Override
+        public boolean isCachedMemory() {
+            return src.isCachedMemory();
+        }
+
+        @Override
+        public boolean isCachedFile() {
+            return src.isCachedFile();
+        }
+
+        @Override
+        public void close() throws IOException {
+            //the only important one. nothing
+        }
+    }
+
+    static final String readerClassName
+            = MarkTryFinallyReproducerSpi.class.getName();
+    static final String[] localNames = {"myNames"};
+    static final String[] localSuffixes = {"mySuffixes"};
+    static final String[] localMIMETypes = {"myMimes"};
+
+    public static class MarkTryFinallyReproducerSpi extends ImageReaderSpi {
+
+        public MarkTryFinallyReproducerSpi() {
+            super("MarkTryFinallyReproducerSpi",
+                    "1.0",
+                    localNames,
+                    localSuffixes,
+                    localMIMETypes,
+                    readerClassName,
+                    new Class[]{ImageInputStream.class},
+                    new String[0],
+                    false,
+                    null,
+                    null,
+                    new String[0],
+                    new String[0],
+                    false,
+                    null,
+                    null,
+                    new String[0],
+                    new String[0]);
+        }
+
+        @Override
+        public String getDescription(Locale locale) {
+            return "";
+        }
+
+        @Override
+        public boolean canDecodeInput(Object input) throws IOException {
+            throw new IOException("Bad luck");
+        }
+
+        @Override
+        public ImageReader createReaderInstance(Object extension) {
+            return null;
+        }
+    }
+
+    public static void main(String[] args) throws IOException {
+        MarkTryFinallyReproducerSpi spi = new MarkTryFinallyReproducerSpi();
+        IIORegistry.getDefaultInstance().registerServiceProvider(spi);
+
+        ImageInputStream iis1 =
+          new NotClosingImageInputStream(ImageIO.createImageInputStream(new ByteArrayInputStream(bmp)));
+        iis1.readByte();
+        iis1.mark();
+        long p1 = iis1.getStreamPosition();
+        iis1.readByte();
+        iis1.mark();
+        long p2 = iis1.getStreamPosition();
+        BufferedImage bi1 = ImageIO.read(iis1);
+        iis1.reset();
+        long pn2 = iis1.getStreamPosition();
+        iis1.reset();
+        long pn1 = iis1.getStreamPosition();
+        if (p1 != pn1 || p2!= pn2) {
+            throw new RuntimeException("Exception from call to canDecodeInput in ImageIO. " +
+                                       "Corrupted stack in ImageInputStream");
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/MBeanServer/ExceptionFactory.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.util.ArrayList;
+import javax.management.AttributeNotFoundException;
+import javax.management.BadAttributeValueExpException;
+import javax.management.BadBinaryOpValueExpException;
+import javax.management.BadStringOperationException;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.IntrospectionException;
+import javax.management.InvalidApplicationException;
+import javax.management.InvalidAttributeValueException;
+import javax.management.JMException;
+import javax.management.JMRuntimeException;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MBeanRegistrationException;
+import javax.management.MalformedObjectNameException;
+import javax.management.NotCompliantMBeanException;
+import javax.management.OperationsException;
+import javax.management.ReflectionException;
+import javax.management.RuntimeErrorException;
+import javax.management.RuntimeMBeanException;
+import javax.management.RuntimeOperationsException;
+import javax.management.ServiceNotFoundException;
+import javax.management.StringValueExp;
+import javax.management.modelmbean.InvalidTargetObjectTypeException;
+import javax.management.modelmbean.XMLParseException;
+import javax.management.monitor.MonitorSettingException;
+import javax.management.openmbean.InvalidKeyException;
+import javax.management.openmbean.InvalidOpenTypeException;
+import javax.management.openmbean.KeyAlreadyExistsException;
+import javax.management.openmbean.OpenDataException;
+import javax.management.relation.InvalidRelationIdException;
+import javax.management.relation.InvalidRelationServiceException;
+import javax.management.relation.InvalidRelationTypeException;
+import javax.management.relation.InvalidRoleInfoException;
+import javax.management.relation.InvalidRoleValueException;
+import javax.management.relation.RelationException;
+import javax.management.relation.RelationNotFoundException;
+import javax.management.relation.RelationServiceNotRegisteredException;
+import javax.management.relation.RelationTypeNotFoundException;
+import javax.management.relation.RoleInfoNotFoundException;
+import javax.management.relation.RoleNotFoundException;
+import javax.management.remote.JMXProviderException;
+import javax.management.remote.JMXServerErrorException;
+
+/**
+ *  |----- Original Description Coming From Tonga Original Source Code -------|
+ *  |                                                                         |
+ *  | That class creates an ArrayList and fill it with an instance of each of |
+ *  | the Exception class of the JMX API.                                     |
+ *  | It's dedicated to use by ExceptionTest.                                 |
+ *  |-------------------------------------------------------------------------|
+ */
+public class ExceptionFactory {
+
+    public static final ArrayList<Exception> exceptions =
+            new ArrayList<Exception>();
+
+    static {
+        String mes = "SQE";
+        exceptions.add(new AttributeNotFoundException());
+        exceptions.add(new BadAttributeValueExpException(mes));
+        exceptions.add(new BadBinaryOpValueExpException(new StringValueExp(mes)));
+        exceptions.add(new BadStringOperationException(mes));
+        exceptions.add(new InstanceAlreadyExistsException());
+        exceptions.add(new InstanceNotFoundException());
+        exceptions.add(new IntrospectionException());
+        exceptions.add(new InvalidApplicationException(mes));
+        exceptions.add(new InvalidAttributeValueException());
+        exceptions.add(new JMException());
+        exceptions.add(new JMRuntimeException());
+        exceptions.add(new ListenerNotFoundException());
+        exceptions.add(new MalformedObjectNameException());
+        exceptions.add(new MBeanException(new Exception(mes), mes));
+        exceptions.add(new MBeanRegistrationException(new Exception(mes), mes));
+        exceptions.add(new NotCompliantMBeanException());
+        exceptions.add(new OperationsException());
+        exceptions.add(new ReflectionException(new Exception(mes), mes));
+        exceptions.add(new RuntimeErrorException(new Error(mes), mes));
+        exceptions.add(new RuntimeMBeanException(new RuntimeException(mes), mes));
+        exceptions.add(new RuntimeOperationsException(new RuntimeException(mes), mes));
+        exceptions.add(new ServiceNotFoundException());
+        exceptions.add(new InvalidTargetObjectTypeException());
+        exceptions.add(new XMLParseException());
+        exceptions.add(new MonitorSettingException());
+        exceptions.add(new InvalidKeyException());
+        exceptions.add(new InvalidOpenTypeException());
+        exceptions.add(new KeyAlreadyExistsException());
+        exceptions.add(new OpenDataException());
+        exceptions.add(new InvalidRelationIdException());
+        exceptions.add(new InvalidRelationServiceException());
+        exceptions.add(new InvalidRelationTypeException());
+        exceptions.add(new InvalidRoleInfoException());
+        exceptions.add(new InvalidRoleValueException());
+        exceptions.add(new RelationException());
+        exceptions.add(new RelationNotFoundException());
+        exceptions.add(new RelationServiceNotRegisteredException());
+        exceptions.add(new RelationTypeNotFoundException());
+        exceptions.add(new RoleInfoNotFoundException());
+        exceptions.add(new RoleNotFoundException());
+        exceptions.add(new JMXProviderException());
+        exceptions.add(new JMXServerErrorException(mes, new Error(mes)));
+        ExceptionTest.Utils.debug(ExceptionTest.Utils.DEBUG_STANDARD,
+                "DataFactory::updateMap: Initialized" +
+                " an ArrayList with the " +
+                exceptions.size() + " exceptions of the JMX API");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/MBeanServer/ExceptionTest.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,372 @@
+/*
+ * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8058865
+ * @summary Checks that exceptions are correctly wired (compared to reference).
+ * @author Olivier Lagneau
+ * @modules java.management
+ * @run main/othervm/timeout=300 -DDEBUG_STANDARD ExceptionTest
+ */
+
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Properties;
+import java.lang.reflect.Method;
+
+import java.lang.management.ManagementFactory;
+import javax.management.ObjectName;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+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 ExceptionTest {
+
+    /*
+     * First Debug properties and arguments are collect in expected
+     * map  (argName, value) format, then calls original test's run method.
+     */
+    public static void main(String args[]) throws Exception {
+
+        System.out.println("=================================================");
+
+        // Parses parameters
+        Utils.parseDebugProperties();
+        Map<String, Object> map = Utils.parseParameters(args) ;
+
+        // Run test
+        ExceptionTest test = new ExceptionTest();
+        test.run(map);
+
+    }
+
+    public void run(Map<String, Object> args) {
+
+        System.out.println("ExceptionTest::run: Start");
+        int errorCount = 0;
+
+        JMXConnectorServer cs = null;
+        JMXConnector cc = null;
+
+        try {
+            // JMX MbeanServer used inside single VM as if remote.
+            MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+
+            JMXServiceURL url = new JMXServiceURL("rmi", null, 0);
+            cs = JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);
+            cs.start();
+
+            JMXServiceURL addr = cs.getAddress();
+            cc = JMXConnectorFactory.connect(addr);
+            MBeanServerConnection mbsc = cc.getMBeanServerConnection();
+
+            // ----
+            ObjectName objName =
+                new ObjectName(ExceptionThrower.EXCEPTION_THROWER_NAME);
+            System.out.println("ExceptionTest::run: Create and register MBean " + objName);
+            mbsc.createMBean("ExceptionThrower", objName);
+            System.out.println("---- OK\n");
+
+            // ----
+            System.out.println("ExceptionTest::run: Ask for exception(s)");
+            Object[] throwExceptionParam = new Object[1];
+            String[] throwExceptionSig = new String[]{"int"};
+
+            for (int i = 0; i < ExceptionFactory.exceptions.size(); i++) {
+                throwExceptionParam[0] = new Integer(i);
+
+                Exception ex =
+                    (Exception)mbsc.invoke(objName,
+                        "throwException", throwExceptionParam, throwExceptionSig);
+
+                if ( ! matches(ex, ExceptionFactory.exceptions.get(i)) ) {
+                    errorCount++;
+                    System.out.println("ExceptionTest::run: (ERROR) Received \n["
+                            + ex + "]\nin place of\n["
+                            + ExceptionFactory.exceptions.get(i) + "]");
+                } else {
+                    System.out.println("OK [" + ex + "]");
+                }
+            }
+
+            System.out.println("---- DONE\n");
+
+        } catch (Exception e) {
+            Utils.printThrowable(e, true);
+            throw new RuntimeException();
+        } finally {
+            try {
+                // Close JMX Connector Client
+                cc.close();
+                // Stop connertor server
+                cs.stop();
+
+            } catch (Exception e) {
+                Utils.printThrowable(e, true);
+                throw new RuntimeException(
+                    "Unable to either close connector client or stop connector server");
+            }
+        }
+
+        if (errorCount == 0) {
+            System.out.println("ExceptionTest::run: Done without any error");
+        } else {
+            System.out.println("ExceptionTest::run: Done with " + errorCount
+                    + " error(s)");
+            throw new RuntimeException("errorCount = " + errorCount);
+        }
+
+        System.out.println("ExceptionTest::run: Done");
+    }
+
+    // Check both Exception are identical.
+    // That means:
+    // - none is null.
+    // - they are of the same Class.
+    // - if their respective messages aren't null they're equal.
+    // - if the message of one is null the message of the other is null too.
+    private boolean matches(Exception ex, Exception refex) {
+        if ( ex == null || refex == null ) {
+            System.out.println("(ERROR) Called with one or more null parameter; check "
+                    + ex + " against " + refex);
+            return false;
+        }
+
+        String exClass = ex.getClass().getName();
+        String refexClass = refex.getClass().getName();
+
+        if ( ! exClass.equals(refexClass) ) {
+            System.out.println("(ERROR) Class names don't match; check ["
+                        + exClass + "] against [" + refexClass + "]");
+            return false;
+        }
+
+        String exMes = ex.getMessage();
+        String refexMes = refex.getMessage();
+
+        if ( exMes != null && refexMes != null ) {
+            if ( ! exMes.equals(refexMes) ) {
+                System.out.println("(ERROR) Non null messages don't match; check ["
+                        + exMes + "] against [" + refexMes + "]");
+                return false;
+            }
+        } else if ( (exMes == null && refexMes != null)
+                || (exMes != null && refexMes == null) ) {
+                System.out.println("(ERROR) Messages don't match; check [" + exMes
+                        + "] against [" + refexMes + "]");
+        }
+
+        return true;
+    }
+
+    // Utility inner class coming from JMX Tonga test suite.
+    // Also used by ExceptionFactory.
+    static class Utils {
+
+        // DEBUG is printed depending on the DEBUG and DEBUG_LEVEL JAVA property
+        static final String DEBUG_HEADER = "[debug] ";
+
+        // DEBUG levels
+        static int selectedDebugLevel = 0;
+        static final int DEBUG_STANDARD = 1;
+        static final int DEBUG_VERBOSE = 2;  // Mainly used for stress tests
+        static final int DEBUG_ALL = DEBUG_STANDARD | DEBUG_VERBOSE;
+
+        static void parseDebugProperties() {
+            int level = 0;
+            Properties p = System.getProperties();
+
+            // get selected levels
+            if (p.getProperty("DEBUG_STANDARD") != null) {
+                level |= DEBUG_STANDARD;
+            }
+
+            if (p.getProperty("DEBUG_VERBOSE") != null) {
+                level |= DEBUG_VERBOSE;
+            }
+
+            if (p.getProperty("DEBUG_ALL") != null) {
+                level |= DEBUG_ALL;
+            }
+
+            selectedDebugLevel = level;
+        }
+
+        /**
+         * Reproduces the original parsing and collection of test parameters
+         * from the DTonga JMX test suite.
+         *
+         * Collects passed args and returns them in a map(argname, value) structure,
+         * which will be then propagated as necessary to various called methods.
+         */
+        static Map<String, Object> parseParameters(String args[])
+        throws Exception {
+            debug(DEBUG_STANDARD, "TestRoot::parseParameters: Start");
+            HashMap<String, Object> map = new HashMap<>();
+
+            for ( int i = 0; i < args.length; i++ ) {
+                if ( args[i].trim().startsWith("-") ) {
+                    if ((i+1) < args.length && !args[i+1].startsWith("-") ) {
+                        debug(DEBUG_STANDARD,
+                            "TestRoot::parseParameters: added in map = " +
+                            args[i] +
+                            " with value " +
+                            args[i+1]) ;
+                        map.put(args[i].trim(), args[i+1].trim()) ;
+                    } else if ((i+1) < args.length && args[i+1].startsWith("-") ||
+                               (i+1) == args.length ) {
+                        debug(DEBUG_STANDARD,
+                                "TestRoot::parseParameters: added in map = " +
+                                args[i] +
+                                " with null value") ;
+                        map.put(args[i].trim(), null) ;
+                    } else {
+                        System.out.println(
+                            "TestRoot::parseParameters: (WARNING) not added in map = " +
+                            args[i]) ;
+                    }
+                }
+            }
+
+            debug(DEBUG_STANDARD, "TestRoot::parseParameters: Done") ;
+            return map ;
+        }
+
+        /**
+         * This method is to be used in all tests to print anything
+         * that is temporary.
+         * Printing is done only when debug is activated by the property DEBUG.
+         * Printing depends also on the DEBUG_LEVEL property.
+         * Here it encapsulates a System.out.println.
+         */
+        static void debug(int level, String line) {
+            if ((selectedDebugLevel & level) != 0) {
+                System.out.println(DEBUG_HEADER + line);
+            }
+        }
+
+        /**
+         * Do print stack trace when withStack is true.
+         * Does try to call getTargetException() and getTargetError() then
+         * print embedded stacks in the case of an Exception wrapping
+         * another Exception or an Error. Recurse until no more wrapping
+         * is found.
+         */
+        static void printThrowable(Throwable theThro, boolean withStack) {
+            try {
+                if (withStack) {
+                    theThro.printStackTrace(System.out);
+                }
+                if (theThro instanceof Exception) {
+                    Exception t = (Exception) theThro;
+                    Method target = null;
+                    String blank = " ";
+                    try {
+                        target = t.getClass().getMethod("getTargetException",
+                                (java.lang.Class<?>[]) null);
+                    } catch (Exception ee) {
+                    // OK: getTargetException method could be there or not
+                    }
+                    System.out.println(blank + t.getClass() + "==>" + t.getMessage());
+                    while (target != null) {
+                        try {
+                            t = (Exception) target.invoke(t,
+                                    (java.lang.Object[]) null);
+                        } catch (Exception ee) {
+                            t = null;
+                        }
+                        try {
+                            if (t != null) {
+                                blank = blank + "  ";
+                                System.out.println(blank + t.getClass() + "==>" +
+                                        t.getMessage());
+                                try {
+                                    target =
+                                            t.getClass().getMethod("getTargetException",
+                                            (java.lang.Class<?>[]) null);
+                                } catch (Exception ee) {
+                                // OK: getTargetException method could be there or not                            }
+                                }
+                            } else {
+                                target = null;
+                            }
+                        } catch (Exception ee) {
+                            target = null;
+                        }
+                    }
+
+                    // We may have exceptions wrapping an Error then it is
+                    // getTargetError that is likely to be called
+                    try {
+                        target = ((Exception) theThro).getClass().getMethod("getTargetError",
+                                (java.lang.Class<?>[]) null);
+                    } catch (Exception ee) {
+                    // OK: getTargetError method could be there or not
+                    }
+                    Throwable err = theThro;
+                    while (target != null) {
+                        try {
+                            err = (Error) target.invoke(err,
+                                    (java.lang.Object[]) null);
+                        } catch (Exception ee) {
+                            err = null;
+                        }
+                        try {
+                            if (err != null) {
+                                blank = blank + "  ";
+                                System.out.println(blank + err.getClass() + "==>" +
+                                        err.getMessage());
+                                if (withStack) {
+                                    err.printStackTrace(System.out);
+                                }
+                                try {
+                                    target = err.getClass().getMethod("getTargetError",
+                                            (java.lang.Class<?>[]) null);
+                                } catch (Exception ee) {
+                                // OK: getTargetError method could be there or not
+                                }
+                            } else {
+                                target = null;
+                            }
+                        } catch (Exception ee) {
+                            target = null;
+                        }
+                    }
+                } else {
+                    System.out.println("Throwable is : " + theThro);
+                }
+            } catch (Throwable x) {
+                System.out.println("Exception : raised in printException : " + x);
+            }
+        }
+    }
+
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/MBeanServer/ExceptionThrower.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * This class defines a simple standard MBean.
+ */
+public class ExceptionThrower implements ExceptionThrowerMBean {
+
+    public static final String EXCEPTION_THROWER_NAME
+            = "sqe:type=ExceptionThrower";
+
+    public Exception throwException(int exceptionIndex) {
+        return ExceptionFactory.exceptions.get(exceptionIndex);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/MBeanServer/ExceptionThrowerMBean.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * This interface defines a simple standard MBean.
+ */
+public interface ExceptionThrowerMBean {
+    public Exception throwException(int exceptionIndex);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/mxbean/Basic.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,530 @@
+/*
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import javax.management.Descriptor;
+import javax.management.ImmutableDescriptor;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanNotificationInfo;
+import javax.management.MBeanRegistration;
+import javax.management.MBeanServer;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationEmitter;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+
+/**
+ * Class Basic
+ * Basic Description
+ */
+public class Basic implements BasicMXBean, NotificationEmitter,
+                              MBeanRegistration {
+
+    public static final String EXCEPTION_MESSAGE = "from Basic";
+    public static final String NOTIFICATION_MESSAGE = "from Basic";
+    /** Attribute : IntAtt */
+    private int intAtt = 0;
+    /** Attribute : IntegerAtt */
+    private Integer integerAtt = 0;
+    /** Attribute : BoolAtt */
+    private boolean boolAtt = false;
+    /** Attribute : BooleanAtt */
+    private Boolean booleanAtt = false;
+    /** Attribute : StringAtt */
+    private String stringAtt = null;
+    /** Attribute : DateAtt */
+    private Date dateAtt = null;
+    /** Attribute : ObjectNameAtt */
+    private ObjectName objectNameAtt = null;
+    /** Attribute : NotifDescriptorAsMapAtt */
+    private Map<String, String> notifDescriptorAsMapAtt = null;
+    /** Attribute : NotifDescriptorAtt */
+    private Descriptor notifDescriptorAtt = null;
+    /** Attribute : SqeParameter */
+    private SqeParameter sqeParameterAtt = null;
+
+    /* Creates a new instance of Basic */
+    @SqeDescriptorKey("CONSTRUCTOR Basic")
+    public Basic() {
+    }
+
+    /* Creates a new instance of Basic */
+    @SqeDescriptorKey("CONSTRUCTOR Basic")
+    public Basic(
+            @SqeDescriptorKey("CONSTRUCTOR PARAMETER SqeParameter") SqeParameter param) {
+    }
+
+    /**
+     * Get int attribute
+     */
+    public int getIntAtt() {
+        return intAtt;
+    }
+
+    /**
+     * Set int attribute
+     */
+    public void setIntAtt(int value) {
+        intAtt = value;
+    }
+
+    /**
+     * Get Integer attribute
+     */
+    public Integer getIntegerAtt() {
+        return integerAtt;
+    }
+
+    /**
+     * Set Integer attribute
+     */
+    public void setIntegerAtt(Integer value) {
+        integerAtt = value;
+    }
+
+    /**
+     * Get boolean attribute
+     */
+    public boolean getBoolAtt() {
+        return boolAtt;
+    }
+
+    /**
+     * Set boolean attribute
+     */
+    public void setBoolAtt(boolean value) {
+        boolAtt = value;
+    }
+
+    /**
+     * Get Boolean attribute
+     */
+    public Boolean getBooleanAtt() {
+        return booleanAtt;
+    }
+
+    /**
+     * Set Boolean attribute
+     */
+    public void setBooleanAtt(Boolean value) {
+        booleanAtt = value;
+    }
+
+    /**
+     * Get String attribute
+     */
+    public String getStringAtt() {
+        return stringAtt;
+    }
+
+    /**
+     * Set String attribute
+     */
+    public void setStringAtt(String value) {
+        stringAtt = value;
+    }
+
+    /**
+     * Get Date attribute
+     */
+    public Date getDateAtt() {
+        return dateAtt;
+    }
+
+    /**
+     * Set Date attribute
+     */
+    public void setDateAtt(Date value) {
+        dateAtt = value;
+    }
+
+    /**
+     * Get ObjectName attribute
+     */
+    public ObjectName getObjectNameAtt() {
+        return objectNameAtt;
+    }
+
+    /**
+     * Set ObjectName attribute
+     */
+    public void setObjectNameAtt(ObjectName value) {
+        objectNameAtt = value;
+    }
+
+    /**
+     * Get SqeParameter attribute
+     */
+    public SqeParameter getSqeParameterAtt() throws Exception {
+        if (sqeParameterAtt == null) {
+            sqeParameterAtt = new SqeParameter();
+            sqeParameterAtt.setGlop("INITIALIZED");
+        }
+
+        return sqeParameterAtt;
+    }
+
+    /**
+     * Set SqeParameter attribute
+     */
+    public void setSqeParameterAtt(SqeParameter value) {
+        sqeParameterAtt = value;
+    }
+
+    /**
+     * Get the Descriptor used to build the NotificationInfo
+     * of emitted notifications.
+     */
+    public Map<String, String> getNotifDescriptorAsMapAtt() {
+        if (notifDescriptorAsMapAtt == null) {
+            initNotifDescriptorAtt();
+        }
+
+        return notifDescriptorAsMapAtt;
+    }
+
+    /**
+     * Set the Descriptor used to build the NotificationInfo
+     * of emitted notifications.
+     * <br>A Map<String, Object> would better fit Descriptor needs but then
+     * it is not convertible according the MXBean specification so the MBean
+     * registration fails.
+     * As we plan to test our custom Descriptor finds its way into
+     * the metadata of emitted notifications, String is good enough.
+     */
+    public void setNotifDescriptorAsMapAtt(Map<String, String> value) {
+        notifDescriptorAsMapAtt = new HashMap<String, String>(value);
+        notifDescriptorAtt = new ImmutableDescriptor(value);
+    }
+
+    /**
+     * Do nothing
+     */
+    public void doNothing() {
+        // I said NOTHING !
+    }
+
+    /**
+     * Do take SqeParameter as a parameter
+     */
+    public void doWeird(SqeParameter param) {
+    }
+
+    /**
+     * Throw an Exception
+     */
+    public void throwException() throws Exception {
+        throw new Exception(EXCEPTION_MESSAGE);
+    }
+
+    /**
+     * Throw an Error
+     */
+    public void throwError() {
+        throw new InternalError(EXCEPTION_MESSAGE);
+    }
+
+    /**
+     * Reset all attributes
+     */
+    public void reset() {
+        intAtt = 0;
+        integerAtt = 0;
+        boolAtt = false;
+        booleanAtt = Boolean.FALSE;
+        stringAtt = null;
+        dateAtt = null;
+        objectNameAtt = null;
+    }
+
+    /**
+     * Returns the weather for the coming days
+     * @param verbose <code>boolean</code> verbosity
+     * @throws java.lang.Exception <code>storm</code>
+     * @return <code>ObjectName</code>
+     */
+    public Weather getWeather(boolean verbose)
+            throws java.lang.Exception {
+        return Weather.SUNNY;
+    }
+
+    // Starting here are the 4 methods of MBeanRegistration interface.
+    // We use that to grab the ObjectName the MBean is registered with.
+    //
+    public ObjectName preRegister(MBeanServer server, ObjectName name)
+            throws Exception {
+        // Grab a reference on the MBeanServer we're registered in.
+        mbs = server;
+        // Compute the name we're registered with.
+        if (name != null) {
+            mbeanName = name;
+            return name;
+        } else {
+            mbeanName =
+                new ObjectName("sqe:type=" + Basic.class.getName());
+            return mbeanName;
+        }
+    }
+
+    public void postRegister(Boolean registrationDone) {
+        // Do nothing
+    }
+
+    public void preDeregister() throws Exception {
+        // Do nothing
+    }
+
+    public void postDeregister() {
+        // Do nothing
+    }
+
+    /**
+     * Send one Notification of the provided notifType type.
+     */
+    public void sendNotification(String notifType) {
+        Notification notification = null;
+
+        if (notifType.equals(NOTIF_TYPE_0)) {
+            notification = new Notification(NOTIF_TYPE_0,
+                    mbeanName,
+                    seqNumber,
+                    NOTIFICATION_MESSAGE);
+        } else if (notifType.equals(NOTIF_TYPE_1)) {
+            notification = new SqeNotification(NOTIF_TYPE_1,
+                    mbeanName,
+                    seqNumber,
+                    NOTIFICATION_MESSAGE);
+        }
+
+        seqNumber++;
+        broadcaster.sendNotification(notification);
+    }
+
+    /**
+     * That method starts a set of threads, each thread sends a given number of
+     * notifications.
+     * The number of threads can be set via the attribute numOfNotificationSenders.
+     * The number of notification sent by each thread can be set via
+     * the attribute numOfNotificationSenderLoops.
+     * Depending on the parameter customNotification we send either custom
+     * notification(s) or MBeanServer registration and unregistration notification(s).
+     * When customNotification=true the total number of notification(s) sent is
+     * (numOfNotificationSenders * numOfNotificationSenderLoops). They are
+     * sequentially of type NOTIF_TYPE_0 then NOTIF_TYPE_1 and so on.
+     *
+     * When customNotification=false the total number of notification(s) sent is
+     * (numOfNotificationSenders * numOfNotificationSenderLoops) registration
+     * notification(s)
+     * +
+     * (numOfNotificationSenders * numOfNotificationSenderLoops) unregistration
+     * notification(s)
+     *
+     * @throws java.lang.Exception
+     */
+    public void sendNotificationWave(boolean customNotification) throws
+            Exception {
+        // Build the set of notification sender.
+        Collection<Callable<Integer>> tasks =
+                new HashSet<Callable<Integer>>(numOfNotificationSenders);
+
+        for (int i = 1; i <= numOfNotificationSenders; i++) {
+            tasks.add(new NotifSender(numOfNotificationSenderLoops,
+                    customNotification, i));
+        }
+
+        // Start all notification sender in parallel.
+        ExecutorService execServ = null;
+        try {
+            execServ = Executors.newFixedThreadPool(numOfNotificationSenders);
+            List<Future<Integer>> taskHandlers = execServ.invokeAll(tasks);
+            checkNotifSenderThreadStatus(taskHandlers);
+        } finally {
+            if (!execServ.isShutdown()) {
+                execServ.shutdown();
+            }
+        }
+    }
+
+    public void setNumOfNotificationSenders(int value) {
+        numOfNotificationSenders = value;
+    }
+
+    public void setNumOfNotificationSenderLoops(int value) {
+        numOfNotificationSenderLoops = value;
+    }
+
+    /**
+     * MBean Notification support
+     * You shouldn't update these methods
+     */
+    // <editor-fold defaultstate="collapsed" desc=" Generated Code ">
+    public void addNotificationListener(NotificationListener listener,
+                                        NotificationFilter filter,
+                                        Object handback)
+            throws IllegalArgumentException {
+        broadcaster.addNotificationListener(listener, filter, handback);
+    }
+
+    public MBeanNotificationInfo[] getNotificationInfo() {
+        if (notifDescriptorAtt == null) {
+            initNotifDescriptorAtt();
+        }
+
+        return new MBeanNotificationInfo[]{
+                    new MBeanNotificationInfo(new String[]{
+                        NOTIF_TYPE_0
+                    },
+                    javax.management.Notification.class.getName(),
+                    "Standard JMX Notification",
+                    notifDescriptorAtt),
+                    new MBeanNotificationInfo(new String[]{
+                        NOTIF_TYPE_1
+                    },
+                    SqeNotification.class.getName(),
+                    "SQE Notification",
+                    notifDescriptorAtt)
+                };
+    }
+
+    public void removeNotificationListener(NotificationListener listener)
+            throws ListenerNotFoundException {
+        broadcaster.removeNotificationListener(listener);
+    }
+
+    public void removeNotificationListener(NotificationListener listener,
+                                           NotificationFilter filter,
+                                           Object handback)
+            throws ListenerNotFoundException {
+        broadcaster.removeNotificationListener(listener, filter, handback);
+    }
+    // </editor-fold>
+    private synchronized long getNextSeqNumber() {
+        return seqNumber++;
+    }
+
+    private void initNotifDescriptorAtt() {
+        String key = "CRABE";
+        String value = "TAMBOUR";
+        notifDescriptorAtt =
+                new ImmutableDescriptor(new String[]{key + "=" + value});
+        notifDescriptorAsMapAtt =
+                new HashMap<String, String>();
+        notifDescriptorAsMapAtt.put(key, value);
+    }
+
+    private void checkNotifSenderThreadStatus(
+            List<Future<Integer>> taskHandlers)
+            throws Exception {
+        String msgTag = "Basic::checkNotifSenderThreadStatus: ";
+        // Grab back status of each notification sender.
+        for (Future<Integer> f : taskHandlers) {
+            if (f.isCancelled()) {
+                String message = msgTag +
+                        "---- ERROR : One thread has been cancelled";
+                System.out.println(message);
+                throw new RuntimeException(message);
+            } else {
+                Integer effectiveNumOfLoops = f.get();
+
+                if (effectiveNumOfLoops != numOfNotificationSenderLoops) {
+                    String message = msgTag + "---- ERROR : One thread did " +
+                            effectiveNumOfLoops + " loops in place of " +
+                            numOfNotificationSenderLoops;
+                    System.out.println(message);
+                    throw new RuntimeException(message);
+                }
+            }
+        }
+    }
+    //
+    private int numOfNotificationSenderLoops = 2;
+    private int numOfNotificationSenders = 13;
+
+    private class NotifSender implements Callable<Integer> {
+
+        private int cycles;
+        private boolean customNotification;
+        private int senderID;
+
+        public NotifSender(int cycles, boolean customNotification, int id) {
+            this.cycles = cycles;
+            this.customNotification = customNotification;
+            this.senderID = id;
+        }
+
+        public Integer call() throws Exception {
+            int callsDone = 0;
+
+            try {
+                for (int i = 1; i <= cycles; i++) {
+                    if (customNotification) {
+                        if (i % 2 == 0) {
+                            sendNotification(NOTIF_TYPE_0);
+                        } else {
+                            sendNotification(NOTIF_TYPE_1);
+                        }
+                    } else {
+                        ObjectName mbeanName = new ObjectName("SQE:type=" +
+                                mbeanClassName + ",senderID=" + senderID);
+                        mbs.createMBean(mbeanClassName, mbeanName);
+                        mbs.unregisterMBean(mbeanName);
+                    }
+                    callsDone++;
+                }
+            } catch (Exception e) {
+                System.out.println("NotifSender::call: (ERROR) Thread [" + senderID +
+                        "] failed after " + callsDone + " cycles");
+                throw e;
+            }
+
+            return Integer.valueOf(callsDone);
+        }
+    }
+
+    //
+    private long seqNumber;
+    private final NotificationBroadcasterSupport broadcaster =
+            new NotificationBroadcasterSupport();
+    private ObjectName mbeanName;
+    private MBeanServer mbs;
+    private String mbeanClassName = "Simple";
+
+    /**
+     * Notification types definitions. To use when creating JMX Notifications.
+     */
+    public static final String NOTIF_TYPE_0 =
+            "sqe.notification.a.type";
+    public static final String NOTIF_TYPE_1 =
+            "sqe.notification.b.type";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/mxbean/BasicMXBean.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.util.Date;
+import java.util.Map;
+
+import javax.management.ObjectName;
+
+/**
+ * Interface BasicMBean
+ * Basic Description
+ */
+@SqeDescriptorKey("INTERFACE BasicMXBean")
+public interface BasicMXBean
+{
+   /**
+    * Get int attribute
+    */
+    @SqeDescriptorKey("ATTRIBUTE intAtt")
+    public int getIntAtt();
+
+   /**
+    * Set int attribute
+    */
+    @SqeDescriptorKey("ATTRIBUTE intAtt")
+    public void setIntAtt(int value);
+
+   /**
+    * Get Integer attribute
+    */
+    @SqeDescriptorKey("ATTRIBUTE integerAtt")
+    public Integer getIntegerAtt();
+
+   /**
+    * Set Integer attribute
+    */
+    @SqeDescriptorKey("ATTRIBUTE integerAtt")
+    public void setIntegerAtt(Integer value);
+
+   /**
+    * Get boolean attribute
+    */
+    @SqeDescriptorKey("ATTRIBUTE boolAtt")
+    public boolean getBoolAtt();
+
+   /**
+    * Set boolean attribute
+    */
+    @SqeDescriptorKey("ATTRIBUTE boolAtt")
+    public void setBoolAtt(boolean value);
+
+   /**
+    * Get Boolean attribute
+    */
+    @SqeDescriptorKey("ATTRIBUTE booleanAtt")
+    public Boolean getBooleanAtt();
+
+   /**
+    * Set Boolean attribute
+    */
+    @SqeDescriptorKey("ATTRIBUTE booleanAtt")
+    public void setBooleanAtt(Boolean value);
+
+   /**
+    * Get String attribute
+    */
+    @SqeDescriptorKey("ATTRIBUTE stringAtt")
+    public String getStringAtt();
+
+   /**
+    * Set String attribute
+    */
+    @SqeDescriptorKey("ATTRIBUTE stringAtt")
+    public void setStringAtt(String value);
+
+   /**
+    * Get Date attribute
+    */
+    @SqeDescriptorKey("ATTRIBUTE dateAtt")
+    public Date getDateAtt();
+
+   /**
+    * Set Date attribute
+    */
+    @SqeDescriptorKey("ATTRIBUTE dateAtt")
+    public void setDateAtt(Date value);
+
+   /**
+    * Get ObjectName attribute
+    */
+    @SqeDescriptorKey("ATTRIBUTE objectNameAtt")
+    public ObjectName getObjectNameAtt();
+
+   /**
+    * Set ObjectName attribute
+    */
+    @SqeDescriptorKey("ATTRIBUTE objectNameAtt")
+    public void setObjectNameAtt(ObjectName value);
+
+   /**
+    * Get SqeParameter attribute
+    */
+    @SqeDescriptorKey("ATTRIBUTE sqeParameterAtt")
+    public SqeParameter getSqeParameterAtt() throws Exception;
+
+   /**
+    * Set SqeParameter attribute
+    */
+    @SqeDescriptorKey("ATTRIBUTE sqeParameterAtt")
+    public void setSqeParameterAtt(SqeParameter value);
+
+   /**
+    * Set NumOfNotificationSenders attribute
+    */
+    @SqeDescriptorKey("ATTRIBUTE NumOfNotificationSenders")
+    public void setNumOfNotificationSenders(int value);
+
+   /**
+    * Set NumOfNotificationSenderLoops attribute
+    */
+    @SqeDescriptorKey("ATTRIBUTE NumOfNotificationSenderLoops")
+    public void setNumOfNotificationSenderLoops(int value);
+
+   /**
+    * do nothing
+    *
+    */
+    @SqeDescriptorKey("OPERATION doNothing")
+    public void doNothing();
+
+   /**
+    * Do take SqeParameter as a parameter
+    */
+    @SqeDescriptorKey("OPERATION doWeird")
+    public void doWeird(@SqeDescriptorKey("METHOD PARAMETER")SqeParameter param);
+
+    /**
+    * throw an Exception
+    *
+    */
+    @SqeDescriptorKey("OPERATION throwException")
+    public void throwException() throws Exception;
+
+   /**
+    * throw an Error
+    *
+    */
+    @SqeDescriptorKey("OPERATION throwError")
+    public void throwError();
+
+   /**
+    * reset all attributes
+    *
+    */
+    @SqeDescriptorKey("OPERATION reset")
+    public void reset();
+
+   /**
+    * returns the weather for the coming days
+    *
+    * @param verbose <code>boolean</code> verbosity
+    * @return <code>ObjectName</code>
+    */
+    @SqeDescriptorKey("OPERATION getWeather")
+    public Weather getWeather(@SqeDescriptorKey("METHOD PARAMETER")boolean verbose)
+        throws java.lang.Exception;
+
+    public enum Weather {
+        CLOUDY, SUNNY
+    }
+
+    @SqeDescriptorKey("ATTRIBUTE notifDescriptorAsMapAtt")
+    public Map<String, String> getNotifDescriptorAsMapAtt();
+
+    @SqeDescriptorKey("ATTRIBUTE notifDescriptorAsMapAtt")
+    public void setNotifDescriptorAsMapAtt(Map<String, String> value);
+
+    @SqeDescriptorKey("OPERATION sendNotification")
+    public void sendNotification(@SqeDescriptorKey("METHOD PARAMETER")String notifType);
+
+    @SqeDescriptorKey("OPERATION sendNotificationWave")
+    public void sendNotificationWave(boolean customNotification) throws Exception;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/mxbean/MXBeanExceptionHandlingTest.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8058865
+ * @summary Checks correct exception and error events from NotificationListener
+ * @author Olivier Lagneau
+ * @modules java.management
+ * @library /lib/testlibrary
+ * @compile Basic.java
+ * @run main/othervm/timeout=300 -DDEBUG_STANDARD MXBeanExceptionHandlingTest -timeForNotificationInSeconds 3
+ */
+
+
+import java.util.Map;
+import java.util.HashMap;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+
+import java.lang.management.ManagementFactory;
+import javax.management.MBeanServer;
+import javax.management.MBeanException;
+import javax.management.MBeanServerDelegate;
+import javax.management.Notification;
+import javax.management.NotificationListener;
+import javax.management.MBeanServerConnection;
+import javax.management.ObjectName;
+import javax.management.RuntimeErrorException;
+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 MXBeanExceptionHandlingTest implements NotificationListener {
+
+    private static String BASIC_MXBEAN_CLASS_NAME = "Basic";
+
+    private long timeForNotificationInSeconds = 3L;
+    private int numOfNotifications = 2;
+    private BlockingQueue<Notification> notifList = null;
+
+
+    /*
+     * First Debug properties and arguments are collect in expected
+     * map  (argName, value) format, then calls original test's run method.
+     */
+    public static void main(String args[]) throws Exception {
+
+        System.out.println("=================================================");
+
+        // Parses parameters
+        Utils.parseDebugProperties();
+        Map<String, Object> map = Utils.parseParameters(args) ;
+
+        // Run test
+        MXBeanExceptionHandlingTest test = new MXBeanExceptionHandlingTest();
+        test.run(map);
+
+    }
+
+    protected void parseArgs(Map<String, Object> args) throws Exception {
+
+        String arg = null;
+
+        // Init timeForNotificationInSeconds
+        // It is the maximum time in seconds we wait for a notification.
+        arg = (String)args.get("-timeForNotificationInSeconds") ;
+        if (arg != null) {
+            timeForNotificationInSeconds = (new Long(arg)).longValue();
+        }
+
+    }
+
+    public void run(Map<String, Object> args) {
+
+        System.out.println("MXBeanExceptionHandlingTest::run: Start") ;
+        int errorCount = 0 ;
+
+        try {
+            parseArgs(args);
+            notifList = new ArrayBlockingQueue<Notification>(numOfNotifications);
+
+            // JMX MbeanServer used inside single VM as if remote.
+            MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+
+            JMXServiceURL url = new JMXServiceURL("rmi", null, 0);
+            JMXConnectorServer cs =
+                JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);
+            cs.start();
+
+            JMXServiceURL addr = cs.getAddress();
+            JMXConnector cc = JMXConnectorFactory.connect(addr);
+            MBeanServerConnection mbsc = cc.getMBeanServerConnection();
+
+            // ----
+            System.out.println("Add me as notification listener");
+            mbsc.addNotificationListener(MBeanServerDelegate.DELEGATE_NAME,
+                    this, null, null);
+            System.out.println("---- OK\n") ;
+
+            // ----
+            System.out.println("Create and register the MBean");
+            ObjectName objName = new ObjectName("sqe:type=Basic,protocol=rmi") ;
+            mbsc.createMBean(BASIC_MXBEAN_CLASS_NAME, objName);
+            System.out.println("---- OK\n") ;
+
+            // ----
+            System.out.println("Call method throwException on our MXBean");
+
+            try {
+                mbsc.invoke(objName, "throwException", null, null);
+                errorCount++;
+                System.out.println("(ERROR) Did not get awaited MBeanException") ;
+            } catch (MBeanException mbe) {
+                System.out.println("(OK) Got awaited MBeanException") ;
+                Throwable cause = mbe.getCause();
+
+                if ( cause instanceof java.lang.Exception ) {
+                    System.out.println("(OK) Cause is of the right class") ;
+                    String mess = cause.getMessage();
+
+                    if ( mess.equals(Basic.EXCEPTION_MESSAGE ) ) {
+                        System.out.println("(OK) Cause message is fine") ;
+                    } else {
+                        errorCount++;
+                        System.out.println("(ERROR) Cause has message "
+                                + cause.getMessage()
+                                + " as we expect "
+                                + Basic.EXCEPTION_MESSAGE) ;
+                    }
+                } else {
+                    errorCount++;
+                    System.out.println("(ERROR) Cause is of  class "
+                            + cause.getClass().getName()
+                            + " as we expect java.lang.Exception") ;
+                }
+            } catch (Exception e) {
+                errorCount++;
+                System.out.println("(ERROR) Did not get awaited MBeanException but "
+                        + e) ;
+                Utils.printThrowable(e, true);
+            }
+            System.out.println("---- DONE\n") ;
+
+            // ----
+            System.out.println("Call method throwError on our MXBean");
+
+            try {
+                mbsc.invoke(objName, "throwError", null, null);
+                errorCount++;
+                System.out.println("(ERROR) Did not get awaited RuntimeErrorException") ;
+            } catch (RuntimeErrorException ree) {
+                System.out.println("(OK) Got awaited RuntimeErrorException") ;
+                Throwable cause = ree.getCause();
+
+                if ( cause instanceof java.lang.InternalError ) {
+                    System.out.println("(OK) Cause is of the right class") ;
+                    String mess = cause.getMessage();
+
+                    if ( mess.equals(Basic.EXCEPTION_MESSAGE ) ) {
+                        System.out.println("(OK) Cause message is fine") ;
+                    } else {
+                        errorCount++;
+                        System.out.println("(ERROR) Cause has message "
+                                + cause.getMessage()
+                                + " as we expect "
+                                + Basic.EXCEPTION_MESSAGE) ;
+                    }
+                } else {
+                    errorCount++;
+                    System.out.println("(ERROR) Cause is of  class "
+                            + cause.getClass().getName()
+                            + " as we expect java.lang.InternalError") ;
+                }
+            } catch (Exception e) {
+                errorCount++;
+                System.out.println("(ERROR) Did not get awaited RuntimeErrorException but "
+                        + e) ;
+                Utils.printThrowable(e, true);
+            }
+            System.out.println("---- DONE\n") ;
+
+            // ----
+            System.out.println("Unregister the MBean");
+            mbsc.unregisterMBean(objName);
+            System.out.println("---- OK\n") ;
+
+            Thread.sleep(timeForNotificationInSeconds * 1000);
+            int numOfReceivedNotif = notifList.size();
+
+            if ( numOfReceivedNotif == numOfNotifications ) {
+                System.out.println("(OK) We received "
+                        + numOfNotifications
+                        + " Notifications") ;
+            } else {
+                errorCount++;
+                System.out.println("(ERROR) We received "
+                        + numOfReceivedNotif
+                        + " Notifications in place of "
+                        + numOfNotifications) ;
+            }
+        } catch(Exception e) {
+            Utils.printThrowable(e, true) ;
+            throw new RuntimeException(e);
+        }
+
+        if ( errorCount == 0 ) {
+            System.out.println("MXBeanExceptionHandlingTest::run: Done without any error") ;
+        } else {
+            System.out.println("MXBeanExceptionHandlingTest::run: Done with "
+                    + errorCount
+                    + " error(s)") ;
+            throw new RuntimeException("errorCount = " + errorCount);
+        }
+    }
+
+    public void handleNotification(Notification notification, Object handback) {
+        System.out.println("MXBeanExceptionHandlingTest::handleNotification: Received "
+                + notification);
+        notifList.add(notification);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/mxbean/MXBeanInteropTest1.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,638 @@
+/*
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8058865
+ * @summary Test all MXBeans available by default on the platform
+ * @author Olivier Lagneau
+ * @modules java.management
+ * @library /lib/testlibrary
+ * @run main/othervm/timeout=300 -DDEBUG_STANDARD MXBeanInteropTest1
+ */
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import java.lang.management.ClassLoadingMXBean;
+import java.lang.management.CompilationMXBean;
+import java.lang.management.GarbageCollectorMXBean;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryMXBean;
+import java.lang.management.MemoryManagerMXBean;
+import java.lang.management.MemoryPoolMXBean;
+import java.lang.management.OperatingSystemMXBean;
+import java.lang.management.RuntimeMXBean;
+import java.lang.management.ThreadMXBean;
+
+import javax.management.JMX;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanConstructorInfo;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.MBeanInfo;
+import javax.management.MBeanNotificationInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanServerConnection;
+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 MXBeanInteropTest1 {
+
+    /*
+     * First Debug properties and arguments are collect in expected
+     * map  (argName, value) format, then calls original test's run method.
+     */
+    public static void main(String args[]) throws Exception {
+
+        System.out.println("=================================================");
+
+        // Parses parameters
+        Utils.parseDebugProperties();
+        Map<String, Object> map = Utils.parseParameters(args) ;
+
+        // Run test
+        MXBeanInteropTest1 test = new MXBeanInteropTest1();
+        test.run(map);
+
+    }
+
+    public void run(Map<String, Object> args) {
+
+        System.out.println("MXBeanInteropTest1::run: Start") ;
+        int errorCount = 0 ;
+
+        try {
+            // JMX MbeanServer used inside single VM as if remote.
+            // MBeanServer mbs = MBeanServerFactory.newMBeanServer();
+            MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+
+            JMXServiceURL url = new JMXServiceURL("rmi", null, 0);
+            JMXConnectorServer cs =
+                JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);
+            cs.start();
+
+            JMXServiceURL addr = cs.getAddress();
+            JMXConnector cc = JMXConnectorFactory.connect(addr);
+            MBeanServerConnection mbsc = cc.getMBeanServerConnection();
+
+            // Print out registered java.lang.management MXBeans found
+            // in the remote jvm.
+            printMBeans(mbsc) ;
+
+            // For each possible kind of JDK 5 defined MXBean, we retrieve its
+            // MBeanInfo and print it and we call all getters and print
+            // their output.
+            errorCount += doClassLoadingMXBeanTest(mbsc) ;
+            errorCount += doMemoryMXBeanTest(mbsc) ;
+            errorCount += doThreadMXBeanTest(mbsc) ;
+            errorCount += doRuntimeMXBeanTest(mbsc) ;
+            errorCount += doOperatingSystemMXBeanTest(mbsc) ;
+            errorCount += doCompilationMXBeanTest(mbsc) ;
+            errorCount += doGarbageCollectorMXBeanTest(mbsc) ;
+            errorCount += doMemoryManagerMXBeanTest(mbsc) ;
+            errorCount += doMemoryPoolMXBeanTest(mbsc) ;
+
+            // Terminate the JMX Client
+            cc.close();
+
+        } catch(Exception e) {
+            Utils.printThrowable(e, true) ;
+            throw new RuntimeException(e);
+        }
+
+        if ( errorCount == 0 ) {
+            System.out.println("MXBeanInteropTest1::run: Done without any error") ;
+        } else {
+            System.out.println("MXBeanInteropTest1::run: Done with "
+                    + errorCount
+                    + " error(s)") ;
+            throw new RuntimeException("errorCount = " + errorCount);
+        }
+    }
+
+    /**
+     * Prints all MBeans of domain java.lang.
+     * They are MBeans related to the JSR 174 that defines
+     * package java.lang.management.
+     */
+    private static void printMBeans(MBeanServerConnection mbsc) throws Exception {
+        ObjectName filterName = new ObjectName("java.lang:*");
+        Set<ObjectName> set = mbsc.queryNames(filterName, null);
+
+        if ( set.size() == 0 ) {
+            throw new RuntimeException("(ERROR) No MBean found with filter "
+                    + filterName);
+        }
+
+        System.out.println("---- MBeans found in domain java.lang :");
+
+        for (Iterator<ObjectName> iter = set.iterator(); iter.hasNext(); ) {
+            System.out.println(iter.next().toString());
+        }
+
+        System.out.println("\n") ;
+    }
+
+
+    private final int doClassLoadingMXBeanTest(MBeanServerConnection mbsc) {
+        int errorCount = 0 ;
+        System.out.println("---- ClassLoadingMXBean") ;
+
+        try {
+            ObjectName classLoadingName =
+                    new ObjectName(ManagementFactory.CLASS_LOADING_MXBEAN_NAME) ;
+            MBeanInfo mbInfo = mbsc.getMBeanInfo(classLoadingName);
+            errorCount += checkNonEmpty(mbInfo);
+            System.out.println("getMBeanInfo\t\t"
+                    + mbInfo);
+            ClassLoadingMXBean classLoading = null;
+
+            classLoading = JMX.newMXBeanProxy(mbsc,
+                    classLoadingName,
+                    ClassLoadingMXBean.class) ;
+            System.out.println("getLoadedClassCount\t\t"
+                    + classLoading.getLoadedClassCount());
+            System.out.println("getTotalLoadedClassCount\t\t"
+                    + classLoading.getTotalLoadedClassCount());
+            System.out.println("getUnloadedClassCount\t\t"
+                    + classLoading.getUnloadedClassCount());
+            System.out.println("isVerbose\t\t"
+                    + classLoading.isVerbose());
+
+            System.out.println("---- OK\n") ;
+
+        } catch (Exception e) {
+            Utils.printThrowable(e, true) ;
+            errorCount++ ;
+            System.out.println("---- ERROR\n") ;
+        }
+
+        return errorCount ;
+    }
+
+
+    private final int doMemoryMXBeanTest(MBeanServerConnection mbsc) {
+        int errorCount = 0 ;
+        System.out.println("---- MemoryMXBean") ;
+
+        try {
+            ObjectName memoryName =
+                    new ObjectName(ManagementFactory.MEMORY_MXBEAN_NAME) ;
+            MBeanInfo mbInfo = mbsc.getMBeanInfo(memoryName);
+            errorCount += checkNonEmpty(mbInfo);
+            System.out.println("getMBeanInfo\t\t"
+                    + mbInfo);
+            MemoryMXBean memory = null ;
+
+            memory =
+                    JMX.newMXBeanProxy(mbsc,
+                    memoryName,
+                    MemoryMXBean.class,
+                    true) ;
+            System.out.println("getMemoryHeapUsage\t\t"
+                    + memory.getHeapMemoryUsage());
+            System.out.println("getNonHeapMemoryHeapUsage\t\t"
+                    + memory.getNonHeapMemoryUsage());
+            System.out.println("getObjectPendingFinalizationCount\t\t"
+                    + memory.getObjectPendingFinalizationCount());
+            System.out.println("isVerbose\t\t"
+                    + memory.isVerbose());
+
+            System.out.println("---- OK\n") ;
+
+        } catch (Exception e) {
+            Utils.printThrowable(e, true) ;
+            errorCount++ ;
+            System.out.println("---- ERROR\n") ;
+        }
+
+        return errorCount ;
+    }
+
+
+    private final int doThreadMXBeanTest(MBeanServerConnection mbsc) {
+        int errorCount = 0 ;
+        System.out.println("---- ThreadMXBean") ;
+
+        try {
+            ObjectName threadName =
+                    new ObjectName(ManagementFactory.THREAD_MXBEAN_NAME) ;
+            MBeanInfo mbInfo = mbsc.getMBeanInfo(threadName);
+            errorCount += checkNonEmpty(mbInfo);
+            System.out.println("getMBeanInfo\t\t" + mbInfo);
+            ThreadMXBean thread = null ;
+
+            thread =
+                    JMX.newMXBeanProxy(mbsc,
+                    threadName,
+                    ThreadMXBean.class) ;
+            System.out.println("findMonitorDeadlockedThreads\t\t"
+                    + thread.findMonitorDeadlockedThreads());
+            long[] threadIDs = thread.getAllThreadIds() ;
+            System.out.println("getAllThreadIds\t\t"
+                    + threadIDs);
+
+            for ( long threadID : threadIDs ) {
+                System.out.println("getThreadInfo long\t\t"
+                        + thread.getThreadInfo(threadID));
+                System.out.println("getThreadInfo long, int\t\t"
+                        + thread.getThreadInfo(threadID, 2));
+            }
+
+            System.out.println("getThreadInfo long[]\t\t"
+                    + thread.getThreadInfo(threadIDs));
+            System.out.println("getThreadInfo long[], int\t\t"
+                    + thread.getThreadInfo(threadIDs, 2));
+            System.out.println("getDaemonThreadCount\t\t"
+                    + thread.getDaemonThreadCount());
+            System.out.println("getPeakThreadCount\t\t"
+                    + thread.getPeakThreadCount());
+            System.out.println("getThreadCount\t\t"
+                    + thread.getThreadCount());
+            System.out.println("getTotalStartedThreadCount\t\t"
+                    + thread.getTotalStartedThreadCount());
+            boolean supported = thread.isThreadContentionMonitoringSupported() ;
+            System.out.println("isThreadContentionMonitoringSupported\t\t"
+                    + supported);
+
+            if ( supported ) {
+                System.out.println("isThreadContentionMonitoringEnabled\t\t"
+                        + thread.isThreadContentionMonitoringEnabled());
+            }
+
+            supported = thread.isThreadCpuTimeSupported() ;
+            System.out.println("isThreadCpuTimeSupported\t\t"
+                    + supported);
+
+            if ( supported ) {
+                System.out.println("isThreadCpuTimeEnabled\t\t"
+                        + thread.isThreadCpuTimeEnabled());
+
+                for (long id : threadIDs) {
+                    System.out.println("getThreadCpuTime(" + id + ")\t\t"
+                            + thread.getThreadCpuTime(id));
+                    System.out.println("getThreadUserTime(" + id + ")\t\t"
+                            + thread.getThreadUserTime(id));
+                }
+            }
+
+            supported = thread.isCurrentThreadCpuTimeSupported() ;
+            System.out.println("isCurrentThreadCpuTimeSupported\t\t"
+                    + supported);
+
+            if ( supported ) {
+                System.out.println("getCurrentThreadCpuTime\t\t"
+                        + thread.getCurrentThreadCpuTime());
+                System.out.println("getCurrentThreadUserTime\t\t"
+                        + thread.getCurrentThreadUserTime());
+            }
+
+            thread.resetPeakThreadCount() ;
+
+            System.out.println("---- OK\n") ;
+        } catch (Exception e) {
+            Utils.printThrowable(e, true) ;
+            errorCount++ ;
+            System.out.println("---- ERROR\n") ;
+        }
+
+        return errorCount ;
+    }
+
+
+    private final int doRuntimeMXBeanTest(MBeanServerConnection mbsc) {
+        int errorCount = 0 ;
+        System.out.println("---- RuntimeMXBean") ;
+
+        try {
+            ObjectName runtimeName =
+                    new ObjectName(ManagementFactory.RUNTIME_MXBEAN_NAME) ;
+            MBeanInfo mbInfo = mbsc.getMBeanInfo(runtimeName);
+            errorCount += checkNonEmpty(mbInfo);
+            System.out.println("getMBeanInfo\t\t" + mbInfo);
+            RuntimeMXBean runtime = null;
+
+            runtime =
+                    JMX.newMXBeanProxy(mbsc,
+                    runtimeName,
+                    RuntimeMXBean.class) ;
+            System.out.println("getClassPath\t\t"
+                    + runtime.getClassPath());
+            System.out.println("getInputArguments\t\t"
+                    + runtime.getInputArguments());
+            System.out.println("getLibraryPath\t\t"
+                    + runtime.getLibraryPath());
+            System.out.println("getManagementSpecVersion\t\t"
+                    + runtime.getManagementSpecVersion());
+            System.out.println("getName\t\t"
+                    + runtime.getName());
+            System.out.println("getSpecName\t\t"
+                    + runtime.getSpecName());
+            System.out.println("getSpecVendor\t\t"
+                    + runtime.getSpecVendor());
+            System.out.println("getSpecVersion\t\t"
+                    + runtime.getSpecVersion());
+            System.out.println("getStartTime\t\t"
+                    + runtime.getStartTime());
+            System.out.println("getSystemProperties\t\t"
+                    + runtime.getSystemProperties());
+            System.out.println("getUptime\t\t"
+                    + runtime.getUptime());
+            System.out.println("getVmName\t\t"
+                    + runtime.getVmName());
+            System.out.println("getVmVendor\t\t"
+                    + runtime.getVmVendor());
+            System.out.println("getVmVersion\t\t"
+                    + runtime.getVmVersion());
+            boolean supported = runtime.isBootClassPathSupported() ;
+            System.out.println("isBootClassPathSupported\t\t"
+                    + supported);
+
+            if ( supported ) {
+                System.out.println("getBootClassPath\t\t"
+                        + runtime.getBootClassPath());
+            }
+
+            System.out.println("---- OK\n") ;
+        } catch (Exception e) {
+            Utils.printThrowable(e, true) ;
+            errorCount++ ;
+            System.out.println("---- ERROR\n") ;
+        }
+
+        return errorCount ;
+    }
+
+
+    private final int doOperatingSystemMXBeanTest(MBeanServerConnection mbsc) {
+        int errorCount = 0 ;
+        System.out.println("---- OperatingSystemMXBean") ;
+
+        try {
+            ObjectName operationName =
+                    new ObjectName(ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME) ;
+            MBeanInfo mbInfo = mbsc.getMBeanInfo(operationName);
+            errorCount += checkNonEmpty(mbInfo);
+            System.out.println("getMBeanInfo\t\t" + mbInfo);
+            OperatingSystemMXBean operation = null ;
+
+            operation =
+                    JMX.newMXBeanProxy(mbsc,
+                    operationName,
+                    OperatingSystemMXBean.class) ;
+            System.out.println("getArch\t\t"
+                    + operation.getArch());
+            System.out.println("getAvailableProcessors\t\t"
+                    + operation.getAvailableProcessors());
+            System.out.println("getName\t\t"
+                    + operation.getName());
+            System.out.println("getVersion\t\t"
+                    + operation.getVersion());
+
+            System.out.println("---- OK\n") ;
+        } catch (Exception e) {
+            Utils.printThrowable(e, true) ;
+            errorCount++ ;
+            System.out.println("---- ERROR\n") ;
+        }
+
+        return errorCount ;
+    }
+
+
+    private final int doCompilationMXBeanTest(MBeanServerConnection mbsc) {
+        int errorCount = 0 ;
+        System.out.println("---- CompilationMXBean") ;
+
+        try {
+            ObjectName compilationName =
+                    new ObjectName(ManagementFactory.COMPILATION_MXBEAN_NAME);
+
+            if ( mbsc.isRegistered(compilationName) ) {
+                MBeanInfo mbInfo = mbsc.getMBeanInfo(compilationName);
+                errorCount += checkNonEmpty(mbInfo);
+                System.out.println("getMBeanInfo\t\t" + mbInfo);
+                CompilationMXBean compilation = null ;
+
+                compilation =
+                        JMX.newMXBeanProxy(mbsc,
+                        compilationName,
+                        CompilationMXBean.class) ;
+                System.out.println("getName\t\t"
+                        + compilation.getName());
+                boolean supported =
+                        compilation.isCompilationTimeMonitoringSupported() ;
+                System.out.println("isCompilationTimeMonitoringSupported\t\t"
+                        + supported);
+
+                if ( supported ) {
+                    System.out.println("getTotalCompilationTime\t\t"
+                            + compilation.getTotalCompilationTime());
+                }
+            }
+
+            System.out.println("---- OK\n") ;
+        } catch (Exception e) {
+            Utils.printThrowable(e, true) ;
+            errorCount++ ;
+            System.out.println("---- ERROR\n") ;
+        }
+
+        return errorCount ;
+    }
+
+
+    private final int doGarbageCollectorMXBeanTest(MBeanServerConnection mbsc) {
+        int errorCount = 0 ;
+        System.out.println("---- GarbageCollectorMXBean") ;
+
+        try {
+            ObjectName filterName =
+                    new ObjectName(ManagementFactory.GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE
+                    + ",*");
+            Set<ObjectName> onSet = mbsc.queryNames(filterName, null);
+
+            for (Iterator<ObjectName> iter = onSet.iterator(); iter.hasNext(); ) {
+                ObjectName garbageName = iter.next() ;
+                System.out.println("-------- " + garbageName) ;
+                MBeanInfo mbInfo = mbsc.getMBeanInfo(garbageName);
+                errorCount += checkNonEmpty(mbInfo);
+                System.out.println("getMBeanInfo\t\t" + mbInfo);
+                GarbageCollectorMXBean garbage = null ;
+
+                garbage =
+                        JMX.newMXBeanProxy(mbsc,
+                        garbageName,
+                        GarbageCollectorMXBean.class) ;
+                System.out.println("getCollectionCount\t\t"
+                        + garbage.getCollectionCount());
+                System.out.println("getCollectionTime\t\t"
+                        + garbage.getCollectionTime());
+            }
+
+            System.out.println("---- OK\n") ;
+        } catch (Exception e) {
+            Utils.printThrowable(e, true) ;
+            errorCount++ ;
+            System.out.println("---- ERROR\n") ;
+        }
+
+        return errorCount ;
+    }
+
+
+    private final int doMemoryManagerMXBeanTest(MBeanServerConnection mbsc) {
+        int errorCount = 0 ;
+        System.out.println("---- MemoryManagerMXBean") ;
+
+        try {
+            ObjectName filterName =
+                    new ObjectName(ManagementFactory.MEMORY_MANAGER_MXBEAN_DOMAIN_TYPE
+                    + ",*");
+            Set<ObjectName> onSet = mbsc.queryNames(filterName, null);
+
+            for (Iterator<ObjectName> iter = onSet.iterator(); iter.hasNext(); ) {
+                ObjectName memoryManagerName = iter.next() ;
+                System.out.println("-------- " + memoryManagerName) ;
+                MBeanInfo mbInfo = mbsc.getMBeanInfo(memoryManagerName);
+                System.out.println("getMBeanInfo\t\t" + mbInfo);
+                errorCount += checkNonEmpty(mbInfo);
+                MemoryManagerMXBean memoryManager = null;
+
+                memoryManager =
+                        JMX.newMXBeanProxy(mbsc,
+                        memoryManagerName,
+                        MemoryManagerMXBean.class) ;
+                System.out.println("getMemoryPoolNames\t\t"
+                        + Arrays.deepToString(memoryManager.getMemoryPoolNames()));
+                System.out.println("getName\t\t"
+                        + memoryManager.getName());
+                System.out.println("isValid\t\t"
+                        + memoryManager.isValid());
+            }
+
+            System.out.println("---- OK\n") ;
+        } catch (Exception e) {
+            Utils.printThrowable(e, true) ;
+            errorCount++ ;
+            System.out.println("---- ERROR\n") ;
+        }
+
+        return errorCount ;
+    }
+
+
+    private final int doMemoryPoolMXBeanTest(MBeanServerConnection mbsc) {
+        int errorCount = 0 ;
+        System.out.println("---- MemoryPoolMXBean") ;
+
+        try {
+            ObjectName filterName =
+                    new ObjectName(ManagementFactory.MEMORY_POOL_MXBEAN_DOMAIN_TYPE
+                    + ",*");
+            Set<ObjectName> onSet = mbsc.queryNames(filterName, null);
+
+            for (Iterator<ObjectName> iter = onSet.iterator(); iter.hasNext(); ) {
+                ObjectName memoryPoolName = iter.next() ;
+                System.out.println("-------- " + memoryPoolName) ;
+                MBeanInfo mbInfo = mbsc.getMBeanInfo(memoryPoolName);
+                errorCount += checkNonEmpty(mbInfo);
+                System.out.println("getMBeanInfo\t\t" + mbInfo);
+                MemoryPoolMXBean memoryPool = null;
+
+                memoryPool =
+                        JMX.newMXBeanProxy(mbsc,
+                        memoryPoolName,
+                        MemoryPoolMXBean.class,
+                        true) ;
+                System.out.println("getCollectionUsage\t\t"
+                        + memoryPool.getCollectionUsage());
+                System.out.println("getMemoryManagerNames\t\t"
+                        + Arrays.deepToString(memoryPool.getMemoryManagerNames()));
+                System.out.println("getName\t\t"
+                        + memoryPool.getName());
+                System.out.println("getPeakUsage\t\t"
+                        + memoryPool.getPeakUsage());
+                System.out.println("getType\t\t"
+                        + memoryPool.getType());
+                System.out.println("getUsage\t\t"
+                        + memoryPool.getUsage());
+                System.out.println("isValid\t\t"
+                        + memoryPool.isValid());
+                boolean supported = memoryPool.isUsageThresholdSupported() ;
+                System.out.println("isUsageThresholdSupported\t\t"
+                        + supported);
+
+                if ( supported ) {
+                    System.out.println("getUsageThreshold\t\t"
+                            + memoryPool.getUsageThreshold());
+                    System.out.println("isUsageThresholdExceeded\t\t"
+                            + memoryPool.isUsageThresholdExceeded());
+                    System.out.println("getUsageThresholdCount\t\t"
+                            + memoryPool.getUsageThresholdCount());
+                }
+
+                supported = memoryPool.isCollectionUsageThresholdSupported() ;
+                System.out.println("isCollectionUsageThresholdSupported\t\t"
+                        + supported);
+
+                if ( supported ) {
+                    System.out.println("getCollectionUsageThreshold\t\t"
+                            + memoryPool.getCollectionUsageThreshold());
+                    System.out.println("getCollectionUsageThresholdCount\t\t"
+                            + memoryPool.getCollectionUsageThresholdCount());
+                    System.out.println("isCollectionUsageThresholdExceeded\t\t"
+                            + memoryPool.isCollectionUsageThresholdExceeded());
+                }
+
+                memoryPool.resetPeakUsage();
+            }
+
+            System.out.println("---- OK\n") ;
+        } catch (Exception e) {
+            Utils.printThrowable(e, true) ;
+            errorCount++ ;
+            System.out.println("---- ERROR\n") ;
+        }
+
+        return errorCount ;
+    }
+
+
+    private int checkNonEmpty(MBeanInfo mbi) {
+        if ( mbi.toString().length() == 0 ) {
+            System.out.println("(ERROR) MBeanInfo is empty !");
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/mxbean/MXBeanInteropTest2.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8058865
+ * @summary Checks access to test MXBean
+ * @author Olivier Lagneau
+ * @modules java.management
+ * @library /lib/testlibrary
+ * @compile Basic.java
+ * @run main/othervm/timeout=300 -DDEBUG_STANDARD MXBeanInteropTest2
+ */
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import javax.management.Attribute;
+import javax.management.JMX;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanConstructorInfo;
+import javax.management.MBeanServer;
+import java.lang.management.ManagementFactory;
+import javax.management.MBeanInfo;
+import javax.management.MBeanNotificationInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanServerConnection;
+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 MXBeanInteropTest2 {
+
+    private static String BASIC_MXBEAN_CLASS_NAME = "Basic";
+
+    /*
+     * First Debug properties and arguments are collect in expected
+     * map  (argName, value) format, then calls original test's run method.
+     */
+    public static void main(String args[]) throws Exception {
+
+        System.out.println("=================================================");
+
+        // Parses parameters
+        Utils.parseDebugProperties();
+        Map<String, Object> map = Utils.parseParameters(args) ;
+
+        // Run test
+        MXBeanInteropTest2 test = new MXBeanInteropTest2();
+        test.run(map);
+
+    }
+
+    public void run(Map<String, Object> args) {
+
+        System.out.println("MXBeanInteropTest2::run: Start") ;
+        int errorCount = 0 ;
+
+        try {
+            // JMX MbeanServer used inside single VM as if remote.
+            MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+
+            JMXServiceURL url = new JMXServiceURL("rmi", null, 0);
+            JMXConnectorServer cs =
+                JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);
+            cs.start();
+
+            JMXServiceURL addr = cs.getAddress();
+            JMXConnector cc = JMXConnectorFactory.connect(addr);
+            MBeanServerConnection mbsc = cc.getMBeanServerConnection();
+
+            // Prints all MBeans whatever the domain is.
+            printMBeans(mbsc) ;
+
+            // Call test body
+            errorCount += doBasicMXBeanTest(mbsc) ;
+
+            // Terminate the JMX Client
+            cc.close();
+
+        } catch(Exception e) {
+            Utils.printThrowable(e, true) ;
+            throw new RuntimeException(e);
+        }
+
+        if ( errorCount == 0 ) {
+            System.out.println("MXBeanInteropTest2::run: Done without any error") ;
+        } else {
+            System.out.println("MXBeanInteropTest2::run: Done with "
+                    + errorCount
+                    + " error(s)") ;
+            throw new RuntimeException("errorCount = " + errorCount);
+        }
+    }
+
+
+    /**
+     * Prints all MBeans whatever the domain is.
+     */
+    private static void printMBeans(MBeanServerConnection mbsc) throws Exception {
+        Set<ObjectName> set = mbsc.queryNames(null, null);
+        System.out.println("---- MBeans found :");
+
+        for (Iterator<ObjectName> iter = set.iterator(); iter.hasNext(); ) {
+            System.out.println(iter.next().toString());
+        }
+
+        System.out.println("\n") ;
+    }
+
+
+    private final int doBasicMXBeanTest(MBeanServerConnection mbsc) {
+        int errorCount = 0 ;
+        System.out.println("---- doBasicMXBeanTest") ;
+
+        try {
+            ObjectName objName =
+                    new ObjectName("sqe:type=BasicMXBean") ;
+            mbsc.createMBean(BASIC_MXBEAN_CLASS_NAME, objName);
+            MBeanInfo mbInfo = mbsc.getMBeanInfo(objName);
+            printMBeanInfo(mbInfo);
+            System.out.println("---- OK\n") ;
+            System.out.println("getMBeanInfo\t\t"
+                    + mbInfo);
+            System.out.println("---- OK\n") ;
+
+            System.out.println("Check mxbean field in the MBeanInfo");
+            String mxbeanField =
+                    (String)mbInfo.getDescriptor().getFieldValue(JMX.MXBEAN_FIELD);
+
+            if ( mxbeanField == null || ! mxbeanField.equals("true")) {
+                System.out.println("---- ERROR : Improper mxbean field value "
+                        + mxbeanField);
+                errorCount++;
+            }
+            System.out.println("---- OK\n") ;
+
+            System.out.println("Set attribute ObjectNameAtt");
+            Attribute att = new Attribute("ObjectNameAtt", objName);
+            mbsc.setAttribute(objName, att);
+            ObjectName value =
+                    (ObjectName)mbsc.getAttribute(objName, "ObjectNameAtt");
+
+            if ( ! value.equals(objName) ) {
+                errorCount++;
+                System.out.println("---- ERROR : setAttribute failed, got "
+                        + value
+                        + " while expecting "
+                        + objName);
+            }
+            System.out.println("---- OK\n") ;
+
+            System.out.println("Call operation doNothing");
+            mbsc.invoke(objName,  "doNothing", null, null);
+            System.out.println("---- OK\n") ;
+
+            System.out.println("Call operation getWeather");
+            Object weather = mbsc.invoke(objName,
+                    "getWeather",
+                    new Object[]{Boolean.TRUE},
+                    new String[]{"boolean"});
+            System.out.println("Weather is " + weather);
+            System.out.println("---- OK\n") ;
+        } catch (Exception e) {
+            Utils.printThrowable(e, true) ;
+            errorCount++ ;
+            System.out.println("---- ERROR\n") ;
+        }
+
+        return errorCount ;
+    }
+
+    private void printMBeanInfo(MBeanInfo mbInfo) {
+        System.out.println("Description " + mbInfo.getDescription());
+
+        for (MBeanConstructorInfo ctor : mbInfo.getConstructors()) {
+            System.out.println("Constructor " + ctor.getName());
+        }
+
+        for (MBeanAttributeInfo att : mbInfo.getAttributes()) {
+            System.out.println("Attribute " + att.getName()
+            + " [" + att.getType() + "]");
+        }
+
+        for (MBeanOperationInfo oper : mbInfo.getOperations()) {
+            System.out.println("Operation " + oper.getName());
+        }
+
+        for (MBeanNotificationInfo notif : mbInfo.getNotifications()) {
+            System.out.println("Notification " + notif.getName());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/mxbean/MXBeanLoadingTest1.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8058865
+ * @summary Checks correct collection of MXBean's class after unregistration
+ * @author Olivier Lagneau
+ * @modules java.management
+ * @library /lib/testlibrary
+ * @run main/othervm/timeout=300 MXBeanLoadingTest1
+ */
+
+import java.lang.ref.WeakReference;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Arrays;
+import java.util.Map;
+import javax.management.Attribute;
+import javax.management.JMX;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.MXBean;
+import javax.management.ObjectName;
+import javax.management.loading.PrivateMLet;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+
+public class MXBeanLoadingTest1 {
+
+    public static void main(String[] args) throws Exception {
+        MXBeanLoadingTest1 test = new MXBeanLoadingTest1();
+        test.run((Map<String, Object>)null);
+    }
+
+
+    public void run(Map<String, Object> args) {
+
+        System.out.println("MXBeanLoadingTest1::run: Start") ;
+
+        try {
+            System.out.println("We ensure no reference is retained on MXBean class"
+                    + " after it is unregistered. We take time to perform"
+                    + " some little extra check of Descriptors, MBean*Info.");
+
+            ClassLoader myClassLoader = MXBeanLoadingTest1.class.getClassLoader();
+
+            if (!(myClassLoader instanceof URLClassLoader)) {
+                String message = "(ERROR) Test's class loader is not " +
+                        "a URLClassLoader";
+                System.out.println(message);
+                throw new RuntimeException(message);
+            }
+
+            URLClassLoader myURLClassLoader = (URLClassLoader) myClassLoader;
+            URL[] urls = myURLClassLoader.getURLs();
+            PrivateMLet mlet = new PrivateMLet(urls, null, false);
+            Class<?> shadowClass = mlet.loadClass(TestMXBean.class.getName());
+
+            if (shadowClass == TestMXBean.class) {
+                String message = "(ERROR) MLet got original TestMXBean, not shadow";
+                System.out.println(message);
+                throw new RuntimeException(message);
+            }
+            shadowClass = null;
+
+            MBeanServer mbs = MBeanServerFactory.createMBeanServer();
+            ObjectName mletName = new ObjectName("x:type=mlet");
+            mbs.registerMBean(mlet, mletName);
+
+            ObjectName testName = new ObjectName("x:type=test");
+            mbs.createMBean(Test.class.getName(), testName, mletName);
+
+            // That test fails because the MXBean instance is accessed via
+            // a delegate OpenMBean which has
+            ClassLoader testLoader = mbs.getClassLoaderFor(testName);
+
+            if (testLoader != mlet) {
+                System.out.println("MLet " + mlet);
+                String message = "(ERROR) MXBean's class loader is not MLet: "
+                        + testLoader;
+                System.out.println(message);
+                throw new RuntimeException(message);
+            }
+            testLoader = null;
+
+
+            // Cycle get/set/get of the attribute of type Luis.
+            // We check the set is effective.
+            CompositeData cd_B = (CompositeData)mbs.getAttribute(testName, "B");
+            CompositeType compType_B = cd_B.getCompositeType();
+
+            CompositeDataSupport cds_B =
+                    new CompositeDataSupport(compType_B,
+                    new String[]{"something"},
+                    new Object[]{Integer.valueOf(13)});
+            Attribute myAtt = new Attribute("B",  cds_B);
+            mbs.setAttribute(testName, myAtt);
+
+            CompositeData cd_B2 = (CompositeData)mbs.getAttribute(testName, "B");
+
+            if ( ((Integer)cd_B2.get("something")).intValue() != 13 ) {
+                String message = "(ERROR) The setAttribute of att B did not work;"
+                        + " expect Luis.something = 13 but got "
+                        + cd_B2.get("something");
+                System.out.println(message);
+                throw new RuntimeException(message);
+            }
+
+            MBeanInfo info = mbs.getMBeanInfo(testName);
+            String mxbeanField =
+                    (String)info.getDescriptor().getFieldValue(JMX.MXBEAN_FIELD);
+
+            if ( mxbeanField == null || ! mxbeanField.equals("true")) {
+                String message = "(ERROR) Improper mxbean field value "
+                        + mxbeanField;
+                System.out.println(message);
+                throw new RuntimeException(message);
+            }
+
+            // Check the 2 attributes.
+            MBeanAttributeInfo[] attrs = info.getAttributes();
+
+            if ( attrs.length == 2 ) {
+                for (MBeanAttributeInfo mbai : attrs) {
+                    String originalTypeFieldValue =
+                            (String)mbai.getDescriptor().getFieldValue(JMX.ORIGINAL_TYPE_FIELD);
+                    OpenType<?> openTypeFieldValue =
+                            (OpenType<?>)mbai.getDescriptor().getFieldValue(JMX.OPEN_TYPE_FIELD);
+
+                    if ( mbai.getName().equals("A") ) {
+                        if ( !mbai.isReadable() || !mbai.isWritable()
+                        || mbai.isIs()
+                        || !mbai.getType().equals("int") ) {
+                            String message = "(ERROR) Unexpected MBeanAttributeInfo for A "
+                                    + mbai;
+                            System.out.println(message);
+                            throw new RuntimeException(message);
+                        }
+
+                        if ( ! originalTypeFieldValue.equals("int") ) {
+                            String message = "(ERROR) Unexpected originalType in Descriptor for A "
+                                    + originalTypeFieldValue;
+                            System.out.println(message);
+                            throw new RuntimeException(message);
+                        }
+
+                        if ( ! openTypeFieldValue.equals(SimpleType.INTEGER) ) {
+                            String message = "(ERROR) Unexpected openType in Descriptor for A "
+                                    + originalTypeFieldValue;
+                            System.out.println(message);
+                            throw new RuntimeException(message);
+                        }
+                    } else if ( mbai.getName().equals("B") ) {
+                        if ( !mbai.isReadable() || !mbai.isWritable()
+                        || mbai.isIs()
+                        || !mbai.getType().equals("javax.management.openmbean.CompositeData") ) {
+                            String message = "(ERROR) Unexpected MBeanAttributeInfo for B "
+                                    + mbai;
+                            System.out.println(message);
+                            throw new RuntimeException(message);
+                        }
+
+                        if ( ! originalTypeFieldValue.equals(Luis.class.getName()) ) {
+                            String message = "(ERROR) Unexpected originalType in Descriptor for B "
+                                    + originalTypeFieldValue;
+                            System.out.println(message);
+                            throw new RuntimeException(message);
+                        }
+
+                        if ( ! openTypeFieldValue.equals(compType_B) ) {
+                            String message = "(ERROR) Unexpected openType in Descriptor for B "
+                                    + compType_B;
+                            System.out.println(message);
+                            throw new RuntimeException(message);
+                        }
+                    } else {
+                        String message = "(ERROR) Unknown attribute name";
+                        System.out.println(message);
+                        throw new RuntimeException(message);
+                    }
+                }
+            } else {
+                String message = "(ERROR) Unexpected MBeanAttributeInfo array"
+                        + Arrays.deepToString(attrs);
+                System.out.println(message);
+                throw new RuntimeException(message);
+            }
+
+            // Check the MXBean operation.
+            MBeanOperationInfo[] ops = info.getOperations();
+            // The impact is ACTION_INFO as for a standard MBean it is UNKNOWN,
+            // logged 6320104.
+            if (ops.length != 1 || !ops[0].getName().equals("bogus")
+            || ops[0].getSignature().length > 0
+                    || !ops[0].getReturnType().equals("void")) {
+                String message = "(ERROR) Unexpected MBeanOperationInfo array "
+                        + Arrays.deepToString(ops);
+                System.out.println(message);
+                throw new RuntimeException(message);
+            }
+
+            String originalTypeFieldValue =
+                    (String)ops[0].getDescriptor().getFieldValue(JMX.ORIGINAL_TYPE_FIELD);
+            OpenType<?> openTypeFieldValue =
+                    (OpenType<?>)ops[0].getDescriptor().getFieldValue(JMX.OPEN_TYPE_FIELD);
+
+            if ( ! originalTypeFieldValue.equals("void") ) {
+                String message = "(ERROR) Unexpected originalType in Descriptor for bogus "
+                        + originalTypeFieldValue;
+                System.out.println(message);
+                throw new RuntimeException(message);
+            }
+
+            if ( ! openTypeFieldValue.equals(SimpleType.VOID) ) {
+                String message = "(ERROR) Unexpected openType in Descriptor for bogus "
+                        + originalTypeFieldValue;
+                System.out.println(message);
+                throw new RuntimeException(message);
+            }
+
+            // Check there is 2 constructors.
+            if (info.getConstructors().length != 2) {
+                String message = "(ERROR) Wrong number of constructors " +
+                        "in introspected bean: " +
+                        Arrays.asList(info.getConstructors());
+                System.out.println(message);
+                throw new RuntimeException(message);
+            }
+
+            // Check MXBean class name.
+            if (!info.getClassName().endsWith("Test")) {
+                String message = "(ERROR) Wrong info class name: " +
+                        info.getClassName();
+                System.out.println(message);
+                throw new RuntimeException(message);
+            }
+
+            mbs.unregisterMBean(testName);
+            mbs.unregisterMBean(mletName);
+
+            WeakReference<PrivateMLet> mletRef =
+                    new WeakReference<PrivateMLet>(mlet);
+            mlet = null;
+
+            System.out.println("MXBean registered and unregistered, waiting for " +
+                    "garbage collector to collect class loader");
+
+            for (int i = 0; i < 10000 && mletRef.get() != null; i++) {
+                System.gc();
+                Thread.sleep(1);
+            }
+
+            if (mletRef.get() == null)
+                System.out.println("(OK) class loader was GC'd");
+            else {
+                String message = "(ERROR) Class loader was not GC'd";
+                System.out.println(message);
+                throw new RuntimeException(message);
+            }
+        } catch(Exception e) {
+            Utils.printThrowable(e, true) ;
+            throw new RuntimeException(e);
+        }
+
+        System.out.println("MXBeanLoadingTest1::run: Done without any error") ;
+    }
+
+
+    // I agree the use of the MXBean annotation and the MXBean suffix for the
+    // interface name are redundant but however harmless.
+    //
+    @MXBean(true)
+    public static interface TestMXBean {
+        public void bogus();
+        public int getA();
+        public void setA(int a);
+        public Luis getB();
+        public void setB(Luis mi);
+    }
+
+
+    public static class Test implements TestMXBean {
+        private Luis luis = new Luis() ;
+        public Test() {}
+        public Test(int x) {}
+
+        public void bogus() {}
+        public int getA() {return 0;}
+        public void setA(int a) {}
+        public Luis getB() {return this.luis;}
+        public void setB(Luis luis) {this.luis = luis;}
+    }
+
+
+    public static class Luis {
+        private int something = 0;
+        public Luis() {}
+        public int getSomething() {return something;}
+        public void setSomething(int v) {something = v;}
+        public void doNothing() {}
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/mxbean/MXBeanNotifTest.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,385 @@
+/*
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8058865
+ * @summary Checks MXBean proper registration both as its implementation class and interface
+ * @author Olivier Lagneau
+ * @modules java.management
+ * @library /lib/testlibrary
+ * @compile Basic.java
+ * @run main/othervm/timeout=300 -DDEBUG_STANDARD MXBeanNotifTest -numOfNotifications 239 -timeForNotificationInSeconds 4
+ */
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+import java.lang.management.ManagementFactory;
+
+import javax.management.Attribute;
+import javax.management.Descriptor;
+import javax.management.ImmutableDescriptor;
+import javax.management.MBeanServer;
+import javax.management.MBeanInfo;
+import javax.management.MBeanNotificationInfo;
+import javax.management.Notification;
+import javax.management.NotificationListener;
+import javax.management.MBeanServerConnection;
+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;
+
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+import javax.management.openmbean.TabularData;
+import javax.management.openmbean.TabularDataSupport;
+import javax.management.openmbean.TabularType;
+
+public class MXBeanNotifTest implements NotificationListener {
+
+    private static String BASIC_MXBEAN_CLASS_NAME = "Basic";
+    private static String BASIC_MXBEAN_INTERFACE_NAME = "BasicMXBean";
+
+    private long timeForNotificationInSeconds = 3L;
+    private int numOfNotifications = 1;
+    private BlockingQueue<Notification> notifList = null;
+    private int numOfNotifDescriptorElements = 13;
+
+    /*
+     * First Debug properties and arguments are collect in expected
+     * map  (argName, value) format, then calls original test's run method.
+     */
+    public static void main(String args[]) throws Exception {
+
+        System.out.println("=================================================");
+
+        // Parses parameters
+        Utils.parseDebugProperties();
+        Map<String, Object> map = Utils.parseParameters(args) ;
+
+        // Run test
+        MXBeanNotifTest test = new MXBeanNotifTest();
+        test.run(map);
+
+    }
+
+    protected void parseArgs(Map<String, Object> args) throws Exception {
+
+        String arg = null;
+
+        // Init numOfNotifications
+        // It is the number of notifications we should trigger and check.
+        arg = (String)args.get("-numOfNotifications") ;
+        if (arg != null) {
+            numOfNotifications = (new Integer(arg)).intValue();
+        }
+
+        // Init timeForNotificationInSeconds
+        // It is the maximum time in seconds we wait for each notification.
+        arg = (String)args.get("-timeForEachNotificationInSeconds") ;
+        if (arg != null) {
+            timeForNotificationInSeconds = (new Long(arg)).longValue();
+        }
+
+    }
+
+    public void run(Map<String, Object> args) {
+
+        System.out.println("MXBeanNotifTest::run: Start") ;
+        int errorCount = 0 ;
+
+        try {
+            parseArgs(args);
+            notifList = new ArrayBlockingQueue<Notification>(numOfNotifications);
+
+            // JMX MbeanServer used inside single VM as if remote.
+            MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+
+            JMXServiceURL url = new JMXServiceURL("rmi", null, 0);
+            JMXConnectorServer cs =
+                JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);
+            cs.start();
+
+            JMXServiceURL addr = cs.getAddress();
+            JMXConnector cc = JMXConnectorFactory.connect(addr);
+            MBeanServerConnection mbsc = cc.getMBeanServerConnection();
+
+            // ----
+            System.out.println("MXBeanNotifTest::run: Create and register the MBean");
+            ObjectName objName = new ObjectName("sqe:type=Basic,protocol=rmi") ;
+            mbsc.createMBean(BASIC_MXBEAN_CLASS_NAME, objName);
+            System.out.println("---- OK\n") ;
+
+            // ----
+            System.out.println("MXBeanNotifTest::run: Add me as notification listener");
+            mbsc.addNotificationListener(objName, this, null, null);
+
+            // ----
+            System.out.println("MXBeanNotifTest::run: Retrieve the Descriptor"
+                    + " that should be in MBeanNotificationInfo");
+            TabularData tabData =
+                (TabularData)mbsc.getAttribute(objName, "NotifDescriptorAsMapAtt");
+            Map<String, String> descrMap = new HashMap<>();
+
+            for (Iterator<?> it = tabData.values().iterator(); it.hasNext(); ) {
+                CompositeData compData = (CompositeData)it.next();
+                descrMap.put((String)compData.get("key"),
+                        (String)compData.get("value"));
+            }
+
+            Descriptor refNotifDescriptor = new ImmutableDescriptor(descrMap);
+            System.out.println("---- OK\n") ;
+
+            // ----
+            // Because the MBean holding the targeted attribute is MXBean, we
+            // should use for the setAttribute a converted form for the
+            // attribute value as described by the MXBean mapping rules.
+            // This explains all that lovely stuff for creating a
+            // TabularDataSupport.
+            //
+            // WARNING : the MBeanInfo of the MXBean used on opposite side
+            // is computed when the MBean is registered.
+            // It means the Descriptor considered for the MBeanNotificationInfo
+            // is not the one we set in the lines below, it is too late.
+            // However, we check that set is harmless when we check
+            // the MBeanNotificationInfo.
+            //
+            System.out.println("MXBeanNotifTest::run: Set a Map<String, String>"
+                    + " attribute");
+            String typeName =
+                    "java.util.Map<java.lang.String,java.lang.String>";
+            String[] keyValue = new String[] {"key", "value"};
+            OpenType<?>[] openTypes =
+                    new OpenType<?>[] {SimpleType.STRING, SimpleType.STRING};
+            CompositeType rowType = new CompositeType(typeName, typeName,
+                    keyValue, keyValue, openTypes);
+            TabularType tabType = new TabularType(typeName, typeName,
+                    rowType, new String[]{"key"});
+            TabularDataSupport convertedDescrMap =
+                    new TabularDataSupport(tabType);
+
+            for (int i = 0; i < numOfNotifDescriptorElements; i++) {
+                Object[] descrValue = {"field" + i, "value" + i};
+                CompositeData data =
+                        new CompositeDataSupport(rowType, keyValue, descrValue);
+                convertedDescrMap.put(data);
+            }
+
+            Attribute descrAtt =
+                    new Attribute("NotifDescriptorAsMapAtt", convertedDescrMap);
+            mbsc.setAttribute(objName, descrAtt);
+            System.out.println("---- OK\n") ;
+
+            // ----
+            System.out.println("MXBeanNotifTest::run: Compare the Descriptor from"
+                    + " the MBeanNotificationInfo against a reference");
+            MBeanInfo mbInfo = mbsc.getMBeanInfo(objName);
+            errorCount += checkMBeanInfo(mbInfo, refNotifDescriptor);
+            System.out.println("---- DONE\n") ;
+
+            // ----
+            System.out.println("Check isInstanceOf(Basic)");
+
+            if ( ! mbsc.isInstanceOf(objName, BASIC_MXBEAN_CLASS_NAME) ) {
+                errorCount++;
+                System.out.println("---- ERROR isInstanceOf returned false\n") ;
+            } else {
+                System.out.println("---- OK\n") ;
+            }
+
+            // ----
+            System.out.println("Check isInstanceOf(BasicMXBean)");
+
+            if ( ! mbsc.isInstanceOf(objName, BASIC_MXBEAN_INTERFACE_NAME) ) {
+                errorCount++;
+                System.out.println("---- ERROR isInstanceOf returned false\n") ;
+            } else {
+                System.out.println("---- OK\n") ;
+            }
+
+            // ----
+            System.out.println("MXBeanNotifTest::run: Ask for "
+                    + numOfNotifications + " notification(s)");
+            Object[] sendNotifParam = new Object[1];
+            String[] sendNotifSig = new String[]{"java.lang.String"};
+
+            for (int i = 0; i < numOfNotifications; i++) {
+                // Select which type of notification we ask for
+                if ( i % 2 == 0 ) {
+                    sendNotifParam[0] = Basic.NOTIF_TYPE_0;
+                } else {
+                    sendNotifParam[0] = Basic.NOTIF_TYPE_1;
+                }
+
+                // Trigger notification emission
+                mbsc.invoke(objName,
+                        "sendNotification",
+                        sendNotifParam,
+                        sendNotifSig);
+
+                // Wait for it then check it when it comes early enough
+                Notification notif =
+                        notifList.poll(timeForNotificationInSeconds,
+                        TimeUnit.SECONDS) ;
+                // The very first notification is likely to come in slower than
+                // all the others. Because that test isn't targeting the speed
+                // notifications are delivered with, we prefer to secure it.
+                if (i == 0 && notif == null) {
+                    System.out.println("MXBeanNotifTest::run: Wait extra "
+                            + timeForNotificationInSeconds + " second(s) the "
+                            + " very first notification");
+                    notif = notifList.poll(timeForNotificationInSeconds,
+                            TimeUnit.SECONDS);
+                }
+
+                if ( notif == null ) {
+                    errorCount++;
+                    System.out.println("---- ERROR No notification received"
+                            + " within allocated " + timeForNotificationInSeconds
+                            + " second(s) !");
+                } else {
+                    errorCount +=
+                            checkNotification(notif,
+                            (String)sendNotifParam[0],
+                            Basic.NOTIFICATION_MESSAGE,
+                            objName);
+                }
+            }
+
+            int toc = 0;
+            while ( notifList.size() < 2 && toc < 10 ) {
+                Thread.sleep(499);
+                toc++;
+            }
+            System.out.println("---- DONE\n") ;
+        } catch(Exception e) {
+            Utils.printThrowable(e, true) ;
+            throw new RuntimeException(e);
+        }
+
+        if ( errorCount == 0 ) {
+            System.out.println("MXBeanNotifTest::run: Done without any error") ;
+        } else {
+            System.out.println("MXBeanNotifTest::run: Done with "
+                    + errorCount
+                    + " error(s)") ;
+            throw new RuntimeException("errorCount = " + errorCount);
+        }
+    }
+
+
+    private int checkMBeanInfo(MBeanInfo mbi, Descriptor refDescr) {
+        MBeanNotificationInfo[] notifsInfo = mbi.getNotifications();
+        int res = 0;
+
+        for (MBeanNotificationInfo mbni : notifsInfo) {
+            if ( mbni.getDescriptor().equals(refDescr) ) {
+                System.out.println("(OK)");
+            } else {
+                System.out.println("(ERROR) Descriptor of the notification is "
+                        + mbni.getDescriptor()
+                        + " as we expect "
+                        + refDescr);
+                res++;
+            }
+        }
+
+        return res;
+    }
+
+
+    private int checkNotification(Notification notif,
+            String refType,
+            String refMessage,
+            ObjectName refSource) {
+        int res = 0;
+
+        Utils.debug(Utils.DEBUG_VERBOSE,
+                "\t getSource " + notif.getSource());
+        Utils.debug(Utils.DEBUG_VERBOSE,
+                "\t getMessage " + notif.getMessage());
+        Utils.debug(Utils.DEBUG_VERBOSE,
+                "\t getSequenceNumber " + notif.getSequenceNumber());
+        Utils.debug(Utils.DEBUG_VERBOSE,
+                "\t getTimeStamp " + notif.getTimeStamp());
+        Utils.debug(Utils.DEBUG_VERBOSE,
+                "\t getType " + notif.getType());
+        Utils.debug(Utils.DEBUG_VERBOSE,
+                "\t getUserData " + notif.getUserData());
+
+        if ( ! notif.getType().equals(refType) ) {
+            res++;
+            System.out.println("(ERROR) Type is not "
+                    + refType + " in notification\n" + notif);
+        } else {
+            if ( notif.getType().equals(Basic.NOTIF_TYPE_0)
+            && ! (notif instanceof javax.management.Notification) ) {
+                res++;
+                System.out.println("(ERROR) Notification is not instance of "
+                        + " javax.management.Notification but rather "
+                        + notif.getClass().getName());
+            } else if ( notif.getType().equals(Basic.NOTIF_TYPE_1)
+            && ! (notif instanceof SqeNotification) ) {
+                res++;
+                System.out.println("(ERROR) Notification is not instance of "
+                        + " javasoft.sqe.jmx.share.SqeNotification but rather "
+                        + notif.getClass().getName());
+            }
+        }
+
+        if ( ! notif.getMessage().equals(refMessage) ) {
+            res++;
+            System.out.println("(ERROR) Message is not "
+                    + refMessage + " in notification\n" + notif);
+        }
+
+        if ( ! notif.getSource().equals(refSource) ) {
+            res++;
+            System.out.println("(ERROR) Source is not "
+                    + refSource + " in notification\n" + notif);
+        }
+
+        return res;
+    }
+
+    public void handleNotification(Notification notification, Object handback) {
+        Utils.debug(Utils.DEBUG_VERBOSE,
+                "MXBeanNotifTest::handleNotification: Received "
+                + notification);
+        notifList.add(notification);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/mxbean/MXBeanWeirdParamTest.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8058865
+ * @summary Checks that a serialized instance is not transmitted from an MXBean.
+ * All the communication should be done via Open Types
+ * @author Olivier Lagneau
+ * @modules java.management
+ * @library /lib/testlibrary
+ * @compile Basic.java
+ * @run main/othervm/timeout=300 -DDEBUG_STANDARD MXBeanWeirdParamTest
+ */
+
+import java.util.Map;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import java.lang.Process;
+import java.lang.management.ManagementFactory;
+
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+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;
+
+import javax.management.ObjectName;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+import javax.management.openmbean.TabularDataSupport;
+import javax.management.openmbean.TabularType;
+
+import jdk.testlibrary.ProcessTools;
+import jdk.testlibrary.JDKToolFinder;
+
+public class MXBeanWeirdParamTest {
+
+    private static String BASIC_MXBEAN_CLASS_NAME = "Basic";
+
+    private static final String CLIENT_CLASS_MAIN =
+        "MXBeanWeirdParamTest$ClientSide";
+
+    private JMXConnectorServer cs;
+
+    /*
+     * First Debug properties and arguments are collect in expected
+     * map  (argName, value) format, then calls original test's run method.
+     */
+    public static void main(String args[]) throws Exception {
+
+        System.out.println("=================================================");
+
+        // Parses parameters
+        Utils.parseDebugProperties();
+        Map<String, Object> map = Utils.parseParameters(args) ;
+
+        // Run test
+        MXBeanWeirdParamTest test = new MXBeanWeirdParamTest();
+        test.run(map);
+
+    }
+
+    /*
+     * Create the MBeansServe side of the test and returns its address
+     */
+    private JMXServiceURL createServerSide() throws Exception {
+        final int NINETY_SECONDS = 90;
+
+        // We will use the platform mbean server
+        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+
+        JMXServiceURL url = new JMXServiceURL("rmi", null, 0);
+        cs = JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);
+        cs.start();
+
+        Utils.waitReady(cs, NINETY_SECONDS);
+
+        JMXServiceURL addr = cs.getAddress();
+        return addr;
+    }
+
+
+    /*
+     * Creating command-line for running subprocess JVM:
+     *
+     * JVM command line is like:
+     * {test_jdk}/bin/java {defaultopts} -cp {test.class.path} {testopts} main
+     *
+     * {defaultopts} are the default java options set by the framework.
+     *
+     */
+    private List<String> buildCommandLine() {
+        List<String> opts = new ArrayList<>();
+        opts.add(JDKToolFinder.getJDKTool("java"));
+        opts.addAll(Arrays.asList(jdk.testlibrary.Utils.getTestJavaOpts()));
+        // We need to set WEIRD_PARAM propertty on the client-side
+        opts.add("-DWEIRD_PARAM");
+        opts.add("-cp");
+        opts.add(System.getProperty("test.class.path", "test.class.path"));
+        opts.add(CLIENT_CLASS_MAIN);
+
+        return opts;
+    }
+
+    /**
+     * Runs MXBeanWeirdParamTest$ClientSide with the passed options and redirects
+     * subprocess standard I/O to the current (parent) process. This provides a
+     * trace of what happens in the subprocess while it is runnning (and before
+     * it terminates).
+     *
+     * @param serviceUrlStr string representing the JMX service Url to connect to.
+     */
+    private int runClientSide(String serviceUrlStr) throws Exception {
+
+        // Building command-line
+        List<String> opts = buildCommandLine();
+        opts.add(serviceUrlStr);
+
+        // Launch separate JVM subprocess
+        int exitCode = 0;
+        String[] optsArray = opts.toArray(new String[0]);
+        ProcessBuilder pb = new ProcessBuilder(optsArray);
+        Process p = ProcessTools.startProcess("MXBeanWeirdParamTest$ClientSide", pb);
+
+        // Handling end of subprocess
+        try {
+            exitCode = p.waitFor();
+            if (exitCode != 0) {
+                System.out.println(
+                    "Subprocess unexpected exit value of [" + exitCode +
+                    "]. Expected 0.\n");
+            }
+        } catch (InterruptedException e) {
+            System.out.println("Parent process interrupted with exception : \n " + e + " :" );
+
+            // Parent thread unknown state, killing subprocess.
+            p.destroyForcibly();
+
+            throw new RuntimeException(
+                "Parent process interrupted with exception : \n " + e + " :" );
+        } finally {
+            return exitCode;
+        }
+
+     }
+
+    public void run(Map<String, Object> args) throws Exception {
+
+        System.out.println("MXBeanWeirdParamTest::run: Start") ;
+        int errorCount = 0;
+
+        try {
+            // Initialise the server side
+            JMXServiceURL urlToUse = createServerSide();
+
+            // Run client side
+            errorCount = runClientSide(urlToUse.toString());
+
+            if ( errorCount == 0 ) {
+                System.out.println("MXBeanWeirdParamTest::run: Done without any error") ;
+            } else {
+                System.out.println("MXBeanWeirdParamTest::run: Done with "
+                        + errorCount
+                        + " error(s)") ;
+                throw new RuntimeException("errorCount = " + errorCount);
+            }
+
+            cs.stop();
+
+        } catch(Exception e) {
+            throw new RuntimeException(e);
+        }
+
+    }
+
+    private static class ClientSide {
+        public static void main(String args[]) throws Exception {
+
+            int errorCount = 0 ;
+            String msgTag = "ClientSide::main: ";
+
+            try {
+
+                // Get a connection to remote mbean server
+                JMXServiceURL addr = new JMXServiceURL(args[0]);
+                JMXConnector cc = JMXConnectorFactory.connect(addr);
+                MBeanServerConnection mbsc = cc.getMBeanServerConnection();
+
+                // ----
+                System.out.println(msgTag + "Create and register the MBean");
+                ObjectName objName = new ObjectName("sqe:type=Basic,protocol=rmi") ;
+                mbsc.createMBean(BASIC_MXBEAN_CLASS_NAME, objName);
+                System.out.println(msgTag +"---- OK\n") ;
+
+                // ----
+                System.out.println(msgTag +"Get attribute SqeParameterAtt on our MXBean");
+                Object result = mbsc.getAttribute(objName, "SqeParameterAtt");
+                System.out.println(msgTag +"(OK) Got result of class "
+                        + result.getClass().getName());
+                System.out.println(msgTag +"Received CompositeData is " + result);
+                System.out.println(msgTag +"---- OK\n") ;
+
+                // ----
+                // We use the value returned by getAttribute to perform the invoke.
+                System.out.println(msgTag +"Call operation doWeird on our MXBean [1]");
+                mbsc.invoke(objName, "doWeird",
+                        new Object[]{result},
+                        new String[]{"javax.management.openmbean.CompositeData"});
+                System.out.println(msgTag +"---- OK\n") ;
+
+                // ----
+                // We build the CompositeData ourselves that time.
+                System.out.println(msgTag +"Call operation doWeird on our MXBean [2]");
+                String typeName = "SqeParameter";
+                String[] itemNames = new String[] {"glop"};
+                OpenType<?>[] openTypes = new OpenType<?>[] {SimpleType.STRING};
+                CompositeType rowType = new CompositeType(typeName, typeName,
+                        itemNames, itemNames, openTypes);
+                Object[] itemValues = {"HECTOR"};
+                CompositeData data =
+                        new CompositeDataSupport(rowType, itemNames, itemValues);
+                TabularType tabType = new TabularType(typeName, typeName,
+                        rowType, new String[]{"glop"});
+                TabularDataSupport tds = new TabularDataSupport(tabType);
+                tds.put(data);
+                System.out.println(msgTag +"Source CompositeData is " + data);
+                mbsc.invoke(objName, "doWeird",
+                        new Object[]{data},
+                        new String[]{"javax.management.openmbean.CompositeData"});
+                System.out.println(msgTag +"---- OK\n") ;
+
+                // ----
+                System.out.println(msgTag +"Unregister the MBean");
+                mbsc.unregisterMBean(objName);
+                System.out.println(msgTag +"---- OK\n") ;
+
+                // Terminate the JMX Client
+                cc.close();
+
+            } catch(Exception e) {
+                Utils.printThrowable(e, true) ;
+                errorCount++;
+                throw new RuntimeException(e);
+            } finally {
+                System.exit(errorCount);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/mxbean/SqeDescriptorKey.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import javax.management.DescriptorKey;
+
+/**
+ * That annotation is usable everywhere DescriptorKey is (and even more).
+ * It is for use to test that you can retrieve the SqeDescriptorKey into the
+ * appropriate Descriptor instances as built by the JMX runtime.
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+public @interface SqeDescriptorKey {
+    @DescriptorKey("sqeDescriptorKey")
+    String value();
+
+    // List descriptor fields that may be added or may be updated
+    // when retrieving an MBeanInfo using a JMXWS connection compared to the
+    // MBeanInfo returned by a local MBeanServer.
+    // The annotation format is :
+    //   <descriptorFieldName>=<descriptorFieldValue>
+    // The values actually handled by the test suite are :
+    //   openType=SimpleType.VOID
+    @DescriptorKey("descriptorFields")
+    String[] descriptorFields() default {};
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/mxbean/SqeNotification.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import javax.management.Notification;
+
+/**
+ * Could hold someday a specific semantic.
+ * For now it is used to have a Notification which of another class, no more.
+ */
+public class SqeNotification extends Notification {
+
+    /** Creates a new instance of SqeNotification */
+    public SqeNotification(String type, Object source, long sequenceNumber) {
+        super(type, source, sequenceNumber);
+    }
+
+    /** Creates a new instance of SqeNotification */
+    public SqeNotification(String type, Object source, long sequenceNumber,
+            long timeStamp) {
+        super(type, source, sequenceNumber, timeStamp);
+    }
+
+    /** Creates a new instance of SqeNotification */
+    public SqeNotification(String type, Object source, long sequenceNumber,
+            long timeStamp, String message) {
+        super(type, source, sequenceNumber, timeStamp, message);
+    }
+
+    /** Creates a new instance of SqeNotification */
+    public SqeNotification(String type, Object source, long sequenceNumber,
+            String message) {
+        super(type, source, sequenceNumber, message);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/mxbean/SqeParameter.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.Serializable;
+
+/**
+ * That class is to use as an MBean operation parameter or returned value.
+ * The property Glop with its public getter + setter is only there to be
+ * reconstructible following MXBean specification, so that SqeParameter can be
+ * used for what it is designed to.
+ */
+public class SqeParameter implements Serializable {
+
+    private static boolean weird;
+    private String glop;
+
+    static {
+        if ( System.getProperty("WEIRD_PARAM") != null ) {
+            weird = true;
+        }
+    }
+
+    /**
+     * Creates a new instance of SqeParameter.
+     * <br>When the Java property WEIRD_PARAM is set, that constructor
+     * throws an exception.
+     * <br>That can be used to ensure the class is instantiated on server side
+     * but never on client side.
+     */
+    public SqeParameter() throws Exception {
+        if ( weird ) {
+            throw new Exception();
+        }
+    }
+
+    public String getGlop() {
+        return glop;
+    }
+
+    public void setGlop(String value) {
+        glop = value;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/mxbean/Utils.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Properties;
+import java.lang.reflect.Method;
+import javax.management.remote.JMXConnectorServerMBean;
+
+// utility class for MXBean* tests coming from JMX Tonga test suite
+class Utils {
+
+    // DEBUG is printed depending on the DEBUG and DEBUG_LEVEL JAVA property
+    private static final String DEBUG_HEADER = "[debug] ";
+
+    // DEBUG levels
+    private static int selectedDebugLevel = 0;
+    static final int DEBUG_STANDARD = 1;
+    static final int DEBUG_VERBOSE = 2;  // Mainly used for stress tests
+    static final int DEBUG_ALL = DEBUG_STANDARD | DEBUG_VERBOSE;
+
+    static void parseDebugProperties() {
+        int level = 0;
+        Properties p = System.getProperties();
+
+        // get selected levels
+        if (p.getProperty("DEBUG_STANDARD") != null) {
+            level |= DEBUG_STANDARD;
+        }
+
+        if (p.getProperty("DEBUG_VERBOSE") != null) {
+            level |= DEBUG_VERBOSE;
+        }
+
+        if (p.getProperty("DEBUG_ALL") != null) {
+            level |= DEBUG_ALL;
+        }
+
+        selectedDebugLevel = level;
+    }
+
+    /**
+     * Reproduces the original parsing and collection of test parameters
+     * from the DTonga JMX test suite.
+     *
+     * Collects passed args and returns them in a map(argname, value) structure,
+     * which will be then propagated as necessary to various called methods.
+     */
+    static Map<String, Object> parseParameters(String args[])
+    throws Exception {
+        Utils.debug(DEBUG_STANDARD, "TestRoot::parseParameters: Start");
+        HashMap<String, Object> map = new HashMap<>();
+
+        for ( int i = 0; i < args.length; i++ ) {
+            if ( args[i].trim().startsWith("-") ) {
+                if ((i+1) < args.length && !args[i+1].startsWith("-") ) {
+                    Utils.debug(DEBUG_STANDARD,
+                        "TestRoot::parseParameters: added in map = " +
+                        args[i] +
+                        " with value " +
+                        args[i+1]) ;
+                    map.put(args[i].trim(), args[i+1].trim()) ;
+                } else if ((i+1) < args.length && args[i+1].startsWith("-") ||
+                           (i+1) == args.length ) {
+                    Utils.debug(DEBUG_STANDARD,
+                            "TestRoot::parseParameters: added in map = " +
+                            args[i] +
+                            " with null value") ;
+                    map.put(args[i].trim(), null) ;
+                } else {
+                    System.out.println(
+                        "TestRoot::parseParameters: (WARNING) not added in map = " +
+                        args[i]) ;
+                }
+            }
+        }
+
+        Utils.debug(DEBUG_STANDARD, "TestRoot::parseParameters: Done") ;
+        return map ;
+    }
+
+    /**
+     * This method is to be used in all tests to print anything
+     * that is temporary.
+     * Printing is done only when debug is activated by the property DEBUG.
+     * Printing depends also on the DEBUG_LEVEL property.
+     * Here it encapsulates a System.out.println.
+     */
+    public static void debug(int level, String line) {
+        if ((selectedDebugLevel & level) != 0) {
+            System.out.println(DEBUG_HEADER + line);
+        }
+    }
+
+    /**
+     * Do print stack trace when withStack is true.
+     * Does try to call getTargetException() and getTargetError() then
+     * print embedded stacks in the case of an Exception wrapping
+     * another Exception or an Error. Recurse until no more wrapping
+     * is found.
+     */
+    public static void printThrowable(Throwable theThro, boolean withStack) {
+        try {
+            if (withStack) {
+                theThro.printStackTrace(System.out);
+            }
+            if (theThro instanceof Exception) {
+                Exception t = (Exception) theThro;
+                Method target = null;
+                String blank = " ";
+                try {
+                    target = t.getClass().getMethod("getTargetException",
+                            (java.lang.Class<?>[]) null);
+                } catch (Exception ee) {
+                // OK: getTargetException method could be there or not
+                }
+                System.out.println(blank + t.getClass() + "==>" + t.getMessage());
+                while (target != null) {
+                    try {
+                        t = (Exception) target.invoke(t,
+                                (java.lang.Object[]) null);
+                    } catch (Exception ee) {
+                        t = null;
+                    }
+                    try {
+                        if (t != null) {
+                            blank = blank + "  ";
+                            System.out.println(blank + t.getClass() + "==>" +
+                                    t.getMessage());
+                            try {
+                                target =
+                                        t.getClass().getMethod("getTargetException",
+                                        (java.lang.Class<?>[]) null);
+                            } catch (Exception ee) {
+                            // OK: getTargetException method could be there or not                            }
+                            }
+                        } else {
+                            target = null;
+                        }
+                    } catch (Exception ee) {
+                        target = null;
+                    }
+                }
+
+                // We may have exceptions wrapping an Error then it is
+                // getTargetError that is likely to be called
+                try {
+                    target = ((Exception) theThro).getClass().getMethod("getTargetError",
+                            (java.lang.Class<?>[]) null);
+                } catch (Exception ee) {
+                // OK: getTargetError method could be there or not
+                }
+                Throwable err = theThro;
+                while (target != null) {
+                    try {
+                        err = (Error) target.invoke(err,
+                                (java.lang.Object[]) null);
+                    } catch (Exception ee) {
+                        err = null;
+                    }
+                    try {
+                        if (err != null) {
+                            blank = blank + "  ";
+                            System.out.println(blank + err.getClass() + "==>" +
+                                    err.getMessage());
+                            if (withStack) {
+                                err.printStackTrace(System.out);
+                            }
+                            try {
+                                target = err.getClass().getMethod("getTargetError",
+                                        (java.lang.Class<?>[]) null);
+                            } catch (Exception ee) {
+                            // OK: getTargetError method could be there or not
+                            }
+                        } else {
+                            target = null;
+                        }
+                    } catch (Exception ee) {
+                        target = null;
+                    }
+                }
+            } else {
+                System.out.println("Throwable is : " + theThro);
+            }
+        } catch (Throwable x) {
+            System.out.println("Exception : raised in printException : " + x);
+        }
+    }
+
+    /**
+     * Wait up to maxTimeInSeconds second(s) the given JMX connector server
+     * comes up (which means isActive returns true).
+     * If it fails to do so we throw a RunTime exception.
+     */
+    public static void waitReady(JMXConnectorServerMBean server,
+                                 int maxTimeInSeconds) throws Exception {
+        int elapsed = 0;
+
+        while (!server.isActive() && elapsed < maxTimeInSeconds) {
+            Thread.sleep(1000);
+            elapsed++;
+        }
+
+        if (server.isActive()) {
+            String message = "Utils::waitReady: JMX connector server came up";
+            if ( elapsed == 0) {
+                message += " immediately";
+            } else {
+                message += " after " + elapsed + " seconds";
+            }
+            message += " [" + server.getAddress() + "]";
+            Utils.debug(DEBUG_STANDARD, message);
+        } else {
+            String message = "Utils::waitReady: (ERROR) JMX connector" +
+                    " server didn't come up after " + elapsed + " seconds [" +
+                    server.getAddress() + "]";
+            System.out.println(message);
+            throw new RuntimeException(message);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/query/QueryData.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+public abstract class QueryData {
+    protected int intValue = 9;
+    protected long longValue = 9L;
+    protected Integer integerValue = Integer.valueOf(9);
+    protected boolean booleanValue = true;
+    protected double doubleValue = 9D;
+    protected float floatValue = 9.0F;
+    protected String stringValue = "9";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/query/QueryFactory.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,328 @@
+/*
+ * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.util.ArrayList;
+
+import javax.management.Query;
+import javax.management.QueryExp;
+import javax.management.ValueExp;
+
+/**
+ * Class used for building QueryExp instances of all every possible type
+ * in terms of JMX API members; note that several JMX classes are private
+ * and appears in the JDK API only by their serial form.
+ * Comments in each case of the big switch in method getQuery() details which
+ * API member we cover with a given query.
+ */
+public class QueryFactory extends QueryData {
+
+    private String mbeanClassName = "";
+    private String primitiveIntAttName = "IntAtt";
+    private String primitiveLongAttName = "LongAtt";
+    private String integerAttName = "IntegerAtt";
+    private String primitiveBooleanAttName = "BooleanAtt";
+    private String primitiveDoubleAttName = "DoubleAtt";
+    private String primitiveFloatAttName = "FloatAtt";
+    private String stringAttName = "StringAtt";
+    private ArrayList<QueryExp> queries = new ArrayList<QueryExp>();
+
+    /**
+     * Creates a new instance of QueryFactory.
+     * The name is the fully qualified class name of an MBean.
+     * There is severe constraints on that MBean that must:
+     * <ul>
+     * <li>extend QueryData in order to inherit attribute values.
+     * <li>define a RW attribute IntAtt of type int
+     * initialized to QueryData.longValue
+     * <li>define a RW attribute LongAtt of type long
+     * initialized to QueryData.intValue
+     * <li>define a RW attribute IntegerAtt of type Integer
+     * initialized to QueryData.integerValue
+     * <li>define a RW attribute BooleanAtt of type boolean
+     * initialized to QueryData.booleanValue
+     * <li>define a RW attribute DoubleAtt of type double
+     * initialized to QueryData.doubleValue
+     * <li>define a RW attribute FloatAtt of type float
+     * initialized to QueryData.floatValue
+     * <li>define a RW attribute StringAtt of type String
+     * initialized to QueryData.stringValue
+     * </ul>
+     */
+    public QueryFactory(String name) {
+        this.mbeanClassName = name;
+    }
+
+    /**
+     * Returns the highest index value the method getQuery supports.
+     * WARNING : returns 0 if buildQueries haven't been called first !
+     */
+    public int getSize() {
+        return queries.size();
+    }
+
+    /**
+     * Populates an ArrayList of QueryExp.
+     * Lowest index is 1.
+     * Highest index is returned by getSize().
+     * <br>The queries numbered 1 to 23 allow to cover all the underlying
+     * Java classes of the JMX API used to build queries.
+     */
+    public void buildQueries() {
+        if ( queries.size() == 0 ) {
+            int smallerIntValue = intValue - 1;
+            int biggerIntValue = intValue + 1;
+
+            // case 1:
+            // True if the MBean is of class mbeanClassName
+            // We cover javax.management.InstanceOfQueryExp
+            queries.add(Query.isInstanceOf(Query.value(mbeanClassName)));
+
+            // case 2:
+            // True if the MBean is of class mbeanClassName
+            // We cover javax.management.MatchQueryExp and
+            // javax.management.ClassAttributeValueExp
+            queries.add(Query.match(Query.classattr(),
+                    Query.value(mbeanClassName)));
+
+            // case 3:
+            // True if an attribute named primitiveIntAttName of type int has
+            // the value intValue
+            // We cover javax.management.BinaryRelQueryExp with
+            // a relOp equal to EQ and javax.management.NumericValueExp
+            queries.add(Query.eq(Query.attr(primitiveIntAttName),
+                    Query.value(intValue)));
+
+            // case 4:
+            // True if an attribute named primitiveLongAttName of type long has
+            // the value longValue
+            // We cover javax.management.BinaryRelQueryExp with
+            // a relOp equal to EQ and javax.management.NumericValueExp
+            queries.add(Query.eq(Query.attr(primitiveLongAttName),
+                    Query.value(longValue)));
+
+            // case 5:
+            // True if an attribute named primitiveDoubleAttName of type double
+            // has the value doubleValue
+            // We cover javax.management.BinaryRelQueryExp with
+            // a relOp equal to EQ and javax.management.NumericValueExp
+            queries.add(Query.eq(Query.attr(primitiveDoubleAttName),
+                    Query.value(doubleValue)));
+
+            // case 6:
+            // True if an attribute named primitiveFloatAttName of type float
+            // has the value floatValue
+            // We cover javax.management.BinaryRelQueryExp with
+            // a relOp equal to EQ and javax.management.NumericValueExp
+            queries.add(Query.eq(Query.attr(primitiveFloatAttName),
+                    Query.value(floatValue)));
+
+            // case 7:
+            // True if an attribute named primitiveIntAttName of type int is
+            // hold by an MBean of class mbeanClassName and has
+            // the value intValue
+            // We cover javax.management.QualifiedAttributeValueExp
+            queries.add(Query.eq(Query.attr(mbeanClassName, primitiveIntAttName),
+                    Query.value(intValue)));
+
+            // case 8:
+            // True if an attribute named stringAttName of type String has
+            // the value stringValue
+            // We cover javax.management.BinaryRelQueryExp with
+            // a relOp equal to EQ and javax.management.StringValueExp
+            queries.add(Query.eq(Query.attr(stringAttName),
+                    Query.value(stringValue)));
+
+            // case 9:
+            // True if an attribute named integerAttName of type Integer has
+            // the value integerValue
+            // We cover javax.management.BinaryRelQueryExp with
+            // a relOp equal to EQ and javax.management.NumericValueExp
+            queries.add(Query.eq(Query.attr(integerAttName),
+                    Query.value(integerValue)));
+
+            // case 10:
+            // True if an attribute named primitiveBooleanAttName of type boolean
+            // has the value booleanValue
+            // We cover javax.management.BinaryRelQueryExp with
+            // a relOp equal to EQ and javax.management.BooleanValueExp
+            queries.add(Query.eq(Query.attr(primitiveBooleanAttName),
+                    Query.value(booleanValue)));
+
+            // case 11:
+            // True if an attribute named primitiveIntAttName of type int has
+            // not the value smallerIntValue
+            // We cover javax.management.NotQueryExp
+            queries.add(Query.not(Query.eq(Query.attr(primitiveIntAttName),
+                    Query.value(smallerIntValue))));
+
+            // case 12:
+            // True if either
+            // an attribute named primitiveIntAttName of type int has
+            // the value intValue
+            // or
+            // an attribute named primitiveLongAttName of type long has
+            // the value longValue
+            // We cover javax.management.OrQueryExp
+            queries.add(Query.or(
+                    Query.eq(Query.attr(primitiveIntAttName),
+                    Query.value(intValue)),
+                    Query.eq(Query.attr(primitiveLongAttName),
+                    Query.value(longValue))));
+
+            // case 13:
+            // True if
+            // an attribute named primitiveIntAttName of type int has
+            // the value intValue
+            // and
+            // an attribute named primitiveLongAttName of type long has
+            // the value longValue
+            // We cover javax.management.AndQueryExp
+            queries.add(Query.and(
+                    Query.eq(Query.attr(primitiveIntAttName),
+                    Query.value(intValue)),
+                    Query.eq(Query.attr(primitiveLongAttName),
+                    Query.value(longValue))));
+
+            // case 14:
+            // True if an attribute named primitiveIntAttName of type int has
+            // the value intValue
+            // We cover javax.management.InQueryExp
+            ValueExp[] inArray = {Query.value(intValue)};
+            queries.add(Query.in(Query.attr(primitiveIntAttName), inArray));
+
+            // case 15:
+            // True if an attribute named primitiveIntAttName of type int has
+            // its value in between smallerIntValue and biggerIntValue
+            // We cover javax.management.BetweenRelQueryExp
+            queries.add(Query.between(Query.attr(primitiveIntAttName),
+                    Query.value(smallerIntValue),
+                    Query.value(biggerIntValue)));
+
+            // case 16:
+            // True if an attribute named primitiveIntAttName of type int has
+            // a value greater than smallerIntValue
+            // We cover javax.management.BinaryRelQueryExp with
+            // a relOp equal to GT
+            queries.add(Query.gt(Query.attr(primitiveIntAttName),
+                    Query.value(smallerIntValue)));
+
+            // case 17:
+            // True if an attribute named primitiveIntAttName of type int has
+            // a value greater or equal to smallerIntValue
+            // We cover javax.management.BinaryRelQueryExp with
+            // a relOp equal to GE
+            queries.add(Query.geq(Query.attr(primitiveIntAttName),
+                    Query.value(smallerIntValue)));
+
+            // case 18:
+            // True if an attribute named primitiveIntAttName of type int has
+            // a value smaller than biggerIntValue
+            // We cover javax.management.BinaryRelQueryExp with
+            // a relOp equal to LT
+            queries.add(Query.lt(Query.attr(primitiveIntAttName),
+                    Query.value(biggerIntValue)));
+
+            // case 19:
+            // True if an attribute named primitiveIntAttName of type int has
+            // a value smaller or equal to biggerIntValue
+            // We cover javax.management.BinaryRelQueryExp with
+            // a relOp equal to LE
+            queries.add(Query.leq(Query.attr(primitiveIntAttName),
+                    Query.value(biggerIntValue)));
+
+            // case 20:
+            // True if an attribute named primitiveIntAttName of type int has
+            // a value equal to intValue minus zero
+            // We cover javax.management.BinaryRelQueryExp with
+            // a relOp equal to MINUS
+            queries.add(Query.eq(Query.attr(primitiveIntAttName),
+                    Query.minus(Query.value(intValue), Query.value(0))));
+
+            // case 21:
+            // True if an attribute named primitiveIntAttName of type int has
+            // a value equal to intValue plus zero
+            // We cover javax.management.BinaryRelQueryExp with
+            // a relOp equal to PLUS
+            queries.add(Query.eq(Query.attr(primitiveIntAttName),
+                    Query.plus(Query.value(intValue), Query.value(0))));
+
+            // case 22:
+            // True if an attribute named primitiveIntAttName of type int has
+            // a value equal to intValue divided by one
+            // We cover javax.management.BinaryRelQueryExp with
+            // a relOp equal to DIV
+            queries.add(Query.eq(Query.attr(primitiveIntAttName),
+                    Query.div(Query.value(intValue), Query.value(1))));
+
+            // case 23:
+            // True if an attribute named primitiveIntAttName of type int has
+            // a value equal to intValue multiplicated by one
+            // We cover javax.management.BinaryRelQueryExp with
+            // a relOp equal to TIMES
+            queries.add(Query.eq(Query.attr(primitiveIntAttName),
+                    Query.times(Query.value(intValue), Query.value(1))));
+
+            // case 24:
+            // That query is a complex one that combines within a big AND
+            // queries with index 2 to 23 inclusive. But because a List is
+            // zero based, we must decrement all indexes by 1 when retrieving
+            // any previously stored query.
+            QueryExp q2_3 = Query.and(queries.get(2-1), queries.get(3-1));
+            QueryExp q4_5 = Query.and(queries.get(4-1), queries.get(5-1));
+            QueryExp q6_7 = Query.and(queries.get(6-1), queries.get(7-1));
+            QueryExp q8_9 = Query.and(queries.get(8-1), queries.get(9-1));
+            QueryExp q10_11 = Query.and(queries.get(10-1), queries.get(11-1));
+            QueryExp q12_13 = Query.and(queries.get(12-1), queries.get(13-1));
+            QueryExp q14_15 = Query.and(queries.get(14-1), queries.get(15-1));
+            QueryExp q16_17 = Query.and(queries.get(16-1), queries.get(17-1));
+            QueryExp q18_19 = Query.and(queries.get(18-1), queries.get(19-1));
+            QueryExp q20_21 = Query.and(queries.get(20-1), queries.get(21-1));
+            QueryExp q22_23 = Query.and(queries.get(22-1), queries.get(23-1));
+            QueryExp q2_5 = Query.and(q2_3, q4_5);
+            QueryExp q6_9 = Query.and(q6_7, q8_9);
+            QueryExp q10_13 = Query.and(q10_11, q12_13);
+            QueryExp q14_17 = Query.and(q14_15, q16_17);
+            QueryExp q18_21 = Query.and(q18_19, q20_21);
+            QueryExp q2_9 = Query.and(q2_5, q6_9);
+            QueryExp q10_17 = Query.and(q10_13, q14_17);
+            QueryExp q18_23 = Query.and(q18_21, q22_23);
+            QueryExp q2_17 = Query.and(q2_9, q10_17);
+            queries.add(Query.and(q2_17, q18_23));
+
+            // case 25:
+            // Complex query mixing AND and OR.
+            queries.add(Query.or(q6_9, q18_23));
+        }
+    }
+
+    /**
+     * Returns a QueryExp taken is the ArrayList populated by buildQueries().
+     * Lowest index is 1.
+     * Highest index is returned by getSize().
+     * <br>The queries numbered 1 to 23 allow to cover all the underlying
+     * Java classes of the JMX API used to build queries.
+     */
+    public QueryExp getQuery(int index) {
+        return queries.get(index - 1);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/query/ServerDelegate.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.management.remote.JMXServiceURL ;
+import javax.management.MBeanRegistration;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.StandardMBean;
+
+/**
+ * This class defines an MBean that can be registered and used on client side
+ * to handle informations or properties of the remote server.
+ *
+ * For example, this MBean can store IOR addresses
+ * of RMI/IIOP connector(s) used in a test.
+ *
+ * That MBean might not be used for testing purpose itself.
+ */
+public class ServerDelegate implements ServerDelegateMBean, MBeanRegistration {
+
+    private MBeanServer mbeanServer = null;
+    private List<JMXServiceURL> addresses  = null;
+    private String port;
+    private static String javaVersion = System.getProperty("java.version");
+    private int sqeJmxwsCredentialsProviderCallCount = 0;
+    private String jmxwsCredentialsProviderUrl = null;
+    private int testJMXAuthenticatorCallCount = 0;
+    private Principal testJMXAuthenticatorPrincipal = null;
+
+    @SqeDescriptorKey("NO PARAMETER CONSTRUCTOR ServerDelegate")
+    public ServerDelegate() {
+        addresses = new ArrayList<JMXServiceURL>();
+    }
+
+    public ObjectName preRegister(MBeanServer server, ObjectName name)
+    throws Exception {
+        // Initialize MBeanServer attribute
+        mbeanServer = server;
+        return name;
+    }
+    public void postRegister(Boolean registrationDone) {
+    }
+    public void preDeregister() throws Exception {
+    }
+    public void postDeregister() {
+    }
+
+    public void addAddress(JMXServiceURL url) {
+        addresses.add(url) ;
+    }
+
+    public List<JMXServiceURL> getAddresses() {
+        return addresses ;
+    }
+
+    public void setPort(String p) {
+        port = p ;
+    }
+
+    public String getPort() {
+        return port ;
+    }
+
+    public String getJavaVersion() {
+        return javaVersion;
+    }
+
+    public void sqeJmxwsCredentialsProviderCalled() {
+        sqeJmxwsCredentialsProviderCallCount++;
+    }
+
+    public int getSqeJmxwsCredentialsProviderCallCount() {
+        return sqeJmxwsCredentialsProviderCallCount;
+    }
+
+    public void setJmxwsCredentialsProviderUrl(String url) {
+        jmxwsCredentialsProviderUrl = url;
+    }
+
+    public String getJmxwsCredentialsProviderUrl() {
+        return jmxwsCredentialsProviderUrl;
+    }
+
+    public void testJMXAuthenticatorCalled() {
+        testJMXAuthenticatorCallCount++;
+    }
+
+    public int getTestJMXAuthenticatorCallCount() {
+        return testJMXAuthenticatorCallCount;
+    }
+
+    public void setTestJMXAuthenticatorPrincipal(Principal principal) {
+        testJMXAuthenticatorPrincipal = principal;
+    }
+
+    public String getTestJMXAuthenticatorPrincipalString() {
+        if ( testJMXAuthenticatorPrincipal != null ) {
+            return testJMXAuthenticatorPrincipal.toString();
+        }
+
+        return null;
+    }
+
+   /**
+     * Instantiates and registers a StandardMBean in the MBean server.
+     *
+     * @param implementationClassName
+     *      The implementation class name of the MBean.
+     * @param interfaceClassName
+     *      The management interface class name of the MBean.
+     * @param isMXBean
+     *      If true, the resultant MBean is an MXBean.
+     * @param name
+     *      The object name of the StandardMBean.
+     */
+    @SuppressWarnings("unchecked")
+    public void createStandardMBean(
+            String implementationClassName,
+            String interfaceClassName,
+            boolean isMXBean,
+            ObjectName name)
+            throws Exception {
+
+        Object implementation =
+                Class.forName(implementationClassName).newInstance();
+        Class<Object> interfaceClass = interfaceClassName == null ? null :
+            (Class<Object>)Class.forName(interfaceClassName);
+
+        // Create the StandardMBean
+        StandardMBean standardMBean = new StandardMBean(
+                implementation,
+                interfaceClass,
+                isMXBean);
+
+        // Register the StandardMBean
+        mbeanServer.registerMBean(standardMBean, name);
+    }
+
+    /**
+     * Instantiates and registers a StandardMBean in the MBean server.
+     * The object will use standard JMX design pattern to determine
+     * the management interface associated with the given implementation.
+     */
+    @SuppressWarnings("unchecked")
+    public void createStandardMBean(
+            String implementationClassName,
+            boolean isMXBean,
+            ObjectName name)
+            throws Exception {
+
+        createStandardMBean(implementationClassName, null, isMXBean, name);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/query/ServerDelegateMBean.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.security.Principal;
+import java.util.List;
+
+import javax.management.remote.JMXServiceURL ;
+import javax.management.ObjectName;
+
+@SqeDescriptorKey("INTERFACE ServerDelegateMBean")
+public interface ServerDelegateMBean {
+    @SqeDescriptorKey("ATTRIBUTE Address")
+    public void addAddress(JMXServiceURL url);
+
+    @SqeDescriptorKey("ATTRIBUTE Address")
+    public List<JMXServiceURL> getAddresses();
+
+    public String getPort();
+    public void setPort(String p);
+
+    public String getJavaVersion();
+
+    public void sqeJmxwsCredentialsProviderCalled();
+    public int getSqeJmxwsCredentialsProviderCallCount();
+
+    public void setJmxwsCredentialsProviderUrl(String url);
+    public String getJmxwsCredentialsProviderUrl();
+
+    public void testJMXAuthenticatorCalled();
+    public int getTestJMXAuthenticatorCallCount();
+
+    public void setTestJMXAuthenticatorPrincipal(Principal principal);
+    public String getTestJMXAuthenticatorPrincipalString();
+
+    public void createStandardMBean(
+            String implementationClassName,
+            String interfaceClassName,
+            boolean isMXBean,
+            ObjectName name)
+            throws Exception;
+
+    public void createStandardMBean(
+            String implementationClassName,
+            boolean isMXBean,
+            ObjectName name)
+            throws Exception;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/query/SqeDescriptorKey.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import javax.management.DescriptorKey;
+
+/**
+ * That annotation is usable everywhere DescriptorKey is (and even more).
+ * It is for use to test that you can retrieve the SqeDescriptorKey into the
+ * appropriate Descriptor instances as built by the JMX runtime.
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+public @interface SqeDescriptorKey {
+    @DescriptorKey("sqeDescriptorKey")
+    String value();
+
+    // List descriptor fields that may be added or may be updated
+    // when retrieving an MBeanInfo using a JMXWS connection compared to the
+    // MBeanInfo returned by a local MBeanServer.
+    // The annotation format is :
+    //   <descriptorFieldName>=<descriptorFieldValue>
+    // The values actually handled by the test suite are :
+    //   openType=SimpleType.VOID
+    @DescriptorKey("descriptorFields")
+    String[] descriptorFields() default {};
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/query/SupportedQueryTypesTest.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,471 @@
+/*
+ * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8058865
+ * @summary Tests most of the existing query types.
+ * @author Olivier Lagneau
+ * @modules java.management
+ * @compile TestQuery.java
+ * @run main/othervm/timeout=300 -DDEBUG_STANDARD SupportedQueryTypesTest -mbeanClassName TestQuery
+ */
+
+import java.util.Map ;
+import java.util.HashMap;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Properties;
+import java.lang.reflect.Method;
+
+import java.lang.management.ManagementFactory;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.MBeanServerConnection;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName ;
+import javax.management.QueryExp;
+
+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 SupportedQueryTypesTest {
+
+    protected String mbeanClassName = null;
+
+    private MBeanServerConnection mbsc = null;
+
+
+    /*
+     * First Debug properties and arguments are collect in expected
+     * map  (argName, value) format, then calls original test's run method.
+     */
+    public static void main(String args[]) throws Exception {
+
+        System.out.println("=================================================");
+
+        // Parses parameters
+        Utils.parseDebugProperties();
+        Map<String, Object> map = Utils.parseParameters(args) ;
+
+        // Run test
+        SupportedQueryTypesTest test = new SupportedQueryTypesTest();
+        test.run(map);
+
+    }
+
+    public void run(Map<String, Object> args) {
+        int errorCount = 0;
+
+        ObjectName on = null;
+        ObjectName serverDelegateObjectName = null;
+
+        JMXConnectorServer cs = null;
+        JMXConnector cc = null;
+
+        System.out.println("SupportedQueryTypesTest::run: Start") ;
+        try {
+            // JMX MbeanServer used inside single VM as if remote.
+            MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+
+            JMXServiceURL url = new JMXServiceURL("rmi", null, 0);
+            cs = JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);
+            cs.start();
+
+            JMXServiceURL addr = cs.getAddress();
+            cc = JMXConnectorFactory.connect(addr);
+            mbsc = cc.getMBeanServerConnection();
+
+
+            // Create and register the ServerDelegate MBean on the remote MBeanServer
+            String serverDelegateClassName = ServerDelegate.class.getName();
+            serverDelegateObjectName =
+                    new ObjectName("defaultDomain:class=" + serverDelegateClassName);
+            mbsc.createMBean(serverDelegateClassName, serverDelegateObjectName);
+
+            // Retrieve the MBean class name
+            mbeanClassName = (String) args.get("-mbeanClassName") ;
+            on = new ObjectName("defaultDomain:class=" + mbeanClassName);
+
+            // Create and register the MBean on the remote MBeanServer
+            System.out.println("SupportedQueryTypesTest::run: CREATE " +
+                    mbeanClassName + " on the remote MBeanServer with name "
+                    + on);
+            mbsc.createMBean(mbeanClassName, on);
+
+            // Create a QueryFactory and setup which query we'll use.
+            QueryFactory queries = new QueryFactory(mbeanClassName);
+            queries.buildQueries();
+            int maxIndex = queries.getSize();
+            int minIndex = 1;
+
+            // Create a reference Set<ObjectName> to check later on
+            // the queryNames() results
+            Set<ObjectName> referenceNameSet = new HashSet<ObjectName>();
+            referenceNameSet.add(on);
+
+            // Create a reference Set<ObjectInstance> to check later on
+            // the queryMBeans() results
+            ObjectInstance oi = new ObjectInstance(on, mbeanClassName);
+            Set<ObjectInstance> referenceInstanceSet =
+                    new HashSet<ObjectInstance>();
+            referenceInstanceSet.add(oi);
+
+            // Perform the queryNames and queryMBeans requests
+            for (int i = minIndex; i <= maxIndex; i++ ) {
+                QueryExp query = queries.getQuery(i);
+                System.out.println("----");
+                System.out.println("SupportedQueryTypesTest::run: Query # " + i);
+                System.out.println("query " + query);
+                errorCount +=
+                    doQueryNames(query, referenceNameSet);
+                errorCount +=
+                    doQueryMBeans(query, referenceInstanceSet);
+            }
+
+        } catch(Exception e) {
+            Utils.printThrowable(e, true);
+            errorCount++;
+
+        } finally {
+            // Do unregister the MBean
+            try {
+                if (mbsc.isRegistered(on)) {
+                    mbsc.unregisterMBean(on);
+                }
+                if (mbsc.isRegistered(serverDelegateObjectName)) {
+                    mbsc.unregisterMBean(serverDelegateObjectName);
+                }
+            } catch (Exception e) {
+                Utils.printThrowable(e, true) ;
+                errorCount++;
+            }
+
+            try {
+                // Close JMX Connector Client
+                cc.close();
+                // Stop connertor server
+                cs.stop();
+
+            } catch (Exception e) {
+                Utils.printThrowable(e, true) ;
+                errorCount++;
+            }
+        }
+
+        System.out.println("");
+        System.out.println("SupportedQueryTypesTest::run: Done") ;
+
+        // Handle result
+        if (errorCount == 0) {
+            System.out.println("SupportedQueryTypesTest::run: (OK)");
+        } else {
+            String message = "SupportedQueryTypesTest::run: (ERROR) Got " +
+                    + errorCount + " error(s)";
+            System.out.println(message);
+            throw new RuntimeException(message);
+        }
+    }
+
+
+    private int doQueryNames(QueryExp query, Set<ObjectName> referenceSet) {
+        int errorCount = 0;
+        System.out.println(" <*> Perform queryNames call ");
+
+        try {
+            // Call queryNames on the remote MBeanServer
+            Set<ObjectName> remoteSet =  mbsc.queryNames(null, query);
+
+            // Compare the 2 Set<ObjectName>
+            errorCount += checkSet(remoteSet, referenceSet);
+
+            // Cleaning
+            remoteSet.clear();
+
+        } catch (Exception e) {
+            Utils.printThrowable(e, true);
+            errorCount++;
+        }
+
+        if ( errorCount == 0 ) {
+            System.out.println("\t(OK)");
+        } else {
+            System.out.println("\t(ERROR) Query failed");
+        }
+
+        return errorCount;
+    }
+
+
+    private int doQueryMBeans(QueryExp query, Set<ObjectInstance> referenceSet) {
+        int errorCount = 0;
+        System.out.println(" <*> Perform queryMBeans call ");
+
+        try {
+            // Call queryMBeans on the remote MBeanServer
+            Set<ObjectInstance> remoteSet =  mbsc.queryMBeans(null, query);
+
+            // Compare the 2 Set<ObjectInstance>
+            errorCount += checkSet(remoteSet, referenceSet);
+
+            // Cleaning
+            remoteSet.clear();
+
+        } catch (Exception e) {
+            Utils.printThrowable(e, true);
+            errorCount++;
+        }
+
+        if ( errorCount == 0 ) {
+            System.out.println("\t(OK)");
+        } else {
+            System.out.println("\t(ERROR) Query failed");
+        }
+
+        return errorCount;
+    }
+
+    /**
+     * Pretty print of a Set content.
+     * When the Set isn't empty, toString() is called on each element.
+     * <br>The variable's name used to hold that Set is given via the setName
+     * parameter and used in the output.
+     */
+    private static void printSet(Set<?> printableSet, String setName) {
+        if ( printableSet.size() == 0 ) {
+            System.out.println("The Set " + setName + " is empty");
+        } else {
+            System.out.println("The Set " + setName + " contains :");
+
+            for (Iterator<?> it = printableSet.iterator(); it.hasNext();) {
+                Object elem = it.next();
+                System.out.println("\t" + elem.toString());
+            }
+        }
+    }
+
+
+    /**
+     * This method check the Set remoteSet is equal to
+     * the reference Set referenceSet,
+     * which means same size and content (order doesn't matter).
+     * <br>It returns 0 when the check is fine, otherwise 1.
+     */
+    private int checkSet(Set<?> remoteSet, Set<?> referenceSet) {
+        if ( !  remoteSet.equals(referenceSet) ) {
+            System.out.println("SupportedQueryTypesTest::checkSet:"
+                    + " (ERROR) Set aren't as expected");
+            printSet(remoteSet, "remoteSet");
+            printSet(referenceSet, "referenceSet");
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    // Utility inner class coming from JMX Tonga test suite.
+    private static class Utils {
+
+        // DEBUG is printed depending on the DEBUG and DEBUG_LEVEL JAVA property
+        static final String DEBUG_HEADER = "[debug] ";
+
+        // DEBUG levels
+        static int selectedDebugLevel = 0;
+        static final int DEBUG_STANDARD = 1;
+        static final int DEBUG_VERBOSE = 2;  // Mainly used for stress tests
+        static final int DEBUG_ALL = DEBUG_STANDARD | DEBUG_VERBOSE;
+
+        static void parseDebugProperties() {
+            int level = 0;
+            Properties p = System.getProperties();
+
+            // get selected levels
+            if (p.getProperty("DEBUG_STANDARD") != null) {
+                level |= DEBUG_STANDARD;
+            }
+
+            if (p.getProperty("DEBUG_VERBOSE") != null) {
+                level |= DEBUG_VERBOSE;
+            }
+
+            if (p.getProperty("DEBUG_ALL") != null) {
+                level |= DEBUG_ALL;
+            }
+
+            selectedDebugLevel = level;
+        }
+
+        /**
+         * Reproduces the original parsing and collection of test parameters
+         * from the DTonga JMX test suite.
+         *
+         * Collects passed args and returns them in a map(argname, value) structure,
+         * which will be then propagated as necessary to various called methods.
+         */
+        static Map<String, Object> parseParameters(String args[])
+        throws Exception {
+            debug(DEBUG_STANDARD, "TestRoot::parseParameters: Start");
+            HashMap<String, Object> map = new HashMap<>();
+
+            for ( int i = 0; i < args.length; i++ ) {
+                if ( args[i].trim().startsWith("-") ) {
+                    if ((i+1) < args.length && !args[i+1].startsWith("-") ) {
+                        debug(DEBUG_STANDARD,
+                            "TestRoot::parseParameters: added in map = " +
+                            args[i] +
+                            " with value " +
+                            args[i+1]) ;
+                        map.put(args[i].trim(), args[i+1].trim()) ;
+                    } else if ((i+1) < args.length && args[i+1].startsWith("-") ||
+                               (i+1) == args.length ) {
+                        debug(DEBUG_STANDARD,
+                                "TestRoot::parseParameters: added in map = " +
+                                args[i] +
+                                " with null value") ;
+                        map.put(args[i].trim(), null) ;
+                    } else {
+                        System.out.println(
+                            "TestRoot::parseParameters: (WARNING) not added in map = " +
+                            args[i]) ;
+                    }
+                }
+            }
+
+            debug(DEBUG_STANDARD, "TestRoot::parseParameters: Done") ;
+            return map ;
+        }
+
+        /**
+         * This method is to be used in all tests to print anything
+         * that is temporary.
+         * Printing is done only when debug is activated by the property DEBUG.
+         * Printing depends also on the DEBUG_LEVEL property.
+         * Here it encapsulates a System.out.println.
+         */
+        static void debug(int level, String line) {
+            if ((selectedDebugLevel & level) != 0) {
+                System.out.println(DEBUG_HEADER + line);
+            }
+        }
+
+        /**
+         * Do print stack trace when withStack is true.
+         * Does try to call getTargetException() and getTargetError() then
+         * print embedded stacks in the case of an Exception wrapping
+         * another Exception or an Error. Recurse until no more wrapping
+         * is found.
+         */
+        static void printThrowable(Throwable theThro, boolean withStack) {
+            try {
+                if (withStack) {
+                    theThro.printStackTrace(System.out);
+                }
+                if (theThro instanceof Exception) {
+                    Exception t = (Exception) theThro;
+                    Method target = null;
+                    String blank = " ";
+                    try {
+                        target = t.getClass().getMethod("getTargetException",
+                                (java.lang.Class<?>[]) null);
+                    } catch (Exception ee) {
+                    // OK: getTargetException method could be there or not
+                    }
+                    System.out.println(blank + t.getClass() + "==>" + t.getMessage());
+                    while (target != null) {
+                        try {
+                            t = (Exception) target.invoke(t,
+                                    (java.lang.Object[]) null);
+                        } catch (Exception ee) {
+                            t = null;
+                        }
+                        try {
+                            if (t != null) {
+                                blank = blank + "  ";
+                                System.out.println(blank + t.getClass() + "==>" +
+                                        t.getMessage());
+                                try {
+                                    target =
+                                            t.getClass().getMethod("getTargetException",
+                                            (java.lang.Class<?>[]) null);
+                                } catch (Exception ee) {
+                                // OK: getTargetException method could be there or not                            }
+                                }
+                            } else {
+                                target = null;
+                            }
+                        } catch (Exception ee) {
+                            target = null;
+                        }
+                    }
+
+                    // We may have exceptions wrapping an Error then it is
+                    // getTargetError that is likely to be called
+                    try {
+                        target = ((Exception) theThro).getClass().getMethod("getTargetError",
+                                (java.lang.Class<?>[]) null);
+                    } catch (Exception ee) {
+                    // OK: getTargetError method could be there or not
+                    }
+                    Throwable err = theThro;
+                    while (target != null) {
+                        try {
+                            err = (Error) target.invoke(err,
+                                    (java.lang.Object[]) null);
+                        } catch (Exception ee) {
+                            err = null;
+                        }
+                        try {
+                            if (err != null) {
+                                blank = blank + "  ";
+                                System.out.println(blank + err.getClass() + "==>" +
+                                        err.getMessage());
+                                if (withStack) {
+                                    err.printStackTrace(System.out);
+                                }
+                                try {
+                                    target = err.getClass().getMethod("getTargetError",
+                                            (java.lang.Class<?>[]) null);
+                                } catch (Exception ee) {
+                                // OK: getTargetError method could be there or not
+                                }
+                            } else {
+                                target = null;
+                            }
+                        } catch (Exception ee) {
+                            target = null;
+                        }
+                    }
+                } else {
+                    System.out.println("Throwable is : " + theThro);
+                }
+            } catch (Throwable x) {
+                System.out.println("Exception : raised in printException : " + x);
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/query/TestQuery.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Class TestQuery
+ * MBean used for testing the types wired when using QueryExp.
+ * It is heavily linked to QueryFactory.
+ */
+public class TestQuery extends QueryData implements TestQueryMBean {
+
+    /**
+     * Attribute : BooleanAtt
+     */
+    private boolean booleanAtt = booleanValue;
+
+    /**
+     * Attribute : DoubleAtt
+     */
+    private double doubleAtt = doubleValue;
+
+    /**
+     * Attribute : FloatAtt
+     */
+    private float floatAtt = floatValue;
+
+    /**
+     * Attribute : IntAtt
+     */
+    private int intAtt = intValue;
+
+    /**
+     * Attribute : IntegerAtt
+     */
+    private Integer integerAtt = integerValue;
+
+    /**
+     * Attribute : LongAtt
+     */
+    private long longAtt = longValue;
+
+    /**
+     * Attribute : StringAtt
+     */
+    private String stringAtt = stringValue;
+
+    public TestQuery() {
+    }
+
+    /**
+     * Get Att of type boolean
+     */
+    public boolean getBooleanAtt() {
+        return booleanAtt;
+    }
+
+    /**
+     * Set Att of type boolean
+     */
+    public void setBooleanAtt(boolean value) {
+        booleanAtt = value;
+    }
+
+    /**
+     * Get Att of type double
+     */
+    public double getDoubleAtt() {
+        return doubleAtt;
+    }
+
+    /**
+     * Set Att of type double
+     */
+    public void setDoubleAtt(double value) {
+        doubleAtt = value;
+    }
+
+    /**
+     * Get Att of type float
+     */
+    public float getFloatAtt() {
+        return floatAtt;
+    }
+
+    /**
+     * Set Att of type float
+     */
+    public void setFloatAtt(float value) {
+        floatAtt = value;
+    }
+
+    /**
+     * Get Att of type int
+     */
+    public int getIntAtt() {
+        return intAtt;
+    }
+
+    /**
+     * Set Att of type int
+     */
+    public void setIntAtt(int value) {
+        intAtt = value;
+    }
+
+    /**
+     * Get Att of type Integer
+     */
+    public Integer getIntegerAtt() {
+        return integerAtt;
+    }
+
+    /**
+     * Set Att of type Integer
+     */
+    public void setIntegerAtt(Integer value) {
+        integerAtt = value;
+    }
+
+    /**
+     * Get Att of type long
+     */
+    public long getLongAtt() {
+        return longAtt;
+    }
+
+    /**
+     * Set Att of type long
+     */
+    public void setLongAtt(long value) {
+        longAtt = value;
+    }
+
+    /**
+     * Get Att of type String
+     */
+    public String getStringAtt() {
+        return stringAtt;
+    }
+
+    /**
+     * Set Att of type String
+     */
+    public void setStringAtt(String value) {
+        stringAtt = value;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/query/TestQueryMBean.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Interface TestQueryMBean
+ * MBean used for testing the types wired when using QueryExp.
+ * It is heavily linked to QueryFactory.
+ */
+public interface TestQueryMBean
+{
+    /**
+     * Get Att of type boolean
+     */
+    public boolean getBooleanAtt();
+
+    /**
+     * Set Att of type boolean
+     */
+    public void setBooleanAtt(boolean value);
+
+    /**
+     * Get Att of type double
+     */
+    public double getDoubleAtt();
+
+    /**
+     * Set Att of type double
+     */
+    public void setDoubleAtt(double value);
+
+    /**
+     * Get Att of type float
+     */
+    public float getFloatAtt();
+
+    /**
+     * Set Att of type float
+     */
+    public void setFloatAtt(float value);
+
+    /**
+     * Get Att of type int
+     */
+    public int getIntAtt();
+
+    /**
+     * Set Att of type int
+     */
+    public void setIntAtt(int value);
+
+    /**
+     * Get Att of type Integer
+     */
+    public Integer getIntegerAtt();
+
+    /**
+     * Set Att of type Integer
+     */
+    public void setIntegerAtt(Integer value);
+
+    /**
+     * Get Att of type long
+     */
+    public long getLongAtt();
+
+    /**
+     * Set Att of type long
+     */
+    public void setLongAtt(long value);
+
+    /**
+     * Get Att of type String
+     */
+    public String getStringAtt();
+
+    /**
+     * Set Att of type String
+     */
+    public void setStringAtt(String value);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/security/AuthorizationTest.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,613 @@
+/*
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8058865
+ * @summary Checks various authentication behavior from remote jmx client
+ * @author Olivier Lagneau
+ * @modules java.management
+ * @library /lib/testlibrary
+ * @compile Simple.java
+ * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Dusername=username1 -Dpassword=password1 AuthorizationTest -server -mapType x.access.file;x.password.file -populate -client -mapType credentials
+ * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Dusername=username2 -Dpassword=password2 AuthorizationTest -server -mapType x.access.file;x.password.file -populate -client -mapType credentials -expectedCreateException -expectedSetException -expectedInvokeException
+ * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Dusername=username6 -Dpassword=password6 AuthorizationTest -server -mapType x.access.file;x.password.file -populate -client -mapType credentials -expectedCreateException -expectedGetException -expectedSetException -expectedInvokeException
+ * @run main/othervm/timeout=300/policy=java.policy.authorization -DDEBUG_STANDARD -Dusername=username1 -Dpassword=password1 AuthorizationTest -server -mapType x.password.file -populate -client -mapType credentials
+ * @run main/othervm/timeout=300/policy=java.policy.authorization -DDEBUG_STANDARD -Dusername=username3 -Dpassword=password3 AuthorizationTest -server -mapType x.password.file -populate -client -mapType credentials -expectedGetException
+ * @run main/othervm/timeout=300/policy=java.policy.authorization -DDEBUG_STANDARD -Dusername=username5 -Dpassword=password5 AuthorizationTest -server -mapType x.password.file -populate -client -mapType credentials -expectedCreateException -expectedGetException -expectedSetException -expectedInvokeException
+ * @run main/othervm/timeout=300/policy=java.policy.authorization -DDEBUG_STANDARD -Dusername=username6 -Dpassword=password6 AuthorizationTest -server -mapType x.password.file -populate -client -mapType credentials -expectedCreateException -expectedGetException -expectedSetException -expectedInvokeException
+ * @run main/othervm/timeout=300/policy=java.policy.authorization -DDEBUG_STANDARD -Dusername=username1 -Dpassword=password1 AuthorizationTest -server -mapType x.access.file;x.password.file -populate -client -mapType credentials
+ * @run main/othervm/timeout=300/policy=java.policy.authorization -DDEBUG_STANDARD -Dusername=username2 -Dpassword=password2 AuthorizationTest -server -mapType x.access.file;x.password.file -populate -client -mapType credentials -expectedCreateException -expectedSetException -expectedInvokeException
+ * @run main/othervm/timeout=300/policy=java.policy.authorization -DDEBUG_STANDARD -Dusername=username3 -Dpassword=password3 AuthorizationTest -server -mapType x.access.file;x.password.file -populate -client -mapType credentials -expectedCreateException -expectedGetException -expectedSetException -expectedInvokeException
+ * @run main/othervm/timeout=300/policy=java.policy.authorization -DDEBUG_STANDARD -Dusername=username4 -Dpassword=password4 AuthorizationTest -server -mapType x.access.file;x.password.file -populate -client -mapType credentials -expectedGetException -expectedSetException
+ * @run main/othervm/timeout=300/policy=java.policy.authorization -DDEBUG_STANDARD -Dusername=username5 -Dpassword=password5 AuthorizationTest -server -mapType x.access.file;x.password.file -populate -client -mapType credentials -expectedCreateException -expectedGetException -expectedSetException -expectedInvokeException
+ */
+
+import java.io.File;
+import java.util.Map ;
+import java.util.HashMap ;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import java.lang.management.ManagementFactory;
+
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory ;
+import javax.management.MBeanServerConnection;
+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;
+
+import javax.management.Attribute ;
+import javax.management.ObjectName ;
+
+import jdk.testlibrary.ProcessTools;
+import jdk.testlibrary.JDKToolFinder;
+
+public class AuthorizationTest {
+
+    static final String SERVER_CLASS_NAME = "AuthorizationTest";
+    static final String CLIENT_CLASS_NAME = "AuthorizationTest$ClientSide";
+    static final String CLIENT_CLASS_MAIN = CLIENT_CLASS_NAME;
+
+    static final String USERNAME_PROPERTY = "username";
+    static final String PASSWORD_PROPERTY = "password";
+
+    private JMXConnectorServer cs;
+
+    /*
+     * First Debug properties and arguments are collect in expected
+     * map  (argName, value) format, then calls original test's run method.
+     */
+    public static void main(String args[]) throws Exception {
+
+        System.out.println("=================================================");
+
+        // Parses parameters
+        Utils.parseDebugProperties();
+
+        // Supported parameters list format is :
+        // "MainClass [-server <param-spec> ...] [-client <param-spec> ...]
+        // with <param-spec> either "-parami valuei" or "-parami"
+        HashMap<String, Object> serverMap = new HashMap<>() ;
+        int clientArgsIndex =
+            Utils.parseServerParameters(args, SERVER_CLASS_NAME, serverMap);
+
+        // Extract and records client params
+        String[] clientParams = null;
+        if (clientArgsIndex < args.length) {
+            int clientParamsSize = args.length - clientArgsIndex;
+            clientParams = new String[clientParamsSize];
+            System.arraycopy(args, clientArgsIndex, clientParams, 0, clientParamsSize);
+        } else {
+            clientParams = new String[0];
+        }
+
+        // Run test
+        AuthorizationTest test = new AuthorizationTest();
+        test.run(serverMap, clientParams);
+
+    }
+
+    /*
+     * Create the MBeansServer side of the test and returns its address
+     */
+    private JMXServiceURL createServerSide(Map<String, Object> serverMap)
+    throws Exception {
+        final int NINETY_SECONDS = 90;
+
+        System.out.println("AuthorizationTest::createServerSide: Start") ;
+
+        MBeanServer mbs = MBeanServerFactory.newMBeanServer();
+        JMXServiceURL url = new JMXServiceURL("rmi", null, 0);
+
+        // Creates connection environment from server side params
+        HashMap<String, Object> env = new HashMap<>();
+        String value = null;
+
+        if ((value = (String)serverMap.get("-mapType")) != null) {
+            if (value.contains("x.access.file")) {
+                String accessFileStr = System.getProperty("test.src") +
+                    File.separator + "access.properties";
+                env.put("jmx.remote.x.access.file", accessFileStr);
+                System.out.println("Added " + accessFileStr + " file as jmx.remote.x.access.file");
+            }
+            if (value.contains("x.password.file")) {
+                String passwordFileStr = System.getProperty("test.src") +
+                    File.separator + "password.properties";
+                env.put("jmx.remote.x.password.file", passwordFileStr);
+                System.out.println("Added " + passwordFileStr + " file as jmx.remote.x.password.file");
+            }
+        }
+
+        if (serverMap.containsKey("-populate")) {
+            String populateClassName = "Simple";
+            ObjectName on =
+                new ObjectName("defaultDomain:class=Simple");
+
+            Utils.debug(Utils.DEBUG_STANDARD, "create and register Simple MBean") ;
+            mbs.createMBean(populateClassName, on);
+        }
+
+        cs = JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);
+        cs.start();
+
+        Utils.waitReady(cs, NINETY_SECONDS);
+
+        JMXServiceURL addr = cs.getAddress();
+
+        System.out.println("AuthorizationTest::createServerSide: Done.") ;
+
+        return addr;
+    }
+
+    /*
+     * Creating command-line for running subprocess JVM:
+     *
+     * JVM command line is like:
+     * {test_jdk}/bin/java {defaultopts} -cp {test.class.path} {testopts} main
+     *
+     * {defaultopts} are the default java options set by the framework.
+     *
+     */
+    private List<String> buildCommandLine(String args[]) {
+        List<String> opts = new ArrayList<>();
+        opts.add(JDKToolFinder.getJDKTool("java"));
+        opts.addAll(Arrays.asList(jdk.testlibrary.Utils.getTestJavaOpts()));
+
+        String usernameValue = System.getProperty(USERNAME_PROPERTY);
+        if (usernameValue != null) {
+            opts.add("-D" + USERNAME_PROPERTY + "=" + usernameValue);
+        }
+        String passwordValue = System.getProperty(PASSWORD_PROPERTY);
+        if (passwordValue != null) {
+            opts.add("-D" + PASSWORD_PROPERTY + "=" + passwordValue);
+        }
+
+        opts.add("-cp");
+        opts.add(System.getProperty("test.class.path", "test.class.path"));
+        opts.add(CLIENT_CLASS_MAIN);
+        opts.addAll(Arrays.asList(args));
+        return opts;
+    }
+
+    /**
+     * Runs AuthorizationTest$ClientSide with the passed options and redirects
+     * subprocess standard I/O to the current (parent) process. This provides a
+     * trace of what happens in the subprocess while it is runnning (and before
+     * it terminates).
+     *
+     * @param serviceUrlStr string representing the JMX service Url to connect to.
+     */
+    private int runClientSide(String args[], String serviceUrlStr) throws Exception {
+
+        // Building command-line
+        List<String> opts = buildCommandLine(args);
+        opts.add("-serviceUrl");
+        opts.add(serviceUrlStr);
+
+        // Launch separate JVM subprocess
+        int exitCode = 0;
+        String[] optsArray = opts.toArray(new String[0]);
+        ProcessBuilder pb = new ProcessBuilder(optsArray);
+        Process p = ProcessTools.startProcess("AuthorizationTest$ClientSide", pb);
+
+        // Handling end of subprocess
+        try {
+            exitCode = p.waitFor();
+            if (exitCode != 0) {
+                System.out.println(
+                    "Subprocess unexpected exit value of [" + exitCode +
+                    "]. Expected 0.\n");
+            }
+        } catch (InterruptedException e) {
+            System.out.println("Parent process interrupted with exception : \n " + e + " :" );
+
+            // Parent thread unknown state, killing subprocess.
+            p.destroyForcibly();
+
+            throw new RuntimeException(
+                "Parent process interrupted with exception : \n " + e + " :" );
+
+        } finally {
+            if (p.isAlive()) {
+                p.destroyForcibly();
+            }
+            return exitCode;
+        }
+
+     }
+
+    public void run(Map<String, Object> serverArgs, String clientArgs[]) {
+
+        System.out.println("AuthorizationTest::run: Start") ;
+        int errorCount = 0;
+
+        try {
+            // Initialise the server side
+            JMXServiceURL urlToUse = createServerSide(serverArgs);
+
+            // Run client side
+            errorCount = runClientSide(clientArgs, urlToUse.toString());
+
+            if ( errorCount == 0 ) {
+                System.out.println("AuthorizationTest::run: Done without any error") ;
+            } else {
+                System.out.println("AuthorizationTest::run: Done with "
+                        + errorCount
+                        + " error(s)") ;
+                throw new RuntimeException("errorCount = " + errorCount);
+            }
+
+            cs.stop();
+
+        } catch(Exception e) {
+            throw new RuntimeException(e);
+        }
+
+    }
+
+    private static class ClientSide {
+
+        private JMXConnector cc = null;
+        private MBeanServerConnection mbsc = null;
+
+        public static void main(String args[]) throws Exception {
+
+            // Parses parameters
+            Utils.parseDebugProperties();
+
+            // Supported parameters list format is : "MainClass [-client <param-spec> ...]
+            // with <param-spec> either "-parami valuei" or "-parami"
+            HashMap<String, Object> clientMap = new HashMap<>() ;
+            Utils.parseClientParameters(args, CLIENT_CLASS_NAME, clientMap);
+
+            // Run test
+            ClientSide test = new ClientSide();
+            test.run(clientMap);
+
+        }
+
+        public void run(Map<String, Object> args) {
+
+            int errorCount = 0 ;
+
+            try {
+                boolean expectedCreateException =
+                        (args.containsKey("-expectedCreateException")) ? true : false ;
+                boolean expectedGetException =
+                        (args.containsKey("-expectedGetException")) ? true : false ;
+                boolean expectedSetException =
+                        (args.containsKey("-expectedSetException")) ? true : false ;
+                boolean expectedInvokeException =
+                        (args.containsKey("-expectedInvokeException")) ? true : false ;
+                // JSR262 (see bug 6440374)
+                // There is no special JSR262 protocol operation for connect.
+                // The first request sent initiate the connection.
+                // In the JSR262 current implementation, getDefaultDomain is sent to
+                // the server in order to get the server part of the connection ID.
+                // => the connection may fail if no access permission on get requests.
+                boolean expectedConnectException =
+                        (args.containsKey("-expectedConnectException")) ? true : false ;
+                // Before connection,
+                // remove the element of the Map with null values (not supported by RMI)
+                // See bug 4982668
+                args.remove("-expectedCreateException");
+                args.remove("-expectedGetException");
+                args.remove("-expectedSetException");
+                args.remove("-expectedInvokeException");
+                args.remove("-expectedConnectException");
+
+
+                // Here do connect to the JMX Server
+                String username = System.getProperty("username");
+                Utils.debug(Utils.DEBUG_STANDARD,
+                    "ClientSide::run: CONNECT on behalf of \"" + username + "\"");
+                doConnect(args, expectedConnectException);
+
+                // If the connection did not fail, perform some requests.
+                // At this stage the mbeanserver connection is up and running
+                if (mbsc != null) {
+                    ObjectName on = new ObjectName("defaultDomain:class=Simple");
+
+                    // Create request
+                    Utils.debug(Utils.DEBUG_STANDARD,
+                        "ClientSide::run: CREATE on behalf of \"" +
+                        username + "\"");
+                    errorCount += doCreateRequest(mbsc,
+                        new ObjectName("defaultDomain:class=Simple,user=" + username),
+                        expectedCreateException);
+
+                    // Get request
+                    Utils.debug(Utils.DEBUG_STANDARD,
+                        "ClientSide::run: GET on behalf of \"" +
+                        username + "\"");
+                    errorCount += doGetRequest(mbsc, on, expectedGetException);
+
+                    // Set request
+                    Utils.debug(Utils.DEBUG_STANDARD,
+                        "ClientSide::run: SET on behalf of \"" +
+                        username + "\"");
+                    errorCount += doSetRequest(mbsc, on, expectedSetException);
+
+                    // Invoke request
+                    Utils.debug(Utils.DEBUG_STANDARD,
+                        "ClientSide::run: INVOKE on behalf of \"" +
+                        username + "\"");
+                    errorCount += doInvokeRequest(mbsc, on, expectedInvokeException);
+                }
+
+            } catch(Exception e) {
+                Utils.printThrowable(e, true) ;
+                errorCount++;
+            } finally {
+                // Terminate the JMX Client
+                try {
+                    cc.close();
+                } catch (Exception e) {
+                    Utils.printThrowable(e, true) ;
+                    errorCount++;
+                }
+            }
+
+            System.out.println("ClientSide::run: Done") ;
+
+            // Handle result
+            if (errorCount == 0) {
+                System.out.println("ClientSide::run: (OK) authorization test succeeded.");
+            } else {
+                String message = "AuthorizationTest$ClientSide::run: (ERROR) " +
+                        " authorization test failed with " +
+                        errorCount + " error(s)";
+                System.out.println(message);
+                throw new RuntimeException(message);
+            }
+        }
+
+        protected void doConnect(Map<String, Object> args,
+                                 boolean expectedException) {
+
+            String msgTag = "ClientSide::doConnect";
+            boolean throwRuntimeException = false;
+            String message = "";
+
+            try {
+                Utils.debug(Utils.DEBUG_STANDARD,
+                    "ClientSide::doConnect: Connect the client");
+
+                // Collect connection environment
+                HashMap<String, Object> env = new HashMap<>();
+
+                Object value = args.get("-mapType");
+                if (value != null) {
+                    String username = System.getProperty("username");
+                    String password = System.getProperty("password");
+                    Utils.debug(Utils.DEBUG_STANDARD,
+                        msgTag + "add \"jmx.remote.credentials\" = \"" +
+                        username + "\", \"" + password + "\"");
+                    env.put("jmx.remote.credentials",
+                        new String[] { username , password });
+                }
+
+                // Get a connection to remote mbean server
+                JMXServiceURL addr = new JMXServiceURL((String)args.get("-serviceUrl"));
+                cc = JMXConnectorFactory.connect(addr,env);
+                mbsc = cc.getMBeanServerConnection();
+
+                if (expectedException) {
+                    message = "ClientSide::doConnect: (ERROR) " +
+                        "Connect did not fail with expected SecurityException";
+                    System.out.println(message);
+                    throwRuntimeException = true;
+                } else {
+                    System.out.println("ClientSide::doConnect: (OK) Connect succeed");
+                }
+            } catch(Exception e) {
+                Utils.printThrowable(e, true);
+                if (expectedException) {
+                    if (e instanceof java.lang.SecurityException) {
+                        System.out.println("ClientSide::doConnect: (OK) " +
+                            "Connect failed with expected SecurityException");
+                    } else {
+                        message = "ClientSide::doConnect: (ERROR) " +
+                            "Create failed with " + e.getClass() +
+                            " instead of expected SecurityException";
+                        System.out.println(message);
+                        throwRuntimeException = true;
+                    }
+                } else {
+                    message = "ClientSide::doConnect: (ERROR) " +
+                        "Connect failed";
+                    System.out.println(message);
+                    throwRuntimeException = true;
+                }
+            }
+
+            // If the connection failed, or if the connection succeeded but should not,
+            // no need to go further => throw RuntimeException and exit the test
+            if (throwRuntimeException) {
+                throw new RuntimeException(message);
+            }
+        }
+
+        protected int doCreateRequest(MBeanServerConnection mbsc,
+                                      ObjectName on,
+                                      boolean expectedException) {
+            int errorCount = 0;
+
+            try {
+                Utils.debug(Utils.DEBUG_STANDARD,
+                    "ClientSide::doCreateRequest: Create and register the MBean") ;
+
+                mbsc.createMBean("Simple", on) ;
+
+                if (expectedException) {
+                    System.out.println("ClientSide::doCreateRequest: " +
+                        "(ERROR) Create did not fail with expected SecurityException");
+                    errorCount++;
+                } else {
+                    System.out.println("ClientSide::doCreateRequest: (OK) Create succeed") ;
+                }
+            } catch(Exception e) {
+                Utils.printThrowable(e, true) ;
+                if (expectedException) {
+                    if (e instanceof java.lang.SecurityException) {
+                        System.out.println("ClientSide::doCreateRequest: " +
+                            "(OK) Create failed with expected SecurityException") ;
+                    } else {
+                        System.out.println("ClientSide::doCreateRequest: " +
+                            "(ERROR) Create failed with " +
+                            e.getClass() + " instead of expected SecurityException");
+                        errorCount++;
+                    }
+                } else {
+                    System.out.println("ClientSide::doCreateRequest: " +
+                        "(ERROR) Create failed");
+                    errorCount++;
+                }
+            }
+            return errorCount;
+        }
+
+        protected int doGetRequest(MBeanServerConnection mbsc,
+                                   ObjectName on,
+                                   boolean expectedException) {
+            int errorCount = 0;
+
+            try {
+                Utils.debug(Utils.DEBUG_STANDARD,
+                    "ClientSide::doGetRequest: Get attributes of the MBean") ;
+
+                mbsc.getAttribute(on, "Attribute");
+
+                if (expectedException) {
+                    System.out.println("ClientSide::doGetRequest: " +
+                        "(ERROR) Get did not fail with expected SecurityException");
+                    errorCount++;
+                } else {
+                    System.out.println("ClientSide::doGetRequest: (OK) Get succeed") ;
+                }
+            } catch(Exception e) {
+                Utils.printThrowable(e, true) ;
+                if (expectedException) {
+                    if (e instanceof java.lang.SecurityException) {
+                        System.out.println("ClientSide::doGetRequest: " +
+                            "(OK) Get failed with expected SecurityException") ;
+                    } else {
+                        System.out.println("ClientSide::doGetRequest: " +
+                            "(ERROR) Get failed with " +
+                            e.getClass() + " instead of expected SecurityException");
+                        errorCount++;
+                    }
+                } else {
+                    System.out.println("ClientSide::doGetRequest: (ERROR) Get failed");
+                    errorCount++;
+                }
+            }
+
+            return errorCount;
+        }
+
+        protected int doSetRequest(MBeanServerConnection mbsc,
+                                   ObjectName on,
+                                   boolean expectedException) {
+            int errorCount = 0;
+
+            try {
+                Utils.debug(Utils.DEBUG_STANDARD,
+                    "ClientSide::doSetRequest: Set attributes of the MBean") ;
+
+                Attribute attribute = new Attribute("Attribute", "My value") ;
+                mbsc.setAttribute(on, attribute) ;
+
+                if (expectedException) {
+                    System.out.println("ClientSide::doSetRequest: " +
+                        "(ERROR) Set did not fail with expected SecurityException");
+                    errorCount++;
+                } else {
+                    System.out.println("ClientSide::doSetRequest: (OK) Set succeed") ;
+                }
+            } catch(Exception e) {
+                Utils.printThrowable(e, true) ;
+                if (expectedException) {
+                    if (e instanceof java.lang.SecurityException) {
+                        System.out.println("ClientSide::doSetRequest: " +
+                            "(OK) Set failed with expected SecurityException") ;
+                    } else {
+                        System.out.println("ClientSide::doSetRequest: " +
+                            "(ERROR) Set failed with " +
+                            e.getClass() + " instead of expected SecurityException");
+                        errorCount++;
+                    }
+                } else {
+                    System.out.println("ClientSide::doSetRequest: (ERROR) Set failed");
+                    errorCount++;
+                }
+            }
+            return errorCount;
+        }
+
+        protected int doInvokeRequest(MBeanServerConnection mbsc,
+                                      ObjectName on,
+                                      boolean expectedException) {
+            int errorCount = 0;
+
+            try {
+                Utils.debug(Utils.DEBUG_STANDARD,
+                    "ClientSide::doInvokeRequest: Invoke operations on the MBean") ;
+
+                mbsc.invoke(on, "operation", null, null) ;
+
+                if (expectedException) {
+                    System.out.println("ClientSide::doInvokeRequest: " +
+                        "(ERROR) Invoke did not fail with expected SecurityException");
+                    errorCount++;
+                } else {
+                    System.out.println("ClientSide::doInvokeRequest: (OK) Invoke succeed") ;
+                }
+            } catch(Exception e) {
+                Utils.printThrowable(e, true) ;
+                if (expectedException) {
+                    if (e instanceof java.lang.SecurityException) {
+                        System.out.println("ClientSide::doInvokeRequest: " +
+                            "(OK) Invoke failed with expected SecurityException") ;
+                    } else {
+                        System.out.println("ClientSide::doInvokeRequest: " +
+                            " (ERROR) Invoke failed with " +
+                            e.getClass() + " instead of expected SecurityException");
+                        errorCount++;
+                    }
+                } else {
+                    System.out.println("ClientSide::doInvokeRequest: " +
+                        "(ERROR) Invoke failed");
+                    errorCount++;
+                }
+            }
+            return errorCount;
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/security/MBS_Light.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import javax.security.auth.Subject;
+import java.security.Principal;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.management.MBeanRegistration ;
+import javax.management.MBeanServer ;
+import javax.management.ObjectName ;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationListener;
+import javax.management.Notification;
+
+public class MBS_Light extends NotificationBroadcasterSupport
+    implements MBS_LightMBean, MBeanRegistration, NotificationListener
+{
+    private RjmxMBeanParameter param = null ;
+    private String aString = "notset" ;
+    private int anInt = 0 ;
+    private MBeanServer mbs = null ;
+    private ObjectName objname = null ;
+    private Exception anException = null ;
+    private Error anError = null ;
+    private int count = 0;
+    private SimpleListener listener = new SimpleListener();
+
+    @SqeDescriptorKey("NO PARAMETER CONSTRUCTOR MBS_Light")
+    public MBS_Light() {
+    }
+
+    @SqeDescriptorKey("ONE RjmxMBeanParameter PARAMETER CONSTRUCTOR MBS_Light")
+    public MBS_Light(@SqeDescriptorKey("CONSTRUCTOR PARAMETER param")
+                     RjmxMBeanParameter param) {
+        this.param = param ;
+    }
+
+    @SqeDescriptorKey("ONE String PARAMETER CONSTRUCTOR MBS_Light")
+    public MBS_Light(@SqeDescriptorKey("CONSTRUCTOR PARAMETER param")String param) {
+        this.aString = param ;
+    }
+
+    // Getter for property param
+    public RjmxMBeanParameter getParam() {
+        return this.param ;
+    }
+
+    // Setter for property param
+    public void setParam(RjmxMBeanParameter param) {
+        this.param = param ;
+    }
+
+    // Getter for property aString
+    public String getAstring() {
+        return this.aString ;
+    }
+
+    // Setter for property aString
+    public void setAstring(String aString) {
+        this.aString = aString ;
+    }
+
+    // Getter for property anInt
+    public int getAnInt() {
+        return this.anInt ;
+    }
+
+    // Setter for property anInt
+    public void setAnInt(int anInt) {
+        this.anInt = anInt ;
+    }
+
+    // Getter for property anException
+    public Exception getAnException() {
+        return this.anException ;
+    }
+
+    // Setter for property anException
+    public void setAnException(Exception anException) {
+        this.anException = anException ;
+    }
+
+    // Getter for property anError
+    public Error getAnError() {
+        return this.anError ;
+    }
+
+    // Setter for property anError
+    public void setAnError(Error anError) {
+        this.anError = anError ;
+    }
+
+    // An operation
+    public RjmxMBeanParameter operate1(String name) {
+        return new RjmxMBeanParameter(name) ;
+    }
+
+    // An operation
+    public String operate2(RjmxMBeanParameter param) {
+        return param.name ;
+    }
+
+    // An operation
+    public void throwError() {
+        throw new Error("JSR-160-ERROR");
+    }
+
+    // An operation
+    public void throwException() throws Exception {
+        throw new Exception("JSR-160-EXCEPTION");
+    }
+
+    // MBeanRegistration method
+    public void postDeregister() {
+    }
+
+    // MBeanRegistration method
+    public void postRegister(Boolean registrationDone) {
+    }
+
+    // MBeanRegistration method
+    public void preDeregister()
+        throws Exception
+    {
+    }
+
+    // MBeanRegistration method
+    public ObjectName preRegister(MBeanServer server, ObjectName name)
+        throws Exception
+    {
+        this.mbs = server ;
+        if ( name == null ) {
+            this.objname = new ObjectName("protocol:class=MBS_Light") ;
+        }
+        else {
+            this.objname = name ;
+        }
+        return this.objname ;
+    }
+
+    public synchronized void handleNotification(Notification notification,
+                                                Object handback) {
+        Utils.debug(Utils.DEBUG_STANDARD,
+            "MBS_Light::handleNotification: " + notification);
+        listener.handleNotification(notification, handback);
+    }
+
+    // Send a notification
+    public void sendNotification() {
+        Notification notification =
+            new Notification("JSR160-TCK-NOTIFICATION", this, count++);
+        sendNotification(notification);
+    }
+
+    public Object waitForNotificationHB() {
+        return listener.waitForNotificationHB();
+    }
+
+    // Receive multi notifications and send back handbacks
+    public synchronized Object[] waitForMultiNotifications(String nb) {
+        return listener.waitForMultiNotifications(Integer.valueOf(nb).intValue());
+    }
+
+    // Receive a notification
+    public synchronized String waitForNotification() {
+        return listener.waitForNotification();
+    }
+
+    // Is the notification received
+    public synchronized Boolean notificationReceived() {
+        return Boolean.valueOf(listener.isNotificationReceived());
+    }
+
+    // The authorization Id
+    public String getAuthorizationId() {
+        AccessControlContext acc = AccessController.getContext();
+        Subject subject = Subject.getSubject(acc);
+        Set<Principal> principals = subject.getPrincipals();
+        Iterator<Principal> i = principals.iterator();
+        StringBuffer buffer = new StringBuffer();
+        while(i.hasNext()) {
+            Principal p = i.next();
+            buffer.append(p.getName());
+            if(i.hasNext())
+                buffer.append(" ");
+        }
+
+        return buffer.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/security/MBS_LightMBean.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+@SqeDescriptorKey("INTERFACE MBS_LightMBean")
+public interface MBS_LightMBean {
+    // Getter for property param
+    @SqeDescriptorKey("ATTRIBUTE Param")
+    public RjmxMBeanParameter getParam() ;
+
+    // Setter for property param
+    @SqeDescriptorKey("ATTRIBUTE Param")
+    public void setParam(RjmxMBeanParameter param) ;
+
+    // Getter for property aString
+    @SqeDescriptorKey("ATTRIBUTE Astring")
+    public String getAstring() ;
+
+    // Setter for property aString
+    @SqeDescriptorKey("ATTRIBUTE Astring")
+    public void setAstring(String aString) ;
+
+    // Getter for property anInt
+    @SqeDescriptorKey("ATTRIBUTE AnInt")
+    public int getAnInt() ;
+
+    // Setter for property anInt
+    @SqeDescriptorKey("ATTRIBUTE AnInt")
+    public void setAnInt(int anInt) ;
+
+    // Getter for property anException
+    @SqeDescriptorKey("ATTRIBUTE AnException")
+    public Exception getAnException() ;
+
+    // Setter for property anException
+    @SqeDescriptorKey("ATTRIBUTE AnException")
+    public void setAnException(Exception anException) ;
+
+    // Getter for property anError
+    @SqeDescriptorKey("ATTRIBUTE AnError")
+    public Error getAnError() ;
+
+    // Setter for property anError
+    @SqeDescriptorKey("ATTRIBUTE AnError")
+    public void setAnError(Error anError) ;
+
+    // An operation
+    @SqeDescriptorKey("OPERATION operate1")
+    public RjmxMBeanParameter operate1(
+            @SqeDescriptorKey("OPERATION PARAMETER name")String name) ;
+
+    // An operation
+    @SqeDescriptorKey("OPERATION operate2")
+    public String operate2(
+            @SqeDescriptorKey("OPERATION PARAMETER param")RjmxMBeanParameter param) ;
+
+    // Throws an error
+    @SqeDescriptorKey("OPERATION throwError")
+    public void throwError();
+
+    // Throws an exception
+    @SqeDescriptorKey("OPERATION throwException")
+    public void throwException() throws Exception;
+
+    // Send a notification
+    @SqeDescriptorKey("OPERATION sendNotification")
+    public void sendNotification();
+
+    // Receive a notification and return the type
+    @SqeDescriptorKey("OPERATION waitForNotification")
+    public String waitForNotification();
+
+    // Receive a notification and return the HandBack
+    @SqeDescriptorKey("OPERATION waitForNotificationHB")
+    public Object waitForNotificationHB();
+
+    // Receive multi notifications and return the HandBacks
+    @SqeDescriptorKey("OPERATION waitForMultiNotifications")
+    public Object[] waitForMultiNotifications(
+            @SqeDescriptorKey("OPERATION PARAMETER nb")String nb);
+
+    // Is the notification received
+    @SqeDescriptorKey("OPERATION notificationReceived")
+    public Boolean notificationReceived();
+
+    // Return the current authorization Id
+    @SqeDescriptorKey("OPERATION getAuthorizationId")
+    public String getAuthorizationId();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/security/RjmxMBeanParameter.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.Serializable ;
+
+/**
+ * That class is used to modelize a parameter to be used as MBean property
+ * value or MBean operation parameter or returned value.
+ */
+public class RjmxMBeanParameter implements Serializable {
+    public String name = "unset" ;
+
+    public RjmxMBeanParameter() {
+    }
+
+    public RjmxMBeanParameter(String name) {
+        this.name = name ;
+    }
+
+    public boolean equals(Object obj) {
+        if ( this.name.equals(((RjmxMBeanParameter)obj).name) ) {
+            return true ;
+        } else {
+            return false ;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/security/SecurityTest.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,800 @@
+/*
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8058865
+ * @summary Checks various secure ways of connecting from remote jmx client
+ * @author Olivier Lagneau
+ * @modules java.management
+ * @library /lib/testlibrary
+ * @compile MBS_Light.java ServerDelegate.java TestSampleLoginModule.java
+ * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Dusername=SQE_username -Dpassword=SQE_password SecurityTest -server -mapType x.password.file -client -mapType credentials
+ * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Dusername=UNKNOWN_username -Dpassword=SQE_password SecurityTest -server -mapType x.password.file -client -mapType credentials -expectedThrowable java.lang.SecurityException
+ * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Dusername=SQE_username -Dpassword=WRONG_password SecurityTest -server -mapType x.password.file -client -mapType credentials -expectedThrowable java.lang.SecurityException
+ * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Dsusername=TestJMXAuthenticatorUsername -Dspassword=TestJMXAuthenticatorPassword -Dusername=TestJMXAuthenticatorUsername -Dpassword=TestJMXAuthenticatorPassword SecurityTest -server -mapType x.authenticator -client -mapType credentials
+ * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Dsusername=TestJMXAuthenticatorUsername -Dspassword=TestJMXAuthenticatorPassword -Dusername=AnotherTestJMXAuthenticatorUsername -Dpassword=TestJMXAuthenticatorPassword SecurityTest -server -mapType x.authenticator -client -mapType credentials -expectedThrowable java.lang.SecurityException
+ * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Dlogin.config.file=${test.src}/login.config -Dpassword.file=password.properties -Dusername=usernameFileLoginModule -Dpassword=passwordFileLoginModule SecurityTest -server -mapType x.login.config.PasswordFileAuthentication -client -mapType credentials
+ * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Dlogin.config.file=${test.src}/login.config.UNKNOWN -Dpassword.file=password.properties -Dusername=usernameFileLoginModule -Dpassword=passwordFileLoginModule SecurityTest -server -mapType x.login.config.PasswordFileAuthentication -client -mapType credentialss -expectedThrowable java.lang.SecurityException
+ * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Dlogin.config.file=${test.src}/login.config -Dpassword.file=password.properties -Dusername=usernameFileLoginModule -Dpassword=passwordFileLoginModule SecurityTest -server -mapType x.login.config.UnknownAuthentication -client -mapType credentials -expectedThrowable java.lang.SecurityException
+ * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Dlogin.config.file=${test.src}/login.config -Dsusername=usernameSampleLoginModule -Dspassword=passwordSampleLoginModule -Dpassword.file=password.properties -Dusername=usernameSampleLoginModule -Dpassword=passwordSampleLoginModule SecurityTest -server -mapType x.login.config.SampleLoginModule -client -mapType credentials
+ * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Dlogin.config.file=${test.src}/login.config -Dsusername=usernameSampleLoginModule -Dspassword=passwordSampleLoginModule -Dpassword.file=password.properties -Dusername=AnotherUsernameSampleLoginModule -Dpassword=passwordSampleLoginModule SecurityTest -server -mapType x.login.config.SampleLoginModule -client -mapType credentials -expectedThrowable java.lang.SecurityException
+ * @run main/othervm/timeout=300 -DDEBUG_STANDARD SecurityTest -server -mapType rmi.client.socket.factory.ssl;rmi.server.socket.factory.ssl -keystore keystoreAgent -keystorepassword glopglop -client -truststore truststoreClient -truststorepassword glopglop
+ * @run main/othervm/timeout=300 -DDEBUG_STANDARD SecurityTest -server -mapType rmi.client.socket.factory.ssl;rmi.server.socket.factory.ssl -keystore keystoreAgent -keystorepassword glopglop -client -truststore truststoreClient -truststorepassword WRONG_password -expectedThrowable java.io.IOException
+ * @run main/othervm/timeout=300 -DDEBUG_STANDARD SecurityTest -server -mapType rmi.server.socket.factory.ssl -keystore keystoreAgent -keystorepassword glopglop -client -truststore truststoreClient -truststorepassword glopglop -expectedThrowable java.io.IOException
+ * @run main/othervm/timeout=300 -DDEBUG_STANDARD SecurityTest -server -mapType rmi.client.socket.factory.ssl -keystore keystoreAgent -keystorepassword glopglop -client -truststore truststoreClient -truststorepassword glopglop -expectedThrowable java.io.IOException
+ * @run main/othervm/timeout=300 -DDEBUG_STANDARD SecurityTest -server -mapType rmi.client.socket.factory.ssl;rmi.server.socket.factory.ssl -keystore keystoreAgent -keystorepassword glopglop -client -expectedThrowable java.io.IOException
+ * @run main/othervm/timeout=300 -DDEBUG_STANDARD SecurityTest -server -mapType rmi.client.socket.factory.ssl;rmi.server.socket.factory.ssl.need.client.authentication -keystore keystoreAgent -keystorepassword glopglop -truststore truststoreAgent -truststorepassword glopglop -client  -keystore keystoreClient -keystorepassword glopglop -truststore truststoreClient -truststorepassword glopglop
+ * @run main/othervm/timeout=300 -DDEBUG_STANDARD SecurityTest -server -mapType rmi.client.socket.factory.ssl;rmi.server.socket.factory.ssl.need.client.authentication -keystore keystoreAgent -keystorepassword glopglop -truststore truststoreAgent -truststorepassword glopglop -client -keystore keystoreClient -keystorepassword WRONG_password -truststore truststoreClient -truststorepassword glopglop -expectedThrowable java.io.IOException
+ * @run main/othervm/timeout=300 -DDEBUG_STANDARD SecurityTest -server -mapType rmi.client.socket.factory.ssl;rmi.server.socket.factory.ssl.need.client.authentication -keystore keystoreAgent -keystorepassword glopglop -truststore truststoreAgent -truststorepassword glopglop -client -truststore truststoreClient -truststorepassword glopglop -expectedThrowable java.io.IOException
+ * @run main/othervm/timeout=300 -DDEBUG_STANDARD SecurityTest -server -mapType rmi.client.socket.factory.ssl;rmi.server.socket.factory.ssl.need.client.authentication -keystore keystoreAgent -keystorepassword glopglop -client -keystore keystoreClient -keystorepassword glopglop -truststore truststoreClient -truststorepassword glopglop -expectedThrowable java.io.IOException
+ * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Djavax.rmi.ssl.client.enabledCipherSuites=SSL_RSA_WITH_RC4_128_MD5 SecurityTest -server -mapType rmi.client.socket.factory.ssl;rmi.server.socket.factory.ssl.enabled.cipher.suites.md5 -keystore keystoreAgent -keystorepassword glopglop -client -truststore truststoreClient -truststorepassword glopglop
+ * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Djavax.rmi.ssl.client.enabledCipherSuites=SSL_RSA_WITH_RC4_128_SHA SecurityTest -server -mapType rmi.client.socket.factory.ssl;rmi.server.socket.factory.ssl.enabled.cipher.suites.md5 -keystore keystoreAgent -keystorepassword glopglop -client -truststore truststoreClient -truststorepassword glopglop -expectedThrowable java.io.IOException
+ * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Djavax.rmi.ssl.client.enabledCipherSuites=SSL_RSA_WITH_RC4_128_MD5 SecurityTest -server -mapType rmi.client.socket.factory.ssl;rmi.server.socket.factory.ssl.enabled.cipher.suites.sha -keystore keystoreAgent -keystorepassword glopglop -client -truststore truststoreClient -truststorepassword glopglop -expectedThrowable java.io.IOException
+ * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Djavax.rmi.ssl.client.enabledProtocols=SSLv3 SecurityTest -server -mapType rmi.client.socket.factory.ssl;rmi.server.socket.factory.ssl.enabled.protocols.sslv3 -keystore keystoreAgent -keystorepassword glopglop -client -truststore truststoreClient -truststorepassword glopglop
+ * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Djavax.rmi.ssl.client.enabledProtocols=TLSv1 SecurityTest -server -mapType rmi.client.socket.factory.ssl;rmi.server.socket.factory.ssl.enabled.protocols.sslv3 -keystore keystoreAgent -keystorepassword glopglop -client -truststore truststoreClient -truststorepassword glopglop -expectedThrowable java.io.IOException
+ * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Djavax.rmi.ssl.client.enabledProtocols=SSLv3 SecurityTest -server -mapType rmi.client.socket.factory.ssl;rmi.server.socket.factory.ssl.enabled.protocols.tlsv1 -keystore keystoreAgent -keystorepassword glopglop -client -truststore truststoreClient -truststorepassword glopglop -expectedThrowable java.io.IOException
+ */
+
+import java.io.File;
+import java.util.Map ;
+import java.util.HashMap ;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory ;
+import javax.management.MBeanServerConnection;
+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;
+
+import javax.management.Attribute ;
+import javax.management.ObjectName ;
+
+import javax.rmi.ssl.SslRMIClientSocketFactory;
+import javax.rmi.ssl.SslRMIServerSocketFactory;
+
+import java.security.Security;
+
+import jdk.testlibrary.ProcessTools;
+import jdk.testlibrary.JDKToolFinder;
+
+public class SecurityTest {
+
+    static final String SERVER_CLASS_NAME = "SecurityTest";
+    static final String CLIENT_CLASS_NAME = "SecurityTest$ClientSide";
+    static final String CLIENT_CLASS_MAIN = CLIENT_CLASS_NAME;
+
+    static final String USERNAME_PROPERTY = "username";
+    static final String PASSWORD_PROPERTY = "password";
+
+    static final String SERVER_DELEGATE_MBEAN_NAME =
+        "defaultDomain:class=ServerDelegate";
+
+    static final String RMI_SERVER_SOCKET_FACTORY_SSL = "rmi.server.socket.factory.ssl";
+    static final String RMI_CLIENT_SOCKET_FACTORY_SSL = "rmi.client.socket.factory.ssl";
+    static final String KEYSTORE_PROPNAME = "javax.net.ssl.keyStore";
+    static final String KEYSTORE_PWD_PROPNAME = "javax.net.ssl.keyStorePassword";
+    static final String TRUSTSTORE_PROPNAME = "javax.net.ssl.trustStore";
+    static final String TRUSTSTORE_PWD_PROPNAME = "javax.net.ssl.trustStorePassword";
+
+    static final String RMI_SSL_CLIENT_ENABLEDCIPHERSUITES =
+        "javax.rmi.ssl.client.enabledCipherSuites";
+    static final String RMI_SSL_CLIENT_ENABLEDPROTOCOLS =
+        "javax.rmi.ssl.client.enabledProtocols";
+
+    private JMXConnectorServer cs;
+
+    // Construct and set keyStore properties from given map
+    static void setKeyStoreProperties(Map<String, Object> map) {
+
+        String keyStore = (String) map.get("-keystore");
+        keyStore = buildSourcePath(keyStore);
+        System.setProperty(KEYSTORE_PROPNAME, keyStore);
+        System.out.println("keyStore location = \"" + keyStore + "\"");
+
+        String password = (String) map.get("-keystorepassword");
+        System.setProperty(KEYSTORE_PWD_PROPNAME, password);
+        System.out.println("keyStore password = " + password);
+
+    }
+
+    // Construct and set trustStore properties from given map
+    static void setTrustStoreProperties(Map<String, Object> map) {
+
+        String trustStore = (String) map.get("-truststore");
+        trustStore = buildSourcePath(trustStore);
+        System.setProperty(TRUSTSTORE_PROPNAME, trustStore);
+        System.out.println("trustStore location = \"" + trustStore + "\"");
+
+        String password = (String) map.get("-truststorepassword");
+        System.setProperty(TRUSTSTORE_PWD_PROPNAME, password);
+        System.out.println("trustStore password = " + password);
+
+    }
+
+    /*
+     * First Debug properties and arguments are collect in expected
+     * map  (argName, value) format, then calls original test's run method.
+     */
+    public static void main(String args[]) throws Exception {
+
+        System.out.println("=================================================");
+
+        // Parses parameters
+        Utils.parseDebugProperties();
+
+        // Supported parameters list format is :
+        // "MainClass [-server <param-spec> ...] [-client <param-spec> ...]
+        // with <param-spec> either "-parami valuei" or "-parami"
+        HashMap<String, Object> serverMap = new HashMap<>() ;
+        int clientArgsIndex =
+            Utils.parseServerParameters(args, SERVER_CLASS_NAME, serverMap);
+
+        // Extract and records client params
+        String[] clientParams = null;
+        if (clientArgsIndex < args.length) {
+            int clientParamsSize = args.length - clientArgsIndex;
+            clientParams = new String[clientParamsSize];
+            System.arraycopy(args, clientArgsIndex, clientParams, 0, clientParamsSize);
+        } else {
+            clientParams = new String[0];
+        }
+
+        // Run test
+        SecurityTest test = new SecurityTest();
+        test.run(serverMap, clientParams);
+
+    }
+
+    // Return full path of filename in the test sopurce directory
+    private static String buildSourcePath(String filename) {
+        return System.getProperty("test.src") + File.separator + filename;
+    }
+
+    /*
+     * Collects security run params for server side.
+     */
+    private HashMap<String, Object> setServerSecurityEnv(Map<String, Object> map)
+    throws Exception {
+
+        // Creates Authentication environment from server side params
+        HashMap<String, Object> env = new HashMap<>();
+
+        // Retrieve and set keystore and truststore config if any
+        if (map.containsKey("-keystore") &&
+            map.get("-keystore") != null) {
+            setKeyStoreProperties(map);
+        }
+        System.out.println("Done keystore properties");
+
+        if (map.containsKey("-truststore") &&
+            map.get("-truststore") != null) {
+            setTrustStoreProperties(map);
+        }
+        System.out.println("Done truststore properties");
+
+        String value = null;
+        if ((value = (String)map.get("-mapType")) != null) {
+
+            // Case of remote password file with all authorized credentials
+            if (value.contains("x.password.file")) {
+                String passwordFileStr = buildSourcePath("password.properties");
+                env.put("jmx.remote.x.password.file", passwordFileStr);
+                System.out.println("Added " + passwordFileStr +
+                    " file as jmx.remote.x.password.file");
+            }
+
+            // Case of dedicated authenticator class : TestJMXAuthenticator
+            if (value.contains("x.authenticator")) {
+                env.put("jmx.remote.authenticator", new TestJMXAuthenticator()) ;
+                System.out.println(
+                    "Added \"jmx.remote.authenticator\" = TestJMXAuthenticator");
+            }
+
+            // Case of security config file with standard Authentication
+            if (value.contains("x.login.config.PasswordFileAuthentication")) {
+                String loginConfig = System.getProperty("login.config.file");
+
+                // Override the default JAAS configuration
+                System.setProperty("java.security.auth.login.config",
+                    "file:" + loginConfig);
+                System.out.println("Overrided default JAAS configuration with " +
+                    "\"java.security.auth.login.config\" = \"" + loginConfig + "\"") ;
+
+                env.put("jmx.remote.x.login.config", "PasswordFileAuthentication") ;
+                System.out.println(
+                    "Added \"jmx.remote.x.login.config\" = " +
+                    "\"PasswordFileAuthentication\"") ;
+
+                // redirects "password.file" property to file in ${test.src}
+                String passwordFileStr =
+                    buildSourcePath(System.getProperty("password.file"));
+                System.setProperty("password.file", passwordFileStr);
+                System.out.println(
+                    "Redirected \"password.file\" property value to = " +
+                    passwordFileStr) ;
+            }
+
+            // Case of security config file with unexisting athentication config
+            if (value.contains("x.login.config.UnknownAuthentication")) {
+                String loginConfig = System.getProperty("login.config.file");
+
+                // Override the default JAAS configuration
+                System.setProperty("java.security.auth.login.config",
+                        "file:" + loginConfig);
+                System.out.println("Overrided default JAAS configuration with " +
+                    "\"java.security.auth.login.config\" = \"" + loginConfig + "\"") ;
+
+                env.put("jmx.remote.x.login.config", "UnknownAuthentication") ;
+                System.out.println(
+                    "Added \"jmx.remote.x.login.config\" = " +
+                    "\"UnknownAuthentication\"") ;
+
+                // redirects "password.file" property to file in ${test.src}
+                 String passwordFileStr =
+                   buildSourcePath(System.getProperty("password.file"));
+                System.setProperty("password.file", passwordFileStr);
+                System.out.println(
+                    "Redirected \"password.file\" property value to = " +
+                    passwordFileStr) ;
+            }
+
+            // Case of security config file with dedicated login module
+            if (value.contains("x.login.config.SampleLoginModule")) {
+                String loginConfig = System.getProperty("login.config.file");
+
+                // Override the default JAAS configuration
+                System.setProperty("java.security.auth.login.config",
+                        "file:" + loginConfig);
+                System.out.println("Overrided default JAAS configuration with " +
+                    "\"java.security.auth.login.config\" = \"" + loginConfig + "\"") ;
+
+                env.put("jmx.remote.x.login.config", "SampleLoginModule") ;
+                System.out.println(
+                    "Added \"jmx.remote.x.login.config\" = " +
+                    "\"SampleLoginModule\"") ;
+            }
+
+            // Simple rmi ssl authentication
+            if (value.contains(RMI_CLIENT_SOCKET_FACTORY_SSL)) {
+                env.put("jmx.remote.rmi.client.socket.factory",
+                    new SslRMIClientSocketFactory()) ;
+                System.out.println(
+                     "Added \"jmx.remote.rmi.client.socket.factory\"" +
+                     " = SslRMIClientSocketFactory") ;
+            }
+
+            if (value.contains(RMI_SERVER_SOCKET_FACTORY_SSL)) {
+                if (value.contains(
+                        "rmi.server.socket.factory.ssl.need.client.authentication")) {
+                   // rmi ssl authentication with client authentication
+                   env.put("jmx.remote.rmi.server.socket.factory",
+                       new SslRMIServerSocketFactory(null, null, true)) ;
+                   System.out.println(
+                       "Added \"jmx.remote.rmi.server.socket.factory\"" +
+                       " = SslRMIServerSocketFactory with client authentication") ;
+
+                } else if (value.contains("rmi.server.socket.factory.ssl.enabled.cipher.suites.md5")) {
+                    // Allows all ciphering and protocols for testing purpose
+                    Security.setProperty("jdk.tls.disabledAlgorithms", "");
+
+                    env.put("jmx.remote.rmi.server.socket.factory",
+                        new SslRMIServerSocketFactory(
+                            new String[] {"SSL_RSA_WITH_RC4_128_MD5"}, null, false));
+                    System.out.println(
+                        "Added \"jmx.remote.rmi.server.socket.factory\"" +
+                        " = SslRMIServerSocketFactory with SSL_RSA_WITH_RC4_128_MD5 cipher suite");
+
+                } else if (value.contains("rmi.server.socket.factory.ssl.enabled.cipher.suites.sha")) {
+                    // Allows all ciphering and protocols for testing purpose
+                    Security.setProperty("jdk.tls.disabledAlgorithms", "");
+
+                    env.put("jmx.remote.rmi.server.socket.factory",
+                        new SslRMIServerSocketFactory(
+                            new String[] { "SSL_RSA_WITH_RC4_128_SHA" }, null, false)) ;
+                    System.out.println(
+                        "Added \"jmx.remote.rmi.server.socket.factory\"" +
+                        " = SslRMIServerSocketFactory with SSL_RSA_WITH_RC4_128_SHA cipher suite") ;
+
+                } else if (value.contains("rmi.server.socket.factory.ssl.enabled.protocols.sslv3")) {
+                    // Allows all ciphering and protocols for testing purpose
+                    Security.setProperty("jdk.tls.disabledAlgorithms", "");
+
+                    env.put("jmx.remote.rmi.server.socket.factory",
+                        new SslRMIServerSocketFactory(null, new String[] {"SSLv3"}, false)) ;
+                    System.out.println(
+                        "Added \"jmx.remote.rmi.server.socket.factory\"" +
+                        " = SslRMIServerSocketFactory with SSLv3 protocol") ;
+
+                } else if (value.contains("rmi.server.socket.factory.ssl.enabled.protocols.tlsv1")) {
+                    // Allows all ciphering and protocols for testing purpose
+                    Security.setProperty("jdk.tls.disabledAlgorithms", "");
+
+                    env.put("jmx.remote.rmi.server.socket.factory",
+                        new SslRMIServerSocketFactory(null, new String[] {"TLSv1"}, false)) ;
+                    System.out.println(
+                        "Added \"jmx.remote.rmi.server.socket.factory\"" +
+                        " = SslRMIServerSocketFactory with TLSv1 protocol") ;
+
+                } else {
+                    env.put("jmx.remote.rmi.server.socket.factory",
+                        new SslRMIServerSocketFactory());
+                    System.out.println(
+                        "Added \"jmx.remote.rmi.server.socket.factory\"" +
+                        " = SslRMIServerSocketFactory");
+                }
+            }
+        }
+
+        return env;
+    }
+
+    /*
+     * Create the MBeansServer side of the test and returns its address
+     */
+    private JMXServiceURL createServerSide(Map<String, Object> serverMap)
+    throws Exception {
+        final int NINETY_SECONDS = 90;
+
+        System.out.println("SecurityTest::createServerSide: Start") ;
+
+        // Prepare server side security env
+        HashMap<String, Object> env = setServerSecurityEnv(serverMap);
+
+        // Create and start mbean server and connector server
+        MBeanServer mbs = MBeanServerFactory.newMBeanServer();
+        JMXServiceURL url = new JMXServiceURL("rmi", null, 0);
+        cs = JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);
+        cs.start();
+
+        // Waits availibility of connector server
+        Utils.waitReady(cs, NINETY_SECONDS);
+
+        JMXServiceURL addr = cs.getAddress();
+
+        System.out.println("SecurityTest::createServerSide: Done.") ;
+
+        return addr;
+    }
+
+    /*
+     * Creating command-line for running subprocess JVM:
+     *
+     * JVM command line is like:
+     * {test_jdk}/bin/java {defaultopts} -cp {test.class.path} {testopts} main
+     *
+     * {defaultopts} are the default java options set by the framework.
+     *
+     */
+    private List<String> buildCommandLine(String args[]) {
+
+        System.out.println("SecurityTest::buildCommandLine: Start") ;
+
+        List<String> opts = new ArrayList<>();
+        opts.add(JDKToolFinder.getJDKTool("java"));
+        opts.addAll(Arrays.asList(jdk.testlibrary.Utils.getTestJavaOpts()));
+
+        // We need to forward some properties to the client side
+        opts.add("-Dtest.src=" + System.getProperty("test.src"));
+
+        String usernameValue = System.getProperty(USERNAME_PROPERTY);
+        if (usernameValue != null) {
+            System.out.println("SecurityTest::buildCommandLine: "+
+                " forward username property to client side");
+            opts.add("-D" + USERNAME_PROPERTY + "=" + usernameValue);
+        }
+        String passwordValue = System.getProperty(PASSWORD_PROPERTY);
+        if (passwordValue != null) {
+            System.out.println("SecurityTest::buildCommandLine: "+
+                " forward password property to client side");
+            opts.add("-D" + PASSWORD_PROPERTY + "=" + passwordValue);
+        }
+
+        String enabledCipherSuites =
+            System.getProperty(RMI_SSL_CLIENT_ENABLEDCIPHERSUITES);
+        if (enabledCipherSuites != null) {
+            System.out.println("SecurityTest::buildCommandLine: "+
+                " forward enabledCipherSuites property to client side");
+            opts.add("-D" + RMI_SSL_CLIENT_ENABLEDCIPHERSUITES +
+                "=" + enabledCipherSuites);
+        }
+
+        String enabledProtocols =
+            System.getProperty(RMI_SSL_CLIENT_ENABLEDPROTOCOLS);
+        if (enabledProtocols != null) {
+            System.out.println("SecurityTest::buildCommandLine: "+
+                " forward enabledProtocols property to client side");
+            opts.add("-D" + RMI_SSL_CLIENT_ENABLEDPROTOCOLS +
+                "=" + enabledProtocols);
+        }
+
+        opts.add("-cp");
+        opts.add(System.getProperty("test.class.path", "test.class.path"));
+        opts.add(CLIENT_CLASS_MAIN);
+        opts.addAll(Arrays.asList(args));
+
+        System.out.println("SecurityTest::buildCommandLine: Done.") ;
+
+        return opts;
+    }
+
+    /**
+     * Runs SecurityTest$ClientSide with the passed options and redirects
+     * subprocess standard I/O to the current (parent) process. This provides a
+     * trace of what happens in the subprocess while it is runnning (and before
+     * it terminates).
+     *
+     * @param serviceUrlStr string representing the JMX service Url to connect to.
+     */
+    private int runClientSide(String args[], String serviceUrlStr) throws Exception {
+
+        System.out.println("SecurityTest::runClientSide: Start") ;
+
+        // Building command-line
+        List<String> opts = buildCommandLine(args);
+        opts.add("-serviceUrl");
+        opts.add(serviceUrlStr);
+
+        // Launch separate JVM subprocess
+        int exitCode = 0;
+        String[] optsArray = opts.toArray(new String[0]);
+        ProcessBuilder pb = new ProcessBuilder(optsArray);
+        Process p = ProcessTools.startProcess("SecurityTest$ClientSide", pb);
+
+        // Handling end of subprocess
+        try {
+            exitCode = p.waitFor();
+            if (exitCode != 0) {
+                System.out.println(
+                    "Subprocess unexpected exit value of [" + exitCode +
+                    "]. Expected 0.\n");
+            }
+        } catch (InterruptedException e) {
+            System.out.println("Parent process interrupted with exception : \n " + e + " :" );
+
+            // Parent thread unknown state, killing subprocess.
+            p.destroyForcibly();
+
+            throw new RuntimeException(
+                "Parent process interrupted with exception : \n " + e + " :" );
+
+        } finally {
+            if (p.isAlive()) {
+                p.destroyForcibly();
+            }
+
+            System.out.println("SecurityTest::runClientSide: Done") ;
+
+            return exitCode;
+        }
+
+     }
+
+    public void run(Map<String, Object> serverArgs, String clientArgs[]) {
+
+        System.out.println("SecurityTest::run: Start") ;
+        int errorCount = 0;
+
+        try {
+            // Initialise the server side
+            JMXServiceURL urlToUse = createServerSide(serverArgs);
+
+            // Run client side
+            errorCount = runClientSide(clientArgs, urlToUse.toString());
+
+            if ( errorCount == 0 ) {
+                System.out.println("SecurityTest::run: Done without any error") ;
+            } else {
+                System.out.println(
+                    "SecurityTest::run: Done with " + errorCount + " error(s)");
+                throw new RuntimeException("errorCount = " + errorCount);
+            }
+
+            cs.stop();
+
+        } catch(Exception e) {
+            throw new RuntimeException(e);
+        }
+
+    }
+
+    private static class ClientSide {
+
+        private JMXConnector cc = null;
+        private MBeanServerConnection mbsc = null;
+
+        public static void main(String args[]) throws Exception {
+
+            // Parses parameters
+            Utils.parseDebugProperties();
+
+            // Supported parameters list format is : "MainClass [-client <param-spec> ...]
+            // with <param-spec> either "-parami valuei" or "-parami"
+            HashMap<String, Object> clientMap = new HashMap<>() ;
+            Utils.parseClientParameters(args, CLIENT_CLASS_NAME, clientMap);
+
+            // Run test
+            ClientSide test = new ClientSide();
+            test.run(clientMap);
+        }
+
+        public void run(Map<String, Object> args) {
+
+            System.out.println("ClientSide::run: Start");
+            int errorCount = 0;
+
+            try {
+                // Setup client side parameters
+                HashMap<String, Object> env = new HashMap<>();
+
+                // If needed allows all ciphering and protocols for testing purpose
+                if (System.getProperty(RMI_SSL_CLIENT_ENABLEDCIPHERSUITES) != null) {
+                    Security.setProperty("jdk.tls.disabledAlgorithms", "");
+                }
+
+                // If needed allows all ciphering and protocols for testing purpose
+                if (System.getProperty(RMI_SSL_CLIENT_ENABLEDPROTOCOLS) != null) {
+                    Security.setProperty("jdk.tls.disabledAlgorithms", "");
+                }
+
+                // Retrieve and set keystore and truststore config if any
+                if (args.containsKey("-keystore") &&
+                    args.get("-keystore") != null) {
+                    SecurityTest.setKeyStoreProperties(args);
+                }
+                if (args.containsKey("-truststore") &&
+                    args.get("-truststore") != null) {
+                    SecurityTest.setTrustStoreProperties(args);
+                }
+
+                Object value = args.get("-mapType");
+                if ((value != null) &&
+                    value.equals("credentials")) {
+                    String username = System.getProperty("username");
+                    String password = System.getProperty("password");
+                    Utils.debug(Utils.DEBUG_STANDARD,
+                        "add \"jmx.remote.credentials\" = \"" +
+                        username + "\", \"" + password + "\"");
+                    env.put("jmx.remote.credentials",
+                        new String[] { username , password });
+                }
+
+                String expectedThrowable = (String) args.get("-expectedThrowable");
+
+                String authCallCountName = "-expectedAuthenticatorCallCount";
+                int authCallCountValue = 0;
+                if (args.containsKey(authCallCountName)) {
+                    authCallCountValue =
+                        (new Integer((String) args.get(authCallCountName))).intValue();
+                }
+
+                try {
+                    // Get a connection to remote mbean server
+                    JMXServiceURL addr = new JMXServiceURL((String)args.get("-serviceUrl"));
+                    cc = JMXConnectorFactory.connect(addr,env);
+                    mbsc = cc.getMBeanServerConnection();
+
+                    // In case we should have got an exception
+                    if (expectedThrowable != null) {
+                        System.out.println("ClientSide::run: (ERROR) " +
+                            " Connect did not fail with expected " + expectedThrowable);
+                        errorCount++;
+                    } else {
+                        System.out.println("ClientSide::run: (OK) Connect succeed");
+                    }
+                } catch (Throwable e) {
+                    Utils.printThrowable(e, true);
+                    if (expectedThrowable != null) {
+                        if (Utils.compareThrowable(e, expectedThrowable)) {
+                            System.out.println("ClientSide::run: (OK) " +
+                                "Connect failed with expected " + expectedThrowable);
+                        } else {
+                            System.out.println("ClientSide::run: (ERROR) Connect failed with " +
+                                e.getClass() + " instead of expected " +
+                                expectedThrowable);
+                            errorCount++;
+                        }
+                    } else {
+                        System.out.println("ClientSide::run: (ERROR) " +
+                            "Connect failed with exception");
+                        errorCount++;
+                    }
+                }
+
+                // Depending on the client state,
+                // perform some requests
+                if (mbsc != null && errorCount == 0) {
+                    // Perform some little JMX requests
+                    System.out.println("ClientSide::run: Start sending requests");
+
+                    doRequests();
+
+                    // In case authentication has been used we check how it did.
+                    if (authCallCountValue != 0) {
+                        errorCount += checkAuthenticator(mbsc, authCallCountValue);
+                    }
+                }
+            } catch (Exception e) {
+                Utils.printThrowable(e, true);
+                errorCount++;
+            } finally {
+                // Terminate the JMX Client if any
+                if (cc != null) {
+                    try {
+                        cc.close();
+                    } catch (Exception e) {
+                        Utils.printThrowable(e, true) ;
+                        errorCount++;
+                    }
+                }
+            }
+
+            System.out.println("ClientSide::run: Done");
+
+            // Handle result
+            if (errorCount != 0) {
+                throw new RuntimeException();
+            }
+        }
+
+        private void doRequests() throws Exception {
+
+            // Send  some requests to the remote JMX server
+            ObjectName objName1 =
+                new ObjectName("TestDomain:class=MBS_Light,rank=1");
+            String mbeanClass = "MBS_Light";
+            Exception exception = new Exception("MY TEST EXCEPTION");
+            Attribute attException = new Attribute("AnException", exception);
+            Error error = new Error("MY TEST ERROR");
+            Attribute attError = new Attribute("AnError", error);
+            String opParamString = "TOTORO";
+            RjmxMBeanParameter opParam = new RjmxMBeanParameter(opParamString);
+            Object[] params1 = {opParamString};
+            String[] sig1 = {"java.lang.String"};
+            Object[] params2 = {opParam};
+            String[] sig2 = {"RjmxMBeanParameter"};
+
+            // Create and register the MBean
+            Utils.debug(Utils.DEBUG_STANDARD,
+                "ClientSide::doRequests: Create and register the MBean");
+            mbsc.createMBean(mbeanClass, objName1);
+            if (!mbsc.isRegistered(objName1)) {
+                throw new Exception("Unable to register an MBean");
+            }
+
+            // Set attributes of the MBean
+            Utils.debug(Utils.DEBUG_STANDARD,
+                "ClientSide::doRequests: Set attributes of the MBean");
+            mbsc.setAttribute(objName1, attException);
+            mbsc.setAttribute(objName1, attError);
+
+            // Get attributes of the MBean
+            Utils.debug(Utils.DEBUG_STANDARD,
+                "ClientSide::doRequests: Get attributes of the MBean");
+            Exception retException =
+                (Exception) mbsc.getAttribute(objName1,"AnException");
+            if (!retException.getMessage().equals(exception.getMessage())) {
+                System.out.println("Expected = " + exception);
+                System.out.println("Got = " + retException);
+                throw new Exception("Attribute AnException not as expected");
+            }
+            Error retError = (Error) mbsc.getAttribute(objName1, "AnError");
+            if (!retError.getMessage().equals(error.getMessage())) {
+                System.out.println("Expected = " + error);
+                System.out.println("Got = " + retError);
+                throw new Exception("Attribute AnError not as expected");
+            }
+
+            // Invoke operations on the MBean
+            Utils.debug(Utils.DEBUG_STANDARD,
+                "ClientSide::doRequests: Invoke operations on the MBean");
+            RjmxMBeanParameter res1 =
+                (RjmxMBeanParameter) mbsc.invoke(objName1, "operate1", params1, sig1);
+            if (!res1.equals(opParam)) {
+                System.out.println("Expected = " + opParam);
+                System.out.println("Got = " + res1);
+                throw new Exception("Operation operate1 behaved badly");
+            }
+            String res2 =
+                (String) mbsc.invoke(objName1, "operate2", params2, sig2);
+            if (!res2.equals(opParamString)) {
+                System.out.println("Expected = " + opParamString);
+                System.out.println("Got = " + res2);
+                throw new Exception("Operation operate2 behaved badly");
+            }
+
+            // Unregister the MBean
+            Utils.debug(Utils.DEBUG_STANDARD,
+                "ClientSide::doRequests: Unregister the MBean");
+            mbsc.unregisterMBean(objName1);
+            if (mbsc.isRegistered(objName1)) {
+                throw new Exception("Unable to unregister an MBean");
+            }
+        }
+
+        /**
+         * Make some check about the instance of TestJMXAuthenticator.
+         * The authenticator is supposed to have set some properties on
+         * a ServerDelegate MBean.
+         * We compare the number of times it has been called with the expected value.
+         * We also check the Principal that has been given to the authenticator
+         * was not null.
+         * That method is of use to authentication with the JSR 262.
+         * @param mbs
+         * @param expectedAuthenticatorCallCount
+         * @return The number of errors encountered.
+         * @throws java.lang.Exception
+         */
+        protected int checkAuthenticator(MBeanServerConnection mbs,
+                int expectedAuthenticatorCallCount) throws Exception {
+            int errorCount = 0;
+
+            // Ensure the authenticator has been called the right number
+            // of times.
+            int callCount =
+                    ((Integer) mbs.getAttribute(
+                    new ObjectName(SERVER_DELEGATE_MBEAN_NAME),
+                    "TestJMXAuthenticatorCallCount")).intValue();
+
+            if (callCount == expectedAuthenticatorCallCount) {
+                System.out.println("---- OK Authenticator has been called "
+                        + expectedAuthenticatorCallCount + " time");
+            } else {
+                errorCount++;
+                System.out.println("---- ERROR Authenticator has been called " + callCount
+                        + " times in place of " + expectedAuthenticatorCallCount);
+            }
+
+            // Ensure the provider has been called with
+            // a non null Principal.
+            String principalString =
+                (String) mbs.getAttribute(
+                new ObjectName(SERVER_DELEGATE_MBEAN_NAME),
+                "TestJMXAuthenticatorPrincipalString");
+
+            if (principalString == null) {
+                errorCount++;
+                System.out.println("---- ERROR Authenticator has been called"
+                        + " with a null Principal");
+            } else {
+                if (principalString.length() > 0) {
+                    System.out.println("---- OK Authenticator has been called"
+                            + " with the Principal " + principalString);
+                } else {
+                    errorCount++;
+                    System.out.println("---- ERROR Authenticator has been called"
+                            + " with an empty Principal");
+                }
+            }
+
+            return errorCount;
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/security/ServerDelegate.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.management.remote.JMXServiceURL ;
+import javax.management.MBeanRegistration;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.StandardMBean;
+
+/**
+ * This class defines an MBean that can be registered and used on client side
+ * to handle informations or properties of the remote server.
+ *
+ * For example, this MBean can store IOR addresses
+ * of RMI/IIOP connector(s) used in a test.
+ *
+ * That MBean might not be used for testing purpose itself.
+ */
+public class ServerDelegate implements ServerDelegateMBean, MBeanRegistration {
+
+    private MBeanServer mbeanServer = null;
+    private List<JMXServiceURL> addresses  = null;
+    private String port;
+    private static String javaVersion = System.getProperty("java.version");
+    private int sqeJmxwsCredentialsProviderCallCount = 0;
+    private String jmxwsCredentialsProviderUrl = null;
+    private int testJMXAuthenticatorCallCount = 0;
+    private Principal testJMXAuthenticatorPrincipal = null;
+
+    @SqeDescriptorKey("NO PARAMETER CONSTRUCTOR ServerDelegate")
+    public ServerDelegate() {
+        addresses = new ArrayList<JMXServiceURL>();
+    }
+
+    public ObjectName preRegister(MBeanServer server, ObjectName name)
+    throws Exception {
+        // Initialize MBeanServer attribute
+        mbeanServer = server;
+        return name;
+    }
+    public void postRegister(Boolean registrationDone) {
+    }
+    public void preDeregister() throws Exception {
+    }
+    public void postDeregister() {
+    }
+
+    public void addAddress(JMXServiceURL url) {
+        addresses.add(url) ;
+    }
+
+    public List<JMXServiceURL> getAddresses() {
+        return addresses ;
+    }
+
+    public void setPort(String p) {
+        port = p ;
+    }
+
+    public String getPort() {
+        return port ;
+    }
+
+    public String getJavaVersion() {
+        return javaVersion;
+    }
+
+    public void sqeJmxwsCredentialsProviderCalled() {
+        sqeJmxwsCredentialsProviderCallCount++;
+    }
+
+    public int getSqeJmxwsCredentialsProviderCallCount() {
+        return sqeJmxwsCredentialsProviderCallCount;
+    }
+
+    public void setJmxwsCredentialsProviderUrl(String url) {
+        jmxwsCredentialsProviderUrl = url;
+    }
+
+    public String getJmxwsCredentialsProviderUrl() {
+        return jmxwsCredentialsProviderUrl;
+    }
+
+    public void testJMXAuthenticatorCalled() {
+        testJMXAuthenticatorCallCount++;
+    }
+
+    public int getTestJMXAuthenticatorCallCount() {
+        return testJMXAuthenticatorCallCount;
+    }
+
+    public void setTestJMXAuthenticatorPrincipal(Principal principal) {
+        testJMXAuthenticatorPrincipal = principal;
+    }
+
+    public String getTestJMXAuthenticatorPrincipalString() {
+        if ( testJMXAuthenticatorPrincipal != null ) {
+            return testJMXAuthenticatorPrincipal.toString();
+        }
+
+        return null;
+    }
+
+   /**
+     * Instantiates and registers a StandardMBean in the MBean server.
+     *
+     * @param implementationClassName
+     *      The implementation class name of the MBean.
+     * @param interfaceClassName
+     *      The management interface class name of the MBean.
+     * @param isMXBean
+     *      If true, the resultant MBean is an MXBean.
+     * @param name
+     *      The object name of the StandardMBean.
+     */
+    @SuppressWarnings("unchecked")
+    public void createStandardMBean(
+            String implementationClassName,
+            String interfaceClassName,
+            boolean isMXBean,
+            ObjectName name)
+            throws Exception {
+
+        Object implementation =
+                Class.forName(implementationClassName).newInstance();
+        Class<Object> interfaceClass = interfaceClassName == null ? null :
+            (Class<Object>)Class.forName(interfaceClassName);
+
+        // Create the StandardMBean
+        StandardMBean standardMBean = new StandardMBean(
+                implementation,
+                interfaceClass,
+                isMXBean);
+
+        // Register the StandardMBean
+        mbeanServer.registerMBean(standardMBean, name);
+    }
+
+    /**
+     * Instantiates and registers a StandardMBean in the MBean server.
+     * The object will use standard JMX design pattern to determine
+     * the management interface associated with the given implementation.
+     */
+    @SuppressWarnings("unchecked")
+    public void createStandardMBean(
+            String implementationClassName,
+            boolean isMXBean,
+            ObjectName name)
+            throws Exception {
+
+        createStandardMBean(implementationClassName, null, isMXBean, name);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/security/ServerDelegateMBean.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.security.Principal;
+import java.util.List;
+
+import javax.management.remote.JMXServiceURL ;
+import javax.management.ObjectName;
+
+@SqeDescriptorKey("INTERFACE ServerDelegateMBean")
+public interface ServerDelegateMBean {
+    @SqeDescriptorKey("ATTRIBUTE Address")
+    public void addAddress(JMXServiceURL url);
+
+    @SqeDescriptorKey("ATTRIBUTE Address")
+    public List<JMXServiceURL> getAddresses();
+
+    public String getPort();
+    public void setPort(String p);
+
+    public String getJavaVersion();
+
+    public void sqeJmxwsCredentialsProviderCalled();
+    public int getSqeJmxwsCredentialsProviderCallCount();
+
+    public void setJmxwsCredentialsProviderUrl(String url);
+    public String getJmxwsCredentialsProviderUrl();
+
+    public void testJMXAuthenticatorCalled();
+    public int getTestJMXAuthenticatorCallCount();
+
+    public void setTestJMXAuthenticatorPrincipal(Principal principal);
+    public String getTestJMXAuthenticatorPrincipalString();
+
+    public void createStandardMBean(
+            String implementationClassName,
+            String interfaceClassName,
+            boolean isMXBean,
+            ObjectName name)
+            throws Exception;
+
+    public void createStandardMBean(
+            String implementationClassName,
+            boolean isMXBean,
+            ObjectName name)
+            throws Exception;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/security/Simple.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+//import java.beans.ConstructorProperties;
+import javax.management.ConstructorParameters;
+
+/**
+ * This class defines a simple standard MBean.
+ */
+public class Simple implements SimpleMBean {
+
+    private String attribute = "initial_value";
+    private boolean operationInvoked = false;
+    private boolean operation2Invoked = false;
+
+    @SqeDescriptorKey("NO PARAMETER CONSTRUCTOR Simple")
+    public Simple() {
+    }
+
+    @SqeDescriptorKey("TWO PARAMETERS CONSTRUCTOR Simple")
+    @ConstructorParameters({"unused1", "unused2"})
+    public Simple(@SqeDescriptorKey("CONSTRUCTOR PARAMETER unused1")int unused1,
+            @SqeDescriptorKey("CONSTRUCTOR PARAMETER unused2")int unused2) {
+    }
+
+    public String getAttribute() {
+        return attribute;
+    }
+    public void setAttribute(String s) {
+        attribute = s;
+    }
+    public boolean getOperationInvoked() {
+        return operationInvoked;
+    }
+    public boolean getOperation2Invoked() {
+        return operation2Invoked;
+    }
+
+    public void operation() {
+        operationInvoked = true;
+        return;
+    }
+
+    public String operation2(int i) {
+        operation2Invoked = true;
+        return String.valueOf(i);
+    }
+
+    public void reset() {
+        attribute = "initial_value";
+        operationInvoked = false;
+        operation2Invoked = false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/security/SimpleListener.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// JDK
+import java.util.Vector;
+
+// JMX
+import javax.management.NotificationListener;
+import javax.management.Notification;
+
+public class SimpleListener implements NotificationListener {
+    private boolean received = false;
+    private String type = null;
+    private Object handback = null;
+    private Vector<Object> handbacks = new Vector<Object>();
+    private int nbrec = 0;
+
+    public synchronized void handleNotification(Notification notification,
+                                                Object handback) {
+        Utils.debug(Utils.DEBUG_STANDARD,
+            "SimpleListener::handleNotification :" + notification);
+        try {
+            received = true;
+            type = notification.getType();
+            this.handback = handback;
+            handbacks.add(handback);
+            nbrec++;
+            notify();
+        } catch(Exception e) {
+            System.out.println("(ERROR) SimpleListener::handleNotification :"
+                        + " Caught exception "
+                        + e) ;
+        }
+    }
+
+    public synchronized boolean isNotificationReceived() {
+        boolean ret = received;
+        reset();
+        return ret;
+    }
+
+    public synchronized Object[] waitForMultiNotifications(int nb) {
+        while(true) {
+            if(nbrec < nb) {
+                Utils.debug(Utils.DEBUG_STANDARD,
+                            "SimpleListener::waitForMultiNotifications wait");
+                try {
+                    wait();
+                } catch(InterruptedException ie) {
+                    // OK : we wait for being interrupted
+                }
+                Utils.debug(Utils.DEBUG_STANDARD,
+                            "SimpleListener::waitForMultiNotifications wait over");
+            }
+            else
+            break;
+        }
+        Object[] ret = handbacks.toArray();
+        reset();
+        return ret;
+    }
+
+    private void reset() {
+        received = false;
+        handback = null;
+        handbacks.removeAllElements();
+        type = null;
+    }
+
+    public synchronized Object waitForNotificationHB() {
+        while(true) {
+            if(!received) {
+                Utils.debug(Utils.DEBUG_STANDARD,
+                    "SimpleListener::waitForNotificationHB wait");
+                try {
+                    wait();
+                } catch(InterruptedException ie) {
+                    // OK : we wait for being interrupted
+                }
+                Utils.debug(Utils.DEBUG_STANDARD,
+                    "SimpleListener::waitForNotificationHB received");
+            }
+            else
+                break;
+        }
+        Object ret = handback;
+        reset();
+        return ret;
+    }
+
+    public synchronized String waitForNotification() {
+        while(true) {
+            if(!received) {
+                Utils.debug(Utils.DEBUG_STANDARD,
+                    "SimpleListener::waitForNotification wait");
+                try {
+                    wait();
+                } catch(InterruptedException ie) {
+                    // OK : we wait for being interrupted
+                }
+                Utils.debug(Utils.DEBUG_STANDARD,
+                    "SimpleListener::waitForNotification received");
+            }
+            else
+                break;
+        }
+        String ret = type;
+        reset();
+        return ret;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/security/SimpleMBean.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * This interface defines a simple standard MBean.
+ */
+@SqeDescriptorKey("INTERFACE SimpleMBean")
+public interface SimpleMBean {
+
+    @SqeDescriptorKey("ATTRIBUTE Attribute")
+    public String getAttribute();
+
+    @SqeDescriptorKey("ATTRIBUTE Attribute")
+    public void setAttribute(String s);
+
+    @SqeDescriptorKey("ATTRIBUTE OperationInvoked")
+    public boolean getOperationInvoked();
+
+    @SqeDescriptorKey("ATTRIBUTE Operation2Invoked")
+    public boolean getOperation2Invoked();
+
+    // Void operation
+    // The associated MBeanOperationInfo is mapped to OpenMBeanOperationInfo
+    // => openType is added to the descriptor
+    @SqeDescriptorKey(value = "OPERATION operation",
+    descriptorFields = {"openType=SimpleType.VOID"})
+    public void operation();
+
+    @SqeDescriptorKey("OPERATION operation2")
+    public String operation2(int i);
+
+    // Void operation
+    // The associated MBeanOperationInfo is mapped to OpenMBeanOperationInfo
+    // => openType is added to the descriptor
+    @SqeDescriptorKey(value = "OPERATION reset",
+    descriptorFields = {"openType=SimpleType.VOID"})
+    public void reset();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/security/SqeDescriptorKey.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import javax.management.DescriptorKey;
+
+/**
+ * That annotation is usable everywhere DescriptorKey is (and even more).
+ * It is for use to test that you can retrieve the SqeDescriptorKey into the
+ * appropriate Descriptor instances as built by the JMX runtime.
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+public @interface SqeDescriptorKey {
+    @DescriptorKey("sqeDescriptorKey")
+    String value();
+
+    // List descriptor fields that may be added or may be updated
+    // when retrieving an MBeanInfo using a JMXWS connection compared to the
+    // MBeanInfo returned by a local MBeanServer.
+    // The annotation format is :
+    //   <descriptorFieldName>=<descriptorFieldValue>
+    // The values actually handled by the test suite are :
+    //   openType=SimpleType.VOID
+    @DescriptorKey("descriptorFields")
+    String[] descriptorFields() default {};
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/security/TestJMXAuthenticator.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.security.Principal;
+
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.remote.JMXAuthenticator;
+import javax.management.remote.JMXPrincipal;
+import javax.security.auth.Subject;
+
+public final class TestJMXAuthenticator implements JMXAuthenticator {
+
+    private String protocol = "";
+    private MBeanServer mbs = null;
+
+    public TestJMXAuthenticator() {
+    }
+
+    public TestJMXAuthenticator(String protocol) {
+        this.protocol = protocol;
+    }
+
+    public TestJMXAuthenticator(String protocol, MBeanServer mbs) {
+        this.protocol = protocol;
+        this.mbs = mbs;
+    }
+
+    public Subject authenticate(Object credentials) {
+
+        String credentials_username = "";
+        String credentials_password = "";
+        Principal aPrincipal = null;
+
+        credentials_username = ((String[]) credentials)[0];
+        credentials_password = ((String[]) credentials)[1];
+
+        String authenticated_username = System.getProperty("susername");
+        String authenticated_password = System.getProperty("spassword");
+        String principal = System.getProperty("principal");
+
+        System.out.println("TestJMXAuthenticator::authenticate: Start");
+        System.out.println("TestJMXAuthenticator::authenticate: credentials username = " +
+                credentials_username);
+        System.out.println("TestJMXAuthenticator::authenticate: credentials password = " +
+                credentials_password);
+        System.out.println("TestJMXAuthenticator::authenticate: authenticated username = " +
+                authenticated_username);
+        System.out.println("TestJMXAuthenticator::authenticate: authenticated password = " +
+                authenticated_password);
+        System.out.println("TestJMXAuthenticator::authenticate: principal used for " +
+                "authorization = " + principal);
+
+        if (credentials_username.equals(authenticated_username) &&
+                credentials_password.equals(authenticated_password)) {
+            System.out.println("TestJMXAuthenticator::authenticate: " +
+                    "Authenticator should succeed");
+        } else {
+            System.out.println("TestJMXAuthenticator::authenticate: " +
+                    "Authenticator should reject");
+            throw new SecurityException("TestJMXAuthenticator throws EXCEPTION");
+        }
+
+        // At this point, authentication has succeeded
+        // (no SecurityException thrown).
+        //
+        // If no authorization is required, the returned subject (empty or not)
+        // is useless.
+        // Otherwise, the returned subject must define a principal
+        // and authorization will be performed against this principal.
+        //
+        // Note that this custom JMXAuthenticator is used for test purpose and
+        // the username used to perform authentication may be different from the
+        // username used to perform authorization.
+        //
+        Subject subject = new Subject();
+
+        if (principal != null) {
+            System.out.println("TestJMXAuthenticator::authenticate: " +
+                    "Add " + principal + " principal to the returned subject");
+            subject.getPrincipals().add(new JMXPrincipal(principal));
+        }
+
+        return subject;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/security/TestSampleLoginModule.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.util.Map;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.login.LoginException;
+import javax.security.auth.spi.LoginModule;
+
+
+public final class TestSampleLoginModule implements LoginModule {
+
+    private Subject subject;
+    private CallbackHandler callbackHandler;
+    private Map<String, ?> sharedState;
+    private Map<String, ?> options;
+
+    public TestSampleLoginModule() {
+    }
+
+    public void initialize(Subject subject,
+            CallbackHandler callbackHandler,
+            Map<String,?> sharedState,
+            Map<String,?> options) {
+
+        this.subject = subject;
+        this.callbackHandler = callbackHandler;
+        this.sharedState = sharedState;
+        this.options = options;
+    }
+
+  /*
+   * Authenticate the user by comparing the values of the java properties
+   * (username and password) against the values of the credentials.
+   * */
+    public boolean login() throws LoginException {
+
+        String credentials_username = null;
+        String credentials_password = null;
+        String authenticated_username = System.getProperty("susername");
+        String authenticated_password = System.getProperty("spassword");
+
+        System.out.println("TestSampleLoginModule::login: Start");
+
+        // First retreive the credentials {username, password} from
+        // the callback handler
+        Callback[] callbacks = new Callback[2];
+        callbacks[0] = new NameCallback("username");
+        callbacks[1] = new PasswordCallback("password", false);
+        try {
+            callbackHandler.handle(callbacks);
+            credentials_username = ((NameCallback)callbacks[0]).getName();
+            credentials_password = new String(((PasswordCallback)callbacks[1]).
+                    getPassword());
+        } catch (Exception e) {
+            throw new LoginException(e.toString());
+        }
+
+        System.out.println("TestSampleLoginModule::login: credentials username = " +
+                credentials_username);
+        System.out.println("TestSampleLoginModule::login: credentials password = " +
+                credentials_password);
+        System.out.println("TestSampleLoginModule::login: authenticated username = " +
+                authenticated_username);
+        System.out.println("TestSampleLoginModule::login: authenticated password = " +
+                authenticated_password);
+
+        if (credentials_username.equals(authenticated_username) &&
+                credentials_password.equals(authenticated_password)) {
+            System.out.println("TestSampleLoginModule::login: " +
+                    "Authentication should succeed");
+            return true;
+        } else {
+            System.out.println("TestSampleLoginModule::login: " +
+                    "Authentication should reject");
+            throw new LoginException("TestSampleLoginModule throws EXCEPTION");
+        }
+    }
+
+    public boolean commit() throws LoginException {
+        return true;
+    }
+
+    public boolean abort() throws LoginException {
+        return true;
+    }
+
+    public boolean logout() throws LoginException {
+        return true;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/security/Utils.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,424 @@
+/*
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Properties;
+import java.util.StringTokenizer;
+import java.lang.reflect.Method;
+import javax.management.remote.JMXConnectorServerMBean;
+
+// utility class for MXBean* tests coming from JMX Tonga test suite
+class Utils {
+
+    private static final String SERVER_SIDE_NAME = "-server";
+    private static final String CLIENT_SIDE_NAME = "-client";
+
+    // DEBUG is printed depending on the DEBUG and DEBUG_LEVEL JAVA property
+    private static final String DEBUG_HEADER = "[debug] ";
+
+    // DEBUG levels
+    private static int selectedDebugLevel = 0;
+    static final int DEBUG_STANDARD = 1;
+    static final int DEBUG_VERBOSE = 2;  // Mainly used for stress tests
+    static final int DEBUG_ALL = DEBUG_STANDARD | DEBUG_VERBOSE;
+
+    static void parseDebugProperties() {
+        int level = 0;
+        Properties p = System.getProperties();
+
+        // get selected levels
+        if (p.getProperty("DEBUG_STANDARD") != null) {
+            level |= DEBUG_STANDARD;
+        }
+
+        if (p.getProperty("DEBUG_VERBOSE") != null) {
+            level |= DEBUG_VERBOSE;
+        }
+
+        if (p.getProperty("DEBUG_ALL") != null) {
+            level |= DEBUG_ALL;
+        }
+
+        selectedDebugLevel = level;
+    }
+
+    /**
+     * Reproduces the original parsing and collection of test parameters
+     * from the DTonga JMX test suite.
+     *
+     * Collects passed args and returns them in a map(argname, value) structure,
+     * which will be then propagated as necessary to various called methods.
+     */
+    static Map<String, Object> parseParameters(String args[])
+    throws Exception {
+        Utils.debug(DEBUG_STANDARD, "TestRoot::parseParameters: Start");
+        HashMap<String, Object> map = new HashMap<>();
+
+        for ( int i = 0; i < args.length; i++ ) {
+            if ( args[i].trim().startsWith("-") ) {
+                if ((i+1) < args.length && !args[i+1].startsWith("-") ) {
+                    Utils.debug(DEBUG_STANDARD,
+                        "TestRoot::parseParameters: added in map = " +
+                        args[i] +
+                        " with value " +
+                        args[i+1]) ;
+                    map.put(args[i].trim(), args[i+1].trim()) ;
+                } else if ((i+1) < args.length && args[i+1].startsWith("-") ||
+                           (i+1) == args.length ) {
+                    Utils.debug(DEBUG_STANDARD,
+                            "TestRoot::parseParameters: added in map = " +
+                            args[i] +
+                            " with null value") ;
+                    map.put(args[i].trim(), null) ;
+                } else {
+                    System.out.println(
+                        "TestRoot::parseParameters: (WARNING) not added in map = " +
+                        args[i]) ;
+                }
+            }
+        }
+
+        Utils.debug(DEBUG_STANDARD, "TestRoot::parseParameters: Done") ;
+        return map ;
+    }
+
+    // Parse server parameters and put them in passed serverMap
+    static int parseServerParameters(String args[],
+                                     String serverSideName,
+                                     Map<String, Object> serverMap )
+    throws Exception {
+        Utils.debug(Utils.DEBUG_STANDARD,
+            serverSideName + "::parseServerParameters: Start");
+
+        int nextIndex = 0;
+        boolean seenServerFlag = false;
+
+        for ( int i = 0; i < args.length; i++ ) {
+            // Case of reaching "-server" flag parameter
+            if (args[i].equals(SERVER_SIDE_NAME)) {
+                if (!seenServerFlag) {
+                    seenServerFlag = true;
+                    continue;
+                } else {
+                    // Already parsing server params, invalid params list
+                    Utils.debug(Utils.DEBUG_STANDARD,
+                        serverSideName + "::parseParameters: Invalid " +
+                        args[i] + " parameter detected in " +
+                        SERVER_SIDE_NAME + " parameters list");
+                    nextIndex = -1;
+                    throw new RuntimeException("Invalid Parameter list");
+                }
+            }
+
+            // Case of reaching "-client" flag parameter
+            if (args[i].equals(CLIENT_SIDE_NAME)) {
+                // While parsing server parameters, then parsing is done.
+                Utils.debug(Utils.DEBUG_STANDARD,
+                    serverSideName + "::parseServerParameters: Parsing of " +
+                    SERVER_SIDE_NAME + " parameters done.");
+                return i;
+            }
+
+            i = parseParamAtIndex(args, i, serverMap);
+            nextIndex = i;
+        }
+
+        Utils.debug(Utils.DEBUG_STANDARD,
+            serverSideName + "::parseServerParameters: Parsing of parameters done");
+
+        return nextIndex;
+    }
+
+    // Parse client parameters and put them in passed clientMap
+    static void parseClientParameters(String args[],
+                                      String clientSideName,
+                                      Map<String, Object> clientMap )
+    throws Exception {
+
+        Utils.debug(Utils.DEBUG_STANDARD,
+            clientSideName + "::parseClientParameters: Start");
+
+        boolean seenClientFlag = false;
+
+        for ( int i = 0; i < args.length; i++ ) {
+            // Case of reaching "-client" flag parameter
+            if (args[i].equals(CLIENT_SIDE_NAME)) {
+                if (!seenClientFlag) {
+                    seenClientFlag = true;
+                    continue;
+                } else {
+                    // Already parsing client params, invalid params list
+                    Utils.debug(Utils.DEBUG_STANDARD,
+                        clientSideName + "::parseClientParameters: Invalid " +
+                        CLIENT_SIDE_NAME + " parameter detected in " +
+                        CLIENT_SIDE_NAME + " parameters list.");
+                    throw new RuntimeException("Invalid parameter in " +
+                        clientSideName + " parameter list");
+                }
+            }
+
+            // Case of reaching "-server" flag parameter
+            if (args[i].equals(SERVER_SIDE_NAME)) {
+                // While parsing client parameters, invalid parameter list.
+                Utils.debug(Utils.DEBUG_STANDARD,
+                    clientSideName + "::parseClientParameters: Invalid " +
+                    SERVER_SIDE_NAME + " parameter inside " +
+                    CLIENT_SIDE_NAME + " parameters list.");
+                throw new RuntimeException("Invalid parameter in " +
+                    clientSideName + " parameter list");
+            }
+
+            i = parseParamAtIndex(args, i, clientMap);
+        }
+
+        Utils.debug(Utils.DEBUG_STANDARD,
+            clientSideName + "::parseClientParameters: Parsing of parameters done.");
+    }
+
+    // Add param found at index to passed map
+    // We only accept either "-param value" or "-param" form.
+    // The "value" form is invalid but just ignored.
+    private static int parseParamAtIndex(String args[],
+                                         int index,
+                                         Map<String, Object> map) {
+
+        if (args[index].trim().startsWith("-") ) {
+            // Case of a "-param value" form
+            if ((index+1) < args.length && !args[index+1].startsWith("-") ) {
+                Utils.debug(Utils.DEBUG_STANDARD,
+                    "TestRoot::parseParamAtIndex: added in map = "
+                    + args[index]
+                    + " with value "
+                    + args[index+1]) ;
+                // adding ("param", value) to the passed map
+                map.put(args[index].trim(), args[index+1].trim()) ;
+                // value should not be parsed a second time
+                return index+1;
+            }
+            // Case of a "-param" form (flag parameter)
+            else if (((index+1) < args.length && args[index+1].startsWith("-")) ||
+                     (index+1) == args.length ) {
+                Utils.debug(Utils.DEBUG_STANDARD,
+                    "TestRoot::parseParamAtIndex: added in map = "
+                    + args[index]
+                    + " with null value") ;
+                // adding ("param", null) to passed map
+                map.put(args[index].trim(), null) ;
+            }
+        } else {
+            // Unsupported "value" alone parameter
+            Utils.debug(Utils.DEBUG_STANDARD,
+                "TestRoot::parseParamAtIndex: invalid " +
+                " value-alone \"" + args[index] + "\" parameter." +
+                " Parameter ignored.");
+        }
+
+        return index;
+    }
+
+    /**
+     * This method is to be used in all tests to print anything
+     * that is temporary.
+     * Printing is done only when debug is activated by the property DEBUG.
+     * Printing depends also on the DEBUG_LEVEL property.
+     * Here it encapsulates a System.out.println.
+     */
+    static void debug(int level, String line) {
+        if ((selectedDebugLevel & level) != 0) {
+            System.out.println(DEBUG_HEADER + line);
+        }
+    }
+
+    /**
+     * Do print stack trace when withStack is true.
+     * Does try to call getTargetException() and getTargetError() then
+     * print embedded stacks in the case of an Exception wrapping
+     * another Exception or an Error. Recurse until no more wrapping
+     * is found.
+     */
+    static void printThrowable(Throwable theThro, boolean withStack) {
+        try {
+            if (withStack) {
+                theThro.printStackTrace(System.out);
+            }
+            if (theThro instanceof Exception) {
+                Exception t = (Exception) theThro;
+                Method target = null;
+                String blank = " ";
+                try {
+                    target = t.getClass().getMethod("getTargetException",
+                            (java.lang.Class<?>[]) null);
+                } catch (Exception ee) {
+                // OK: getTargetException method could be there or not
+                }
+                System.out.println(blank + t.getClass() + "==>" + t.getMessage());
+                while (target != null) {
+                    try {
+                        t = (Exception) target.invoke(t,
+                                (java.lang.Object[]) null);
+                    } catch (Exception ee) {
+                        t = null;
+                    }
+                    try {
+                        if (t != null) {
+                            blank = blank + "  ";
+                            System.out.println(blank + t.getClass() + "==>" +
+                                    t.getMessage());
+                            try {
+                                target =
+                                        t.getClass().getMethod("getTargetException",
+                                        (java.lang.Class<?>[]) null);
+                            } catch (Exception ee) {
+                            // OK: getTargetException method could be there or not                            }
+                            }
+                        } else {
+                            target = null;
+                        }
+                    } catch (Exception ee) {
+                        target = null;
+                    }
+                }
+
+                // We may have exceptions wrapping an Error then it is
+                // getTargetError that is likely to be called
+                try {
+                    target = ((Exception) theThro).getClass().getMethod("getTargetError",
+                            (java.lang.Class<?>[]) null);
+                } catch (Exception ee) {
+                // OK: getTargetError method could be there or not
+                }
+                Throwable err = theThro;
+                while (target != null) {
+                    try {
+                        err = (Error) target.invoke(err,
+                                (java.lang.Object[]) null);
+                    } catch (Exception ee) {
+                        err = null;
+                    }
+                    try {
+                        if (err != null) {
+                            blank = blank + "  ";
+                            System.out.println(blank + err.getClass() + "==>" +
+                                    err.getMessage());
+                            if (withStack) {
+                                err.printStackTrace(System.out);
+                            }
+                            try {
+                                target = err.getClass().getMethod("getTargetError",
+                                        (java.lang.Class<?>[]) null);
+                            } catch (Exception ee) {
+                            // OK: getTargetError method could be there or not
+                            }
+                        } else {
+                            target = null;
+                        }
+                    } catch (Exception ee) {
+                        target = null;
+                    }
+                }
+            } else {
+                System.out.println("Throwable is : " + theThro);
+            }
+        } catch (Throwable x) {
+            System.out.println("Exception : raised in printException : " + x);
+        }
+    }
+
+    /**
+     * Wait up to maxTimeInSeconds second(s) the given JMX connector server
+     * comes up (which means isActive returns true).
+     * If it fails to do so we throw a RunTime exception.
+     */
+    static void waitReady(JMXConnectorServerMBean server,
+                                 int maxTimeInSeconds) throws Exception {
+        int elapsed = 0;
+
+        while (!server.isActive() && elapsed < maxTimeInSeconds) {
+            Thread.sleep(1000);
+            elapsed++;
+        }
+
+        if (server.isActive()) {
+            String message = "Utils::waitReady: JMX connector server came up";
+            if ( elapsed == 0) {
+                message += " immediately";
+            } else {
+                message += " after " + elapsed + " seconds";
+            }
+            message += " [" + server.getAddress() + "]";
+            Utils.debug(DEBUG_STANDARD, message);
+        } else {
+            String message = "Utils::waitReady: (ERROR) JMX connector" +
+                    " server didn't come up after " + elapsed + " seconds [" +
+                    server.getAddress() + "]";
+            System.out.println(message);
+            throw new RuntimeException(message);
+        }
+    }
+
+    /**
+     * This method is used to compare the specified Throwable and possibly
+     * the derived causes to the specified String argument.
+     * The expected String argument format is :
+     *      throwable_1;throwable_2;...;throwable_N
+     * where throwable_i can be :
+     *      - either a throwable class name
+     *      - or the "*" character meaning several unknown throwable class names
+     *      This character must be followed by a throwable class name
+     */
+    static boolean compareThrowable(
+            Throwable t,
+            String expectedThrowable) {
+
+        // First parse the expectedThrowable String
+        StringTokenizer tokenizer = new StringTokenizer(expectedThrowable, ";");
+        String token = null;
+
+        try {
+            while (tokenizer.hasMoreTokens()) {
+                token = tokenizer.nextToken();
+                if (!token.equals("*")) {
+                    if (!Class.forName(token).isInstance(t)) {
+                        return false;
+                    }
+                } else {
+                    token = tokenizer.nextToken();
+                    while (!Class.forName(token).isInstance(t)) {
+                        t = t.getCause();
+                        if (t == null) {
+                            return false;
+                        }
+                    }
+                }
+                t = t.getCause();
+            }
+        } catch (ClassNotFoundException cnfe) {
+            String msg = "Expected throwable class(es) " + expectedThrowable +
+                " cannot be located";
+            System.out.println(msg);
+            throw new IllegalArgumentException(msg);
+        }
+        return true;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/security/access.properties	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,11 @@
+# Access control file for SQE tests.
+
+# Default username
+SQE_username readwrite create Simple
+
+# Functional authorization tests
+username1 readwrite create Simple
+username2 readonly
+username3 readonly
+username4 readwrite create Simple
+username5 readwrite create Simple
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/security/java.policy.authorization	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,98 @@
+// Standard extensions get all permissions by default
+
+grant codeBase "file:${java.home}/lib/ext/*" {
+	permission java.security.AllPermission;
+};
+
+// default permissions granted to all domains
+grant { 
+	// Allows any thread to stop itself using the java.lang.Thread.stop()
+	// method that takes no argument.
+	// Note that this permission is granted by default only to remain
+	// backwards compatible.
+	// It is strongly recommended that you either remove this permission
+	// from this policy file or further restrict it to code sources
+	// that you specify, because Thread.stop() is potentially unsafe.
+	// See "http://java.sun.com/notes" for more information.
+	permission java.lang.RuntimePermission "stopThread";
+
+	// allows anyone to listen on un-privileged ports
+	permission java.net.SocketPermission "localhost:1024-", "listen";
+
+	// "standard" properies that can be read by anyone
+
+	permission java.util.PropertyPermission "java.version", "read";
+	permission java.util.PropertyPermission "java.vendor", "read";
+	permission java.util.PropertyPermission "java.vendor.url", "read";
+	permission java.util.PropertyPermission "java.class.version", "read";
+	permission java.util.PropertyPermission "os.name", "read";
+	permission java.util.PropertyPermission "os.version", "read";
+	permission java.util.PropertyPermission "os.arch", "read";
+	permission java.util.PropertyPermission "file.separator", "read";
+	permission java.util.PropertyPermission "path.separator", "read";
+	permission java.util.PropertyPermission "line.separator", "read";
+
+	permission java.util.PropertyPermission "java.specification.version", "read";
+	permission java.util.PropertyPermission "java.specification.vendor", "read";
+	permission java.util.PropertyPermission "java.specification.name", "read";
+
+	permission java.util.PropertyPermission "java.vm.specification.version", "read";
+	permission java.util.PropertyPermission "java.vm.specification.vendor", "read";
+	permission java.util.PropertyPermission "java.vm.specification.name", "read";
+	permission java.util.PropertyPermission "java.vm.version", "read";
+	permission java.util.PropertyPermission "java.vm.vendor", "read";
+	permission java.util.PropertyPermission "java.vm.name", "read";
+
+       permission java.io.FilePermission "*","read,write";
+
+};
+
+grant codeBase "file:/-" {
+	permission java.security.AllPermission;
+       permission java.io.FilePermission "*","read,write";
+};
+
+grant principal javax.management.remote.JMXPrincipal "SQE_username" {
+    permission javax.management.MBeanServerPermission "*";
+    permission javax.management.MBeanPermission "Simple", "instantiate";
+    permission javax.management.MBeanPermission "Simple", "registerMBean";
+};
+
+grant principal javax.management.remote.JMXPrincipal "username1" {
+    //
+    // JMXPrincipals "username1" has all permissions.
+    //
+    permission java.security.AllPermission;
+};
+
+grant principal javax.management.remote.JMXPrincipal "username2" {
+    //
+    // JMXPrincipals "username2" has all permissions.
+    //
+    permission java.security.AllPermission;
+};
+
+grant principal javax.management.remote.JMXPrincipal "username3" {
+    //
+    // JMXPrincipals "username3" has some permissions.
+    //
+    permission javax.management.MBeanPermission "Simple", "instantiate";
+    permission javax.management.MBeanPermission "Simple", "registerMBean";
+    permission javax.management.MBeanPermission "Simple", "setAttribute";
+    permission javax.management.MBeanPermission "Simple", "invoke";
+};
+
+grant principal javax.management.remote.JMXPrincipal "username4" {
+    //
+    // JMXPrincipals "username4" has all permissions.
+    //
+    permission javax.management.MBeanPermission "Simple", "instantiate";
+    permission javax.management.MBeanPermission "Simple", "registerMBean";
+    permission javax.management.MBeanPermission "Simple", "invoke";
+};
+
+grant principal javax.management.remote.JMXPrincipal "username5" {
+    //
+    // JMXPrincipals "username5" has no permissions.
+    //
+};
Binary file jdk/test/javax/management/security/keystoreAgent has changed
Binary file jdk/test/javax/management/security/keystoreClient has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/security/login.config	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,8 @@
+PasswordFileAuthentication {
+    com.sun.jmx.remote.security.FileLoginModule required
+	passwordFile="${password.file}";
+};
+
+SampleLoginModule {
+    TestSampleLoginModule required;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/security/password.properties	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,12 @@
+# Password file for default SQE username.
+SQE_username SQE_password
+
+# Functional authorization tests
+username1 password1
+username2 password2
+username3 password3
+username4 password4
+username5 password5
+username6 password6
+
+usernameFileLoginModule passwordFileLoginModule
Binary file jdk/test/javax/management/security/truststoreAgent has changed
Binary file jdk/test/javax/management/security/truststoreClient has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/net/ssl/TLSv12/SignatureAlgorithms.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,592 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 8049321
+ * @summary Support SHA256WithDSA in JSSE
+ * @run main/othervm SignatureAlgorithms PKIX "SHA-224,SHA-256"
+ *                   TLS_DHE_DSS_WITH_AES_128_CBC_SHA
+ * @run main/othervm SignatureAlgorithms PKIX "SHA-1,SHA-224"
+ *                   TLS_DHE_DSS_WITH_AES_128_CBC_SHA
+ * @run main/othervm SignatureAlgorithms PKIX "SHA-1,SHA-256"
+ *                   TLS_DHE_DSS_WITH_AES_128_CBC_SHA
+ * @run main/othervm SignatureAlgorithms PKIX "SHA-224,SHA-256"
+ *                   TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
+ * @run main/othervm SignatureAlgorithms PKIX "SHA-1,SHA-224"
+ *                   TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
+ * @run main/othervm SignatureAlgorithms PKIX "SHA-1,SHA-256"
+ *                   TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
+ */
+
+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.X509Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.spec.*;
+import java.security.interfaces.*;
+
+public class SignatureAlgorithms {
+
+    /*
+     * =============================================================
+     * 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 (DSA) used in the test.
+    static String trustedCertStr =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIDYTCCAyGgAwIBAgIJAK8/gw6zg/DPMAkGByqGSM44BAMwOzELMAkGA1UEBhMC\n" +
+        "VVMxDTALBgNVBAoTBEphdmExHTAbBgNVBAsTFFN1bkpTU0UgVGVzdCBTZXJpdmNl\n" +
+        "MB4XDTE1MTIwMzEzNTIyNVoXDTM2MTExMjEzNTIyNVowOzELMAkGA1UEBhMCVVMx\n" +
+        "DTALBgNVBAoTBEphdmExHTAbBgNVBAsTFFN1bkpTU0UgVGVzdCBTZXJpdmNlMIIB\n" +
+        "uDCCASwGByqGSM44BAEwggEfAoGBAPH+b+GSMX6KS7jXDRevzc464DFG4X+uxu5V\n" +
+        "b3U4yhsU8A8cuH4gwin6L/IDkmZQ7N0zC0jRsiGVSMsFETTq10F39pH2eBfUv/hJ\n" +
+        "cLfBnIjBEtVqV/dExK88Hul2sZ4mQihQ4issPl7hsroS9EWYicnX0oNAqAB9PO5Y\n" +
+        "zKbfpL7TAhUA13WW48rln2UP/LaAgtnzKhqcNtMCgYEA3Rv0GirTbAaor8iURd82\n" +
+        "b5FlDTevOCTuq7ZIpfZVV30neS7cBYNet6m/3/4cfUlbbrqhbqIJ2I+I81drnN0Y\n" +
+        "lyN4KkuxEcB6OTwfWkIUj6rvPaCQrBH8Q213bDq3HHtYNaP8OoeQUyVXW+SEGADC\n" +
+        "J1+z8uqP3lIB6ltdgOiV/GQDgYUAAoGBAOXRppuJSGdt6AiZkb81P1DCUgIUlZFI\n" +
+        "J9GxWrjbbHDmGllMwPNhK6dU7LJKJJuYVPW+95rUGlSJEjRqSlHuyHkNb6e3e7qx\n" +
+        "tmx1/oIyq+oLult50hBS7uBvLLR0JbIKjBzzkudL8Rjze4G/Wq7KDM2T1JOP49tW\n" +
+        "eocCvaC8h8uQo4GtMIGqMB0GA1UdDgQWBBT17HcqLllsqnZzP+kElcGcBGmubjBr\n" +
+        "BgNVHSMEZDBigBT17HcqLllsqnZzP+kElcGcBGmubqE/pD0wOzELMAkGA1UEBhMC\n" +
+        "VVMxDTALBgNVBAoTBEphdmExHTAbBgNVBAsTFFN1bkpTU0UgVGVzdCBTZXJpdmNl\n" +
+        "ggkArz+DDrOD8M8wDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwCQYHKoZI\n" +
+        "zjgEAwMvADAsAhQ6Y1I6LtIEBMqNo8o6GIe4LLEJuwIUbVQUKi8tvtWyRoxm8AFV\n" +
+        "0axJYUU=\n" +
+        "-----END CERTIFICATE-----";
+
+    static String[] targetCertStr = {
+        // DSA-SHA1
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIDKTCCAumgAwIBAgIJAOy5c0b+8stFMAkGByqGSM44BAMwOzELMAkGA1UEBhMC\n" +
+        "VVMxDTALBgNVBAoTBEphdmExHTAbBgNVBAsTFFN1bkpTU0UgVGVzdCBTZXJpdmNl\n" +
+        "MB4XDTE1MTIwMzEzNTIyNVoXDTM1MDgyMDEzNTIyNVowTzELMAkGA1UEBhMCVVMx\n" +
+        "DTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0UgVGVzdCBTZXJpdmNlMRIw\n" +
+        "EAYDVQQDDAlsb2NhbGhvc3QwggG3MIIBLAYHKoZIzjgEATCCAR8CgYEA8f5v4ZIx\n" +
+        "fopLuNcNF6/NzjrgMUbhf67G7lVvdTjKGxTwDxy4fiDCKfov8gOSZlDs3TMLSNGy\n" +
+        "IZVIywURNOrXQXf2kfZ4F9S/+Elwt8GciMES1WpX90TErzwe6XaxniZCKFDiKyw+\n" +
+        "XuGyuhL0RZiJydfSg0CoAH087ljMpt+kvtMCFQDXdZbjyuWfZQ/8toCC2fMqGpw2\n" +
+        "0wKBgQDdG/QaKtNsBqivyJRF3zZvkWUNN684JO6rtkil9lVXfSd5LtwFg163qb/f\n" +
+        "/hx9SVtuuqFuognYj4jzV2uc3RiXI3gqS7ERwHo5PB9aQhSPqu89oJCsEfxDbXds\n" +
+        "Orcce1g1o/w6h5BTJVdb5IQYAMInX7Py6o/eUgHqW12A6JX8ZAOBhAACgYB+zYqn\n" +
+        "jJwG4GZpBIN/6qhzbp0flChsV+Trlu0SL0agAQzb6XdI/4JnO87Pgbxaxh3VNAj3\n" +
+        "3+Ghr1NLBuBfTKzJ4j9msWT3EpLupkMyNtXvBYM0iyMrll67lSjMdv++wLEw35Af\n" +
+        "/bzVcjGyA5Q0i0cuEzDmHTVfi0OydynbwSLxtKNjMGEwCwYDVR0PBAQDAgPoMB0G\n" +
+        "A1UdDgQWBBQXJI8AxM0qsYCbbkIMuI5zJ+nMEDAfBgNVHSMEGDAWgBT17HcqLlls\n" +
+        "qnZzP+kElcGcBGmubjASBgNVHREBAf8ECDAGhwR/AAABMAkGByqGSM44BAMDLwAw\n" +
+        "LAIUXgyJ0xll4FrZAKXi8bj7Kiz+SA4CFH9WCSZIBYA9lmJkiTgRS7iM/6IC\n" +
+        "-----END CERTIFICATE-----",
+
+        // DSA-SHA224
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIDLzCCAuugAwIBAgIJAOy5c0b+8stGMAsGCWCGSAFlAwQDATA7MQswCQYDVQQG\n" +
+        "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" +
+        "Y2UwHhcNMTUxMjAzMTU0NDM5WhcNMzUwODIwMTU0NDM5WjBPMQswCQYDVQQGEwJV\n" +
+        "UzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2Y2Ux\n" +
+        "EjAQBgNVBAMMCWxvY2FsaG9zdDCCAbcwggEsBgcqhkjOOAQBMIIBHwKBgQDx/m/h\n" +
+        "kjF+iku41w0Xr83OOuAxRuF/rsbuVW91OMobFPAPHLh+IMIp+i/yA5JmUOzdMwtI\n" +
+        "0bIhlUjLBRE06tdBd/aR9ngX1L/4SXC3wZyIwRLValf3RMSvPB7pdrGeJkIoUOIr\n" +
+        "LD5e4bK6EvRFmInJ19KDQKgAfTzuWMym36S+0wIVANd1luPK5Z9lD/y2gILZ8yoa\n" +
+        "nDbTAoGBAN0b9Boq02wGqK/IlEXfNm+RZQ03rzgk7qu2SKX2VVd9J3ku3AWDXrep\n" +
+        "v9/+HH1JW266oW6iCdiPiPNXa5zdGJcjeCpLsRHAejk8H1pCFI+q7z2gkKwR/ENt\n" +
+        "d2w6txx7WDWj/DqHkFMlV1vkhBgAwidfs/Lqj95SAepbXYDolfxkA4GEAAKBgA81\n" +
+        "CJKEv+pwiqYgxtw/9rkQ9748WP3mKrEC06kjUG+94/Z9dQloNFFfj6LiO1bymc5l\n" +
+        "6QIR8XCi4Po3N80K3+WxhBGFhY+RkVWTh43JV8epb41aH2qiWErarBwBGEh8LyGT\n" +
+        "i30db+Nkz2gfvyz9H/9T0jmYgfLEOlMCusali1qHo2MwYTALBgNVHQ8EBAMCA+gw\n" +
+        "HQYDVR0OBBYEFBqSP0S4+X+zOCTEnlp2hbAjV/W5MB8GA1UdIwQYMBaAFPXsdyou\n" +
+        "WWyqdnM/6QSVwZwEaa5uMBIGA1UdEQEB/wQIMAaHBH8AAAEwCwYJYIZIAWUDBAMB\n" +
+        "AzEAMC4CFQChiRaOnAnsCSJFwdpK22jSxU/mhQIVALgLbj/G39+1Ej8UuSWnEQyU\n" +
+        "4DA+\n" +
+        "-----END CERTIFICATE-----",
+
+        // DSA-SHA256
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIDLTCCAuugAwIBAgIJAOy5c0b+8stHMAsGCWCGSAFlAwQDAjA7MQswCQYDVQQG\n" +
+        "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" +
+        "Y2UwHhcNMTUxMjAzMTU0NjUxWhcNMzUwODIwMTU0NjUxWjBPMQswCQYDVQQGEwJV\n" +
+        "UzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2Y2Ux\n" +
+        "EjAQBgNVBAMMCWxvY2FsaG9zdDCCAbcwggEsBgcqhkjOOAQBMIIBHwKBgQDx/m/h\n" +
+        "kjF+iku41w0Xr83OOuAxRuF/rsbuVW91OMobFPAPHLh+IMIp+i/yA5JmUOzdMwtI\n" +
+        "0bIhlUjLBRE06tdBd/aR9ngX1L/4SXC3wZyIwRLValf3RMSvPB7pdrGeJkIoUOIr\n" +
+        "LD5e4bK6EvRFmInJ19KDQKgAfTzuWMym36S+0wIVANd1luPK5Z9lD/y2gILZ8yoa\n" +
+        "nDbTAoGBAN0b9Boq02wGqK/IlEXfNm+RZQ03rzgk7qu2SKX2VVd9J3ku3AWDXrep\n" +
+        "v9/+HH1JW266oW6iCdiPiPNXa5zdGJcjeCpLsRHAejk8H1pCFI+q7z2gkKwR/ENt\n" +
+        "d2w6txx7WDWj/DqHkFMlV1vkhBgAwidfs/Lqj95SAepbXYDolfxkA4GEAAKBgEF7\n" +
+        "2qiYxGrjX4KCOy0k5nK/RYlgLy4gYDChihQpiaa+fbA5JOBOxPWsh7rdtmJuDrEJ\n" +
+        "keacU223+DIhOKC49fa+EvhLNqo6U1oPn8n/yvBsvvnWkcynw5KfNzaLlaPmzugh\n" +
+        "v9xl/GhyZNAXc1QUcW3C+ceHVNrKnkfbTKZz5eRSo2MwYTALBgNVHQ8EBAMCA+gw\n" +
+        "HQYDVR0OBBYEFNMkPrt40oO9Dpy+bcbQdEvOlNlyMB8GA1UdIwQYMBaAFPXsdyou\n" +
+        "WWyqdnM/6QSVwZwEaa5uMBIGA1UdEQEB/wQIMAaHBH8AAAEwCwYJYIZIAWUDBAMC\n" +
+        "Ay8AMCwCFCvA2QiKSe/n+6GqSYQwgQ/zL5M9AhQfSiuWdMJKWpgPJKakvzhBUbMb\n" +
+        "vA==\n" +
+        "-----END CERTIFICATE-----"};
+
+    // Private key in the format of PKCS#8, key size is 1024 bits.
+    static String[] targetPrivateKey = {
+        // For cert DSA-SHA1
+        "MIIBSwIBADCCASwGByqGSM44BAEwggEfAoGBAPH+b+GSMX6KS7jXDRevzc464DFG\n" +
+        "4X+uxu5Vb3U4yhsU8A8cuH4gwin6L/IDkmZQ7N0zC0jRsiGVSMsFETTq10F39pH2\n" +
+        "eBfUv/hJcLfBnIjBEtVqV/dExK88Hul2sZ4mQihQ4issPl7hsroS9EWYicnX0oNA\n" +
+        "qAB9PO5YzKbfpL7TAhUA13WW48rln2UP/LaAgtnzKhqcNtMCgYEA3Rv0GirTbAao\n" +
+        "r8iURd82b5FlDTevOCTuq7ZIpfZVV30neS7cBYNet6m/3/4cfUlbbrqhbqIJ2I+I\n" +
+        "81drnN0YlyN4KkuxEcB6OTwfWkIUj6rvPaCQrBH8Q213bDq3HHtYNaP8OoeQUyVX\n" +
+        "W+SEGADCJ1+z8uqP3lIB6ltdgOiV/GQEFgIUOiB7J/lrFrNduQ8nDNTe8VspoAI=",
+
+        // For cert DSA-SHA224
+        "MIIBSwIBADCCASwGByqGSM44BAEwggEfAoGBAPH+b+GSMX6KS7jXDRevzc464DFG\n" +
+        "4X+uxu5Vb3U4yhsU8A8cuH4gwin6L/IDkmZQ7N0zC0jRsiGVSMsFETTq10F39pH2\n" +
+        "eBfUv/hJcLfBnIjBEtVqV/dExK88Hul2sZ4mQihQ4issPl7hsroS9EWYicnX0oNA\n" +
+        "qAB9PO5YzKbfpL7TAhUA13WW48rln2UP/LaAgtnzKhqcNtMCgYEA3Rv0GirTbAao\n" +
+        "r8iURd82b5FlDTevOCTuq7ZIpfZVV30neS7cBYNet6m/3/4cfUlbbrqhbqIJ2I+I\n" +
+        "81drnN0YlyN4KkuxEcB6OTwfWkIUj6rvPaCQrBH8Q213bDq3HHtYNaP8OoeQUyVX\n" +
+        "W+SEGADCJ1+z8uqP3lIB6ltdgOiV/GQEFgIUOj9F5mxWd9W1tiLSdsOAt8BUBzE=",
+
+        // For cert DSA-SHA256
+        "MIIBSwIBADCCASwGByqGSM44BAEwggEfAoGBAPH+b+GSMX6KS7jXDRevzc464DFG\n" +
+        "4X+uxu5Vb3U4yhsU8A8cuH4gwin6L/IDkmZQ7N0zC0jRsiGVSMsFETTq10F39pH2\n" +
+        "eBfUv/hJcLfBnIjBEtVqV/dExK88Hul2sZ4mQihQ4issPl7hsroS9EWYicnX0oNA\n" +
+        "qAB9PO5YzKbfpL7TAhUA13WW48rln2UP/LaAgtnzKhqcNtMCgYEA3Rv0GirTbAao\n" +
+        "r8iURd82b5FlDTevOCTuq7ZIpfZVV30neS7cBYNet6m/3/4cfUlbbrqhbqIJ2I+I\n" +
+        "81drnN0YlyN4KkuxEcB6OTwfWkIUj6rvPaCQrBH8Q213bDq3HHtYNaP8OoeQUyVX\n" +
+        "W+SEGADCJ1+z8uqP3lIB6ltdgOiV/GQEFgIUQ2WGgg+OO39Aujj0e4lM4pP4/9g="};
+
+
+    static char passphrase[] = "passphrase".toCharArray();
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile boolean serverReady = 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();
+        try (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()) {
+                sslSocket.setEnabledCipherSuites(
+                        sslSocket.getSupportedCipherSuites());
+                InputStream sslIS = sslSocket.getInputStream();
+                OutputStream sslOS = sslSocket.getOutputStream();
+
+                sslIS.read();
+                sslOS.write('A');
+                sslOS.flush();
+
+                dumpSignatureAlgorithms(sslSocket);
+            }
+        }
+    }
+
+    /*
+     * 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)) {
+
+            // enable TLSv1.2 only
+            sslSocket.setEnabledProtocols(new String[] {"TLSv1.2"});
+
+            // enable a block cipher
+            sslSocket.setEnabledCipherSuites(new String[] {cipherSuite});
+
+            InputStream sslIS = sslSocket.getInputStream();
+            OutputStream sslOS = sslSocket.getOutputStream();
+
+            sslOS.write('B');
+            sslOS.flush();
+            sslIS.read();
+
+            dumpSignatureAlgorithms(sslSocket);
+        }
+    }
+
+    static void dumpSignatureAlgorithms(SSLSocket sslSocket) throws Exception {
+
+        boolean isClient = sslSocket.getUseClientMode();
+        String mode = "[" + (isClient ? "Client" : "Server") + "]";
+        ExtendedSSLSession session =
+                (ExtendedSSLSession)sslSocket.getSession();
+        String[] signAlgs = session.getLocalSupportedSignatureAlgorithms();
+        System.out.println(
+                mode + " local supported signature algorithms: " +
+                Arrays.asList(signAlgs));
+
+        if (!isClient) {
+            signAlgs = session.getPeerSupportedSignatureAlgorithms();
+            System.out.println(
+                mode + " peer supported signature algorithms: " +
+                Arrays.asList(signAlgs));
+        } else {
+            Certificate[] serverCerts = session.getPeerCertificates();
+
+            // server should always send the authentication cert.
+            String sigAlg = ((X509Certificate)serverCerts[0]).getSigAlgName();
+            System.out.println(
+                mode + " the signature algorithm of server certificate: " +
+                sigAlg);
+            if (sigAlg.contains("SHA1")) {
+                if (disabledAlgorithms.contains("SHA-1")) {
+                    throw new Exception(
+                            "Not the expected server certificate. " +
+                            "SHA-1 should be disabled");
+                }
+            } else if (sigAlg.contains("SHA224")) {
+                if (disabledAlgorithms.contains("SHA-224")) {
+                    throw new Exception(
+                            "Not the expected server certificate. " +
+                            "SHA-224 should be disabled");
+                }
+            } else {    // SHA-256
+                if (disabledAlgorithms.contains("SHA-256")) {
+                    throw new Exception(
+                            "Not the expected server certificate. " +
+                            "SHA-256 should be disabled");
+                }
+            }
+        }
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+    private static String tmAlgorithm;          // trust manager
+    private static String disabledAlgorithms;   // disabled algorithms
+    private static String cipherSuite;          // cipher suite
+
+    private static void parseArguments(String[] args) {
+        tmAlgorithm = args[0];
+        disabledAlgorithms = args[1];
+        cipherSuite = args[2];
+    }
+
+    private static SSLContext generateSSLContext(String trustedCertStr,
+            String[] keyCertStrs, String[] keySpecStrs) 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("DSA Signer", trusedCert);
+        }
+
+        if (keyCertStrs != null && keyCertStrs.length != 0) {
+            for (int i = 0; i < keyCertStrs.length; i++) {
+                String keyCertStr = keyCertStrs[i];
+                String keySpecStr = keySpecStrs[i];
+
+                // generate the private key.
+                PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
+                                Base64.getMimeDecoder().decode(keySpecStr));
+                KeyFactory kf = KeyFactory.getInstance("DSA");
+                DSAPrivateKey priKey =
+                        (DSAPrivateKey)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("DSA Entry " + i, priKey, passphrase, chain);
+            }
+        }
+
+        // create SSL context
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm);
+        tmf.init(ks);
+
+        SSLContext ctx = SSLContext.getInstance("TLS");
+        if (keyCertStrs != null && keyCertStrs.length != 0) {
+            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 {
+        /*
+         * debug option
+         */
+        if (debug) {
+            System.setProperty("javax.net.debug", "all");
+        }
+
+        /*
+         * Get the customized arguments.
+         */
+        parseArguments(args);
+
+
+        /*
+         * Ignore testing on Windows if only SHA-224 is available.
+         */
+        if ((Security.getProvider("SunMSCAPI") != null) &&
+                (disabledAlgorithms.contains("SHA-1")) &&
+                (disabledAlgorithms.contains("SHA-256"))) {
+
+            System.out.println(
+                "Windows system does not support SHA-224 algorithms yet. " +
+                "Ignore the testing");
+
+            return;
+        }
+
+        /*
+         * Expose the target algorithms by diabling unexpected algorithms.
+         */
+        Security.setProperty(
+                "jdk.certpath.disabledAlgorithms", disabledAlgorithms);
+
+        /*
+         * Reset the security property to make sure that the algorithms
+         * and keys used in this test are not disabled by default.
+         */
+        Security.setProperty( "jdk.tls.disabledAlgorithms", "");
+
+        /*
+         * Start the tests.
+         */
+        new SignatureAlgorithms();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    SignatureAlgorithms() 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..." + e);
+                        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..." + e);
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            try {
+                doClientSide();
+            } catch (Exception e) {
+                clientException = e;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/print/attribute/Services_getDocFl.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import javax.print.DocFlavor;
+import javax.print.PrintService;
+import javax.print.PrintServiceLookup;
+import javax.print.attribute.HashPrintRequestAttributeSet;
+
+/*
+ * @test
+ * @bug 4901243 8040139
+ * @summary JPG, GIF, and PNG DocFlavors (URL) should be supported if Postscript is supported.
+ * @run main Services_getDocFl
+*/
+
+
+public class Services_getDocFl {
+    public static void main (String [] args) {
+
+        HashPrintRequestAttributeSet prSet = null;
+        boolean psSupported = false,
+            pngImagesSupported = false,
+            gifImagesSupported = false,
+            jpgImagesSupported = false;
+        String mimeType;
+
+        PrintService[] serv = PrintServiceLookup.lookupPrintServices(null, null);
+        if (serv.length==0) {
+            System.out.println("no PrintService  found");
+        } else {
+            System.out.println("number of Services "+serv.length);
+        }
+
+
+        for (int i = 0; i<serv.length ;i++) {
+            System.out.println("           PRINT SERVICE: "+ i+" "+serv[i]);
+            DocFlavor[] flavors = serv[i].getSupportedDocFlavors();
+            pngImagesSupported = false;
+            gifImagesSupported = false;
+            jpgImagesSupported = false;
+            for (int j=0; j<flavors.length; j++) {
+                System.out.println(flavors[j]);
+
+                if (flavors[j].equals(DocFlavor.URL.PNG)) {
+                    pngImagesSupported = true;
+                } else if (flavors[j].equals(DocFlavor.URL.GIF)) {
+                    gifImagesSupported = true;
+                } else if (flavors[j].equals(DocFlavor.URL.JPEG)) {
+                    jpgImagesSupported = true;
+                } else if (flavors[j].getMimeType().indexOf("postscript") != -1) {
+                    psSupported = true;
+                }
+            }
+
+            if (psSupported && !(pngImagesSupported && gifImagesSupported &&
+                jpgImagesSupported)) {
+
+                throw new RuntimeException("Error: URL image DocFlavors are not reported as supported");
+            }
+        }
+
+    }
+}
+
--- a/jdk/test/javax/sound/midi/MidiDeviceProvider/FakeInfo.java	Thu Dec 24 10:33:21 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,80 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-import java.util.Collection;
-import java.util.HashSet;
-
-import javax.sound.midi.MidiDevice;
-import javax.sound.midi.MidiDevice.Info;
-import javax.sound.midi.MidiSystem;
-import javax.sound.midi.MidiUnavailableException;
-import javax.sound.midi.spi.MidiDeviceProvider;
-
-import static java.util.ServiceLoader.load;
-
-/**
- * @test
- * @bug 8059743
- * @summary MidiDeviceProvider shouldn't returns incorrect results in case of
- *          some unknown MidiDevice.Info
- * @author Sergey Bylokhov
- */
-public final class FakeInfo {
-
-    private static final class Fake extends Info {
-
-        Fake() {
-            super("a", "b", "c", "d");
-        }
-    }
-
-    public static void main(final String[] args) {
-        final Info fake = new Fake();
-        // MidiSystem API
-        try {
-            MidiSystem.getMidiDevice(fake);
-            throw new RuntimeException("IllegalArgumentException expected");
-        } catch (final MidiUnavailableException e) {
-            throw new RuntimeException("IllegalArgumentException expected", e);
-        } catch (final IllegalArgumentException ignored) {
-            // expected
-        }
-        // MidiDeviceProvider API
-        final Collection<String> errors = new HashSet<>();
-        for (final MidiDeviceProvider mdp : load(MidiDeviceProvider.class)) {
-            try {
-                if (mdp.isDeviceSupported(fake)) {
-                    throw new RuntimeException("fake is supported");
-                }
-                final MidiDevice device = mdp.getDevice(fake);
-                System.err.println("MidiDevice: " + device);
-                throw new RuntimeException("IllegalArgumentException expected");
-            } catch (final IllegalArgumentException e) {
-                errors.add(e.getMessage());
-            }
-        }
-        if (errors.size() != 1) {
-            throw new RuntimeException("Wrong number of messages:" + errors);
-        }
-    }
-}
--- a/jdk/test/javax/sound/midi/MidiDeviceProvider/NullInfo.java	Thu Dec 24 10:33:21 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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.util.Collection;
-import java.util.HashSet;
-
-import javax.sound.midi.MidiDevice;
-import javax.sound.midi.MidiSystem;
-import javax.sound.midi.MidiUnavailableException;
-import javax.sound.midi.spi.MidiDeviceProvider;
-
-import static java.util.ServiceLoader.load;
-
-/**
- * @test
- * @bug 8058115
- * @summary MidiDeviceProvider shouldn't returns incorrect results or throw NPE
- *          in case of null MidiDevice.Info
- * @author Sergey Bylokhov
- */
-public final class NullInfo {
-
-    public static void main(final String[] args) {
-        // MidiSystem API
-        try {
-            MidiSystem.getMidiDevice(null);
-            throw new RuntimeException("IllegalArgumentException expected");
-        } catch (final MidiUnavailableException e) {
-            throw new RuntimeException("IllegalArgumentException expected", e);
-        } catch (final IllegalArgumentException ignored) {
-            // expected
-        }
-        // MidiDeviceProvider API
-        final Collection<String> errors = new HashSet<>();
-        for (final MidiDeviceProvider mdp : load(MidiDeviceProvider.class)) {
-            try {
-                if (mdp.isDeviceSupported(null)) {
-                    throw new RuntimeException("null is supported");
-                }
-                final MidiDevice device = mdp.getDevice(null);
-                System.err.println("MidiDevice: " + device);
-                throw new RuntimeException("IllegalArgumentException expected");
-            } catch (final IllegalArgumentException e) {
-                errors.add(e.getMessage());
-            }
-        }
-        if (errors.size() != 1) {
-            throw new RuntimeException("Wrong number of messages:" + errors);
-        }
-    }
-}
--- a/jdk/test/javax/sound/midi/MidiDeviceProvider/UnsupportedInfo.java	Thu Dec 24 10:33:21 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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 javax.sound.midi.MidiDevice;
-import javax.sound.midi.MidiSystem;
-import javax.sound.midi.spi.MidiDeviceProvider;
-
-import static java.util.ServiceLoader.load;
-
-/**
- * @test
- * @bug 8058115
- * @summary MidiDeviceProvider shouldn't returns incorrect results in case of
- *          unsupported MidiDevice.Info
- * @author Sergey Bylokhov
- */
-public final class UnsupportedInfo {
-
-    public static void main(final String[] args) {
-        final MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo();
-        for (final MidiDeviceProvider mdp : load(MidiDeviceProvider.class)) {
-            for (final MidiDevice.Info info : infos) {
-                if (mdp.isDeviceSupported(info)) {
-                    if (mdp.getDevice(info) == null) {
-                        throw new RuntimeException("MidiDevice is null");
-                    }
-                } else {
-                    try {
-                        mdp.getDevice(info);
-                        throw new RuntimeException(
-                                "IllegalArgumentException expected");
-                    } catch (final IllegalArgumentException ignored) {
-                        // expected
-                    }
-                }
-            }
-        }
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/sound/midi/spi/MidiDeviceProvider/ExpectedNPEOnNull.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.util.Objects;
+
+import javax.sound.midi.MidiDevice;
+import javax.sound.midi.MidiSystem;
+import javax.sound.midi.spi.MidiDeviceProvider;
+
+import static java.util.ServiceLoader.load;
+
+/**
+ * @test
+ * @bug 8143909
+ * @author Sergey Bylokhov
+ */
+public final class ExpectedNPEOnNull {
+
+    public static void main(final String[] args) throws Exception {
+        testMS();
+        for (final MidiDeviceProvider mdp : load(MidiDeviceProvider.class)) {
+            testMDP(mdp);
+        }
+        testMDP(customMDP);
+    }
+
+    /**
+     * Tests the part of MidiSystem API, which implemented via
+     * MidiDeviceProvider.
+     */
+    private static void testMS() throws Exception {
+        // MidiSystem#getMidiDevice(MidiDevice.Info)
+        try {
+            MidiSystem.getMidiDevice(null);
+            throw new RuntimeException("NPE is expected");
+        } catch (final NullPointerException ignored) {
+        }
+    }
+
+    /**
+     * Tests the MidiDeviceProvider API directly.
+     */
+    private static void testMDP(final MidiDeviceProvider mdp) throws Exception {
+        // MidiDeviceProvider#isDeviceSupported(Info)
+        try {
+            mdp.isDeviceSupported(null);
+            throw new RuntimeException("NPE is expected");
+        } catch (final NullPointerException ignored) {
+        }
+        // MidiDeviceProvider#getDevice(Info)
+        try {
+            mdp.getDevice(null);
+            throw new RuntimeException("NPE is expected");
+        } catch (final NullPointerException ignored) {
+        }
+    }
+
+    /**
+     * Tests some default implementation of MidiDeviceProvider API, using the
+     * custom {@code MidiDeviceProvider}, which support nothing.
+     */
+    static MidiDeviceProvider customMDP = new MidiDeviceProvider() {
+        @Override
+        public MidiDevice.Info[] getDeviceInfo() {
+            return new MidiDevice.Info[0];
+        }
+
+        @Override
+        public MidiDevice getDevice(MidiDevice.Info info) {
+            Objects.requireNonNull(info);
+            return null;
+        }
+    };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/sound/midi/spi/MidiDeviceProvider/FakeInfo.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.util.Collection;
+import java.util.HashSet;
+
+import javax.sound.midi.MidiDevice;
+import javax.sound.midi.MidiDevice.Info;
+import javax.sound.midi.MidiSystem;
+import javax.sound.midi.MidiUnavailableException;
+import javax.sound.midi.spi.MidiDeviceProvider;
+
+import static java.util.ServiceLoader.load;
+
+/**
+ * @test
+ * @bug 8059743
+ * @summary MidiDeviceProvider shouldn't returns incorrect results in case of
+ *          some unknown MidiDevice.Info
+ * @author Sergey Bylokhov
+ */
+public final class FakeInfo {
+
+    private static final class Fake extends Info {
+
+        Fake() {
+            super("a", "b", "c", "d");
+        }
+    }
+
+    public static void main(final String[] args) {
+        final Info fake = new Fake();
+        // MidiSystem API
+        try {
+            MidiSystem.getMidiDevice(fake);
+            throw new RuntimeException("IllegalArgumentException expected");
+        } catch (final MidiUnavailableException e) {
+            throw new RuntimeException("IllegalArgumentException expected", e);
+        } catch (final IllegalArgumentException ignored) {
+            // expected
+        }
+        // MidiDeviceProvider API
+        final Collection<String> errors = new HashSet<>();
+        for (final MidiDeviceProvider mdp : load(MidiDeviceProvider.class)) {
+            try {
+                if (mdp.isDeviceSupported(fake)) {
+                    throw new RuntimeException("fake is supported");
+                }
+                final MidiDevice device = mdp.getDevice(fake);
+                System.err.println("MidiDevice: " + device);
+                throw new RuntimeException("IllegalArgumentException expected");
+            } catch (final IllegalArgumentException e) {
+                errors.add(e.getMessage());
+            }
+        }
+        if (errors.size() != 1) {
+            throw new RuntimeException("Wrong number of messages:" + errors);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/sound/midi/spi/MidiDeviceProvider/UnsupportedInfo.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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 javax.sound.midi.MidiDevice;
+import javax.sound.midi.MidiSystem;
+import javax.sound.midi.spi.MidiDeviceProvider;
+
+import static java.util.ServiceLoader.load;
+
+/**
+ * @test
+ * @bug 8058115
+ * @summary MidiDeviceProvider shouldn't returns incorrect results in case of
+ *          unsupported MidiDevice.Info
+ * @author Sergey Bylokhov
+ */
+public final class UnsupportedInfo {
+
+    public static void main(final String[] args) {
+        final MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo();
+        for (final MidiDeviceProvider mdp : load(MidiDeviceProvider.class)) {
+            for (final MidiDevice.Info info : infos) {
+                if (mdp.isDeviceSupported(info)) {
+                    if (mdp.getDevice(info) == null) {
+                        throw new RuntimeException("MidiDevice is null");
+                    }
+                } else {
+                    try {
+                        mdp.getDevice(info);
+                        throw new RuntimeException(
+                                "IllegalArgumentException expected");
+                    } catch (final IllegalArgumentException ignored) {
+                        // expected
+                    }
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/sound/midi/spi/MidiFileReader/ExpectedNPEOnNull.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.File;
+import java.io.InputStream;
+import java.net.URL;
+
+import javax.sound.midi.MidiSystem;
+import javax.sound.midi.spi.MidiFileReader;
+
+import static java.util.ServiceLoader.load;
+
+/**
+ * @test
+ * @bug 8143909
+ * @author Sergey Bylokhov
+ */
+public final class ExpectedNPEOnNull {
+
+    public static void main(final String[] args) throws Exception {
+        testMS();
+        for (final MidiFileReader mfr : load(MidiFileReader.class)) {
+            testMFR(mfr);
+        }
+    }
+
+    /**
+     * Tests the part of MidiSystem API, which implemented via MidiFileReader.
+     */
+    private static void testMS() throws Exception {
+        // MidiSystem#getMidiFileFormat(InputStream)
+        try {
+            MidiSystem.getMidiFileFormat((InputStream) null);
+            throw new RuntimeException("NPE is expected");
+        } catch (final NullPointerException ignored) {
+        }
+        // MidiSystem#getMidiFileFormat(URL)
+        try {
+            MidiSystem.getMidiFileFormat((URL) null);
+            throw new RuntimeException("NPE is expected");
+        } catch (final NullPointerException ignored) {
+        }
+        // MidiSystem#getMidiFileFormat(File)
+        try {
+            MidiSystem.getMidiFileFormat((File) null);
+            throw new RuntimeException("NPE is expected");
+        } catch (final NullPointerException ignored) {
+        }
+        // MidiSystem#getSequence(InputStream)
+        try {
+            MidiSystem.getSequence((InputStream) null);
+            throw new RuntimeException("NPE is expected");
+        } catch (final NullPointerException ignored) {
+        }
+        // MidiSystem#getSequence(URL)
+        try {
+            MidiSystem.getSequence((URL) null);
+            throw new RuntimeException("NPE is expected");
+        } catch (final NullPointerException ignored) {
+        }
+        // MidiSystem#getSequence(File)
+        try {
+            MidiSystem.getSequence((File) null);
+            throw new RuntimeException("NPE is expected");
+        } catch (final NullPointerException ignored) {
+        }
+    }
+
+    /**
+     * Tests the MidiFileReader API directly.
+     */
+    private static void testMFR(final MidiFileReader mfr) throws Exception {
+        // MidiFileReader#getMidiFileFormat(InputStream)
+        try {
+            mfr.getMidiFileFormat((InputStream) null);
+            throw new RuntimeException("NPE is expected");
+        } catch (final NullPointerException ignored) {
+        }
+        // MidiFileReader#getMidiFileFormat(URL)
+        try {
+            mfr.getMidiFileFormat((URL) null);
+            throw new RuntimeException("NPE is expected");
+        } catch (final NullPointerException ignored) {
+        }
+        // MidiFileReader#getMidiFileFormat(File)
+        try {
+            mfr.getMidiFileFormat((File) null);
+            throw new RuntimeException("NPE is expected");
+        } catch (final NullPointerException ignored) {
+        }
+        // MidiFileReader#getSequence(InputStream)
+        try {
+            mfr.getSequence((InputStream) null);
+            throw new RuntimeException("NPE is expected");
+        } catch (final NullPointerException ignored) {
+        }
+        // MidiFileReader#getSequence(URL)
+        try {
+            mfr.getSequence((URL) null);
+            throw new RuntimeException("NPE is expected");
+        } catch (final NullPointerException ignored) {
+        }
+        // MidiFileReader#getSequence(File)
+        try {
+            mfr.getSequence((File) null);
+            throw new RuntimeException("NPE is expected");
+        } catch (final NullPointerException ignored) {
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/sound/midi/spi/MidiFileWriter/ExpectedNPEOnNull.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.File;
+import java.io.OutputStream;
+import java.util.Objects;
+
+import javax.sound.midi.MidiSystem;
+import javax.sound.midi.Sequence;
+import javax.sound.midi.spi.MidiFileWriter;
+
+import static java.util.ServiceLoader.load;
+
+/**
+ * @test
+ * @bug 8143909
+ * @author Sergey Bylokhov
+ */
+public final class ExpectedNPEOnNull {
+
+    public static void main(final String[] args) throws Exception {
+        testMS();
+        for (final MidiFileWriter mfw : load(MidiFileWriter.class)) {
+            testMFW(mfw);
+        }
+        testMFW(customMFW);
+    }
+
+    /**
+     * Tests the part of MidiSystem API, which implemented via MidiFileWriter.
+     */
+    private static void testMS() throws Exception {
+        // MidiSystem#getMidiFileTypes(Sequence)
+        try {
+            MidiSystem.getMidiFileTypes(null);
+            throw new RuntimeException("NPE is expected");
+        } catch (final NullPointerException ignored) {
+        }
+
+        // MidiSystem#isFileTypeSupported(int, Sequence)
+        for (final int type : MidiSystem.getMidiFileTypes()) {
+            try {
+                MidiSystem.isFileTypeSupported(type, null);
+                throw new RuntimeException("NPE is expected");
+            } catch (final NullPointerException ignored) {
+            }
+        }
+        // MidiSystem#write(Sequence, int, OutputStream)
+        for (final int type : MidiSystem.getMidiFileTypes()) {
+            try {
+                MidiSystem.write(null, type, new NullOutputStream());
+                throw new RuntimeException("NPE is expected");
+            } catch (final NullPointerException ignored) {
+            }
+        }
+        for (final int type : MidiSystem.getMidiFileTypes()) {
+            try {
+                MidiSystem.write(new Sequence(0, 0), type, (OutputStream) null);
+                throw new RuntimeException("NPE is expected");
+            } catch (final NullPointerException ignored) {
+            }
+        }
+        for (final int type : MidiSystem.getMidiFileTypes()) {
+            try {
+                MidiSystem.write(null, type, (OutputStream) null);
+                throw new RuntimeException("NPE is expected");
+            } catch (final NullPointerException ignored) {
+            }
+        }
+        // MidiSystem#write(Sequence, int, File)
+        for (final int type : MidiSystem.getMidiFileTypes()) {
+            try {
+                MidiSystem.write(null, type, new File(""));
+                throw new RuntimeException("NPE is expected");
+            } catch (final NullPointerException ignored) {
+            }
+        }
+        for (final int type : MidiSystem.getMidiFileTypes()) {
+            try {
+                MidiSystem.write(new Sequence(0, 0), type, (File) null);
+                throw new RuntimeException("NPE is expected");
+            } catch (final NullPointerException ignored) {
+            }
+        }
+        for (final int type : MidiSystem.getMidiFileTypes()) {
+            try {
+                MidiSystem.write(null, type, (File) null);
+                throw new RuntimeException("NPE is expected");
+            } catch (final NullPointerException ignored) {
+            }
+        }
+    }
+
+    /**
+     * Tests the MidiFileWriter API directly.
+     */
+    private static void testMFW(final MidiFileWriter mfw) throws Exception {
+        // MidiFileWriter#getMidiFileTypes(Sequence)
+        try {
+            mfw.getMidiFileTypes(null);
+            throw new RuntimeException("NPE is expected");
+        } catch (final NullPointerException ignored) {
+        }
+        // MidiFileWriter#isFileTypeSupported(int, Sequence)
+        for (final int type : MidiSystem.getMidiFileTypes()) {
+            try {
+                mfw.isFileTypeSupported(type, null);
+                throw new RuntimeException("NPE is expected");
+            } catch (final NullPointerException ignored) {
+            }
+        }
+        // MidiFileWriter#write(Sequence, int, OutputStream)
+        for (final int type : MidiSystem.getMidiFileTypes()) {
+            try {
+                mfw.write(null, type, new NullOutputStream());
+                throw new RuntimeException("NPE is expected");
+            } catch (final NullPointerException ignored) {
+            }
+        }
+        for (final int type : MidiSystem.getMidiFileTypes()) {
+            try {
+                mfw.write(new Sequence(0, 0), type, (OutputStream) null);
+                throw new RuntimeException("NPE is expected");
+            } catch (final NullPointerException ignored) {
+            }
+        }
+        for (final int type : MidiSystem.getMidiFileTypes()) {
+            try {
+                mfw.write(null, type, (OutputStream) null);
+                throw new RuntimeException("NPE is expected");
+            } catch (final NullPointerException ignored) {
+            }
+        }
+        // MidiFileWriter#write(Sequence, int, File)
+        for (final int type : MidiSystem.getMidiFileTypes()) {
+            try {
+                mfw.write(null, type, new File(""));
+                throw new RuntimeException("NPE is expected");
+            } catch (final NullPointerException ignored) {
+            }
+        }
+        for (final int type : MidiSystem.getMidiFileTypes()) {
+            try {
+                mfw.write(new Sequence(0, 0), type, (File) null);
+                throw new RuntimeException("NPE is expected");
+            } catch (final NullPointerException ignored) {
+            }
+        }
+        for (final int type : MidiSystem.getMidiFileTypes()) {
+            try {
+                mfw.write(null, type, (File) null);
+                throw new RuntimeException("NPE is expected");
+            } catch (final NullPointerException ignored) {
+            }
+        }
+    }
+    /**
+     * Tests some default implementation of MidiFileWriter API, using the custom
+     * {@code MidiFileWriter}, which support nothing.
+     */
+    static MidiFileWriter customMFW = new MidiFileWriter() {
+        @Override
+        public int[] getMidiFileTypes() {
+            return new int[0];
+        }
+
+        @Override
+        public int[] getMidiFileTypes(Sequence sequence) {
+            Objects.requireNonNull(sequence);
+            return new int[0];
+        }
+
+        @Override
+        public int write(Sequence in, int fileType, OutputStream out) {
+            Objects.requireNonNull(in);
+            Objects.requireNonNull(out);
+            return 0;
+        }
+
+        @Override
+        public int write(Sequence in, int fileType, File out) {
+            Objects.requireNonNull(in);
+            Objects.requireNonNull(out);
+            return 0;
+        }
+    };
+
+    private static final class NullOutputStream extends OutputStream {
+
+        @Override
+        public void write(final int b) {
+            //do nothing
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/sound/midi/spi/SoundbankReader/ExpectedNPEOnNull.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.File;
+import java.io.InputStream;
+import java.net.URL;
+
+import javax.sound.midi.MidiSystem;
+import javax.sound.midi.spi.SoundbankReader;
+
+import static java.util.ServiceLoader.load;
+
+/**
+ * @test
+ * @bug 8143909
+ * @author Sergey Bylokhov
+ */
+public final class ExpectedNPEOnNull {
+
+    public static void main(final String[] args) throws Exception {
+        testMS();
+        for (final SoundbankReader sbr : load(SoundbankReader.class)) {
+            testSBR(sbr);
+        }
+    }
+
+    /**
+     * Tests the part of MidiSystem API, which implemented via SoundbankReader.
+     */
+    private static void testMS() throws Exception {
+        // MidiSystem#getSoundbank(InputStream)
+        try {
+            MidiSystem.getSoundbank((InputStream) null);
+            throw new RuntimeException("NPE is expected");
+        } catch (final NullPointerException ignored) {
+        }
+        // MidiSystem#getSoundbank(URL)
+        try {
+            MidiSystem.getSoundbank((URL) null);
+            throw new RuntimeException("NPE is expected");
+        } catch (final NullPointerException ignored) {
+        }
+        // MidiSystem#getSoundbank(File)
+        try {
+            MidiSystem.getSoundbank((File) null);
+            throw new RuntimeException("NPE is expected");
+        } catch (final NullPointerException ignored) {
+        }
+    }
+
+    /**
+     * Tests the SoundbankReader API directly.
+     */
+    private static void testSBR(final SoundbankReader sbr) throws Exception {
+        // SoundbankReader#getSoundbank(InputStream)
+        try {
+            sbr.getSoundbank((InputStream) null);
+            throw new RuntimeException("NPE is expected");
+        } catch (final NullPointerException ignored) {
+        }
+        // SoundbankReader#getSoundbank(URL)
+        try {
+            sbr.getSoundbank((URL) null);
+            throw new RuntimeException("NPE is expected");
+        } catch (final NullPointerException ignored) {
+        }
+        // SoundbankReader#getSoundbank(File)
+        try {
+            sbr.getSoundbank((File) null);
+            throw new RuntimeException("NPE is expected");
+        } catch (final NullPointerException ignored) {
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/JFileChooser/8067660/FileChooserTest.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8067660
+ * @summary JFileChooser create new folder fails silently
+ * @requires (os.family == "windows")
+ * @run main/manual FileChooserTest
+ */
+import java.awt.Panel;
+import java.awt.TextArea;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javax.swing.SwingUtilities;
+
+public class FileChooserTest {
+
+    private static boolean theTestPassed;
+    private static boolean testGeneratedInterrupt;
+    private static Thread mainThread;
+    private static int sleepTime = 30000;
+    public static  JFileChooser fileChooser;
+
+    private static void init() throws Exception {
+
+        SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
+            public void run() {
+                String[] instructions
+                        = {
+                            "1) Create a folder with read only permissions",
+                            "2) Click on run test button.It will open a open dialog"
+                            + " Navigate to the newly created read only folder",
+                            "3) Click on the create new folder button in open dialog",
+                            "4) If an error message does not pops up"
+                            + "test failed otherwise passed.",
+                            "5) Pressing Pass/Fail button will mark test as "
+                            + "pass/fail and will shutdown JVM"};
+
+                Sysout.createDialogWithInstructions(instructions);
+                Sysout.printInstructions(instructions);
+            }
+        });
+    }
+
+    /**
+     * ***************************************************
+     * Standard Test Machinery Section DO NOT modify anything in this section --
+     * it's a standard chunk of code which has all of the synchronisation
+     * necessary for the test harness. By keeping it the same in all tests, it
+     * is easier to read and understand someone else's test, as well as insuring
+     * that all tests behave correctly with the test harness. There is a section
+     * following this for test-defined classes
+     */
+    public static void main(String args[]) throws Exception {
+
+        mainThread = Thread.currentThread();
+        try {
+            init();
+        } catch (Exception ex) {
+            return;
+        }
+        try {
+            mainThread.sleep(sleepTime);
+        } catch (InterruptedException ex) {
+            Sysout.dispose();
+            if (!theTestPassed && testGeneratedInterrupt) {
+                throw new RuntimeException("Test Failed");
+            }
+        }
+        if (!testGeneratedInterrupt) {
+            Sysout.dispose();
+            throw new RuntimeException("Test Failed");
+        }
+    }
+
+    public static synchronized void pass() {
+        theTestPassed = true;
+        testGeneratedInterrupt = true;
+        mainThread.interrupt();
+    }
+
+    public static synchronized void fail() {
+        theTestPassed = false;
+        testGeneratedInterrupt = true;
+        mainThread.interrupt();
+    }
+}
+
+/**
+ * This is part of the standard test machinery. It creates a dialog (with the
+ * instructions), and is the interface for sending text messages to the user. To
+ * print the instructions, send an array of strings to Sysout.createDialog
+ * WithInstructions method. Put one line of instructions per array entry. To
+ * display a message for the tester to see, simply call Sysout.println with the
+ * string to be displayed. This mimics System.out.println but works within the
+ * test harness as well as standalone.
+ */
+class Sysout {
+
+    private static TestDialog dialog;
+    private static JFrame frame;
+
+    public static void createDialogWithInstructions(String[] instructions) {
+        frame = new JFrame();
+        dialog = new TestDialog(frame, "Instructions");
+        dialog.printInstructions(instructions);
+        dialog.setVisible(true);
+        println("Any messages for the tester will display here.");
+    }
+
+    public static void printInstructions(String[] instructions) {
+        dialog.printInstructions(instructions);
+    }
+
+    public static void println(String messageIn) {
+        dialog.displayMessage(messageIn);
+    }
+
+    public static void dispose() {
+        Sysout.println("Shutting down the Java process..");
+        if(FileChooserTest.fileChooser != null) {
+            FileChooserTest.fileChooser.cancelSelection();
+        }
+        frame.dispose();
+        dialog.dispose();
+    }
+}
+
+/**
+ * This is part of the standard test machinery. It provides a place for the test
+ * instructions to be displayed, and a place for interactive messages to the
+ * user to be displayed. To have the test instructions displayed, see Sysout. To
+ * have a message to the user be displayed, see Sysout. Do not call anything in
+ * this dialog directly.
+ */
+class TestDialog extends JDialog {
+
+    private TextArea instructionsText;
+    private TextArea messageText;
+    private int maxStringLength = 80;
+    private Panel buttonP = new Panel();
+    private JButton run = new JButton("Run");
+    private JButton passB = new JButton("Pass");
+    private JButton failB = new JButton("Fail");
+
+    public TestDialog(JFrame frame, String name) {
+        super(frame, name);
+        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+        int scrollBoth = TextArea.SCROLLBARS_BOTH;
+        instructionsText = new TextArea("", 15, maxStringLength, scrollBoth);
+        add("North", instructionsText);
+
+        messageText = new TextArea("", 5, maxStringLength, scrollBoth);
+        add("Center", messageText);
+
+        buttonP.add("East", run);
+        buttonP.add("East", passB);
+        buttonP.add("West", failB);
+        passB.setEnabled(false);
+        failB.setEnabled(false);
+        add("South", buttonP);
+
+        run.addActionListener(new ActionListener() {
+
+            @Override
+            public void actionPerformed(ActionEvent ae) {
+                FileChooserTest.fileChooser = new JFileChooser();
+                FileChooserTest.fileChooser.showOpenDialog(null);
+                passB.setEnabled(true);
+                failB.setEnabled(true);
+            }
+        });
+
+        passB.addActionListener(new ActionListener() {
+
+            @Override
+            public void actionPerformed(ActionEvent ae) {
+                FileChooserTest.pass();
+            }
+        });
+
+        failB.addActionListener(new ActionListener() {
+
+            @Override
+            public void actionPerformed(ActionEvent ae) {
+                FileChooserTest.fail();
+            }
+        });
+        pack();
+
+        setVisible(true);
+    }
+
+    public void printInstructions(String[] instructions) {
+        instructionsText.setText("");
+
+        String printStr, remainingStr;
+        for (String instruction : instructions) {
+            remainingStr = instruction;
+            while (remainingStr.length() > 0) {
+                if (remainingStr.length() >= maxStringLength) {
+                    int posOfSpace = remainingStr.
+                            lastIndexOf(' ', maxStringLength - 1);
+
+                    if (posOfSpace <= 0) {
+                        posOfSpace = maxStringLength - 1;
+                    }
+
+                    printStr = remainingStr.substring(0, posOfSpace + 1);
+                    remainingStr = remainingStr.substring(posOfSpace + 1);
+                } else {
+                    printStr = remainingStr;
+                    remainingStr = "";
+                }
+                instructionsText.append(printStr + "\n");
+            }
+        }
+
+    }
+
+    public void displayMessage(String messageIn) {
+        messageText.append(messageIn + "\n");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/JMenuItem/8139169/ScreenMenuBarInputTwice.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 8139169
+ * @summary verifies if TextArea gets input twice due to Apple's Screen Menubar
+ * @requires (os.family=="mac")
+ * @library ../../regtesthelpers
+ * @build Util
+ * @run main ScreenMenuBarInputTwice
+ */
+import java.awt.BorderLayout;
+import java.awt.Point;
+import java.awt.Robot;
+import java.awt.event.ActionEvent;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import static java.awt.event.KeyEvent.VK_COMMA;
+import static java.awt.event.KeyEvent.VK_META;
+import static java.awt.event.KeyEvent.VK_SHIFT;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.KeyStroke;
+import javax.swing.SwingUtilities;
+import javax.swing.text.BadLocationException;
+
+public class ScreenMenuBarInputTwice {
+
+    public static final String TEST_STRING = "Check string";
+
+    private static Robot robot;
+    private static JFrame frame;
+    private static JPanel content;
+    private static JTextArea textArea;
+    private static JMenuBar menuBar;
+    private static JMenu menu;
+    private static JMenuItem menuItem;
+
+    public static void main(String[] args) throws Exception {
+        robot = new Robot();
+        createUIWithSeperateMenuBar();
+        robot.delay(2000);
+        shortcutTestCase();
+        robot.delay(2000);
+        cleanUp();
+        createUIWithIntegratedMenuBar();
+        robot.delay(2000);
+        menuTestCase();
+        robot.delay(2000);
+        cleanUp();
+    }
+
+    private static void createUIWithSeperateMenuBar() throws Exception {
+        SwingUtilities.invokeAndWait(new Runnable() {
+
+            @Override
+            public void run() {
+                System.setProperty(
+                        "com.apple.mrj.application.apple.menu.about.name",
+                        "A test frame");
+                System.setProperty("apple.laf.useScreenMenuBar", "true");
+                frame = new JFrame("Text input twice check");
+                content = new JPanel(new BorderLayout());
+                textArea = new JTextArea();
+                content.add(new JScrollPane(textArea,
+                        JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
+                        JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED),
+                        BorderLayout.CENTER);
+                menuBar = new JMenuBar();
+                frame.setJMenuBar(menuBar);
+                Action a = new AbstractAction("Insert some text") {
+                    @Override
+                    public void actionPerformed(ActionEvent arg0) {
+                        try {
+
+                            textArea.getDocument()
+                                    .insertString(0, TEST_STRING, null);
+                        } catch (BadLocationException e) {
+                            frame.dispose();
+                            throw new RuntimeException("Bad location: ", e);
+                        }
+                    }
+                };
+                KeyStroke keyStroke = KeyStroke.getKeyStroke(
+                        "meta shift COMMA");
+                a.putValue(Action.ACCELERATOR_KEY, keyStroke);
+                textArea.getInputMap().put(keyStroke, "myAction");
+                textArea.getActionMap().put("myAction", a);
+                menu = new JMenu("The Menu");
+                menuItem = new JMenuItem(a);
+                menuItem.setAccelerator((KeyStroke) a.getValue(
+                        Action.ACCELERATOR_KEY));
+                menu.add(menuItem);
+                menuBar.add(menu);
+                frame.getContentPane().add(content);
+                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+                frame.setLocationRelativeTo(null);
+                frame.setSize(500, 500);
+                frame.setVisible(true);
+                frame.toFront();
+            }
+        });
+    }
+
+    private static void createUIWithIntegratedMenuBar() throws Exception {
+        SwingUtilities.invokeAndWait(new Runnable() {
+
+            @Override
+            public void run() {
+                System.setProperty(
+                        "com.apple.mrj.application.apple.menu.about.name",
+                        "A test frame");
+                System.setProperty("apple.laf.useScreenMenuBar", "false");
+                frame = new JFrame("Text input twice check");
+                content = new JPanel(new BorderLayout());
+                textArea = new JTextArea();
+                content.add(new JScrollPane(textArea,
+                        JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
+                        JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED),
+                        BorderLayout.CENTER);
+                menuBar = new JMenuBar();
+                frame.setJMenuBar(menuBar);
+                Action a = new AbstractAction("Insert some text") {
+                    @Override
+                    public void actionPerformed(ActionEvent arg0) {
+                        try {
+
+                            textArea.getDocument()
+                                    .insertString(0, TEST_STRING, null);
+                        } catch (BadLocationException e) {
+                            frame.dispose();
+                            throw new RuntimeException("Bad location: ", e);
+                        }
+                    }
+                };
+                KeyStroke keyStroke = KeyStroke.getKeyStroke(
+                        "meta shift COMMA");
+                a.putValue(Action.ACCELERATOR_KEY, keyStroke);
+                textArea.getInputMap().put(keyStroke, "myAction");
+                textArea.getActionMap().put("myAction", a);
+                menu = new JMenu("The Menu");
+                menuItem = new JMenuItem(a);
+                menuItem.setAccelerator((KeyStroke) a.getValue(
+                        Action.ACCELERATOR_KEY));
+                menu.add(menuItem);
+                menuBar.add(menu);
+                frame.getContentPane().add(content);
+                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+                frame.setSize(500, 500);
+                frame.setLocationRelativeTo(null);
+                frame.setVisible(true);
+                frame.toFront();
+            }
+        });
+    }
+
+    private static void shortcutTestCase() throws Exception {
+        robot.keyPress(KeyEvent.VK_META);
+        robot.keyPress(KeyEvent.VK_SHIFT);
+        robot.keyPress(KeyEvent.VK_COMMA);
+        robot.keyRelease(VK_COMMA);
+        robot.keyRelease(VK_SHIFT);
+        robot.keyRelease(VK_META);
+        robot.delay(2000);
+        checkText(textArea.getText());
+    }
+
+    private static void menuTestCase() throws Exception {
+        Point mousePoint;
+        mousePoint = Util.getCenterPoint(menu);
+        robot.mouseMove(mousePoint.x, mousePoint.y);
+        robot.mousePress(InputEvent.BUTTON1_MASK);
+        robot.mouseRelease(InputEvent.BUTTON1_MASK);
+        robot.delay(2000);
+        mousePoint = Util.getCenterPoint(menuItem);
+        robot.mouseMove(mousePoint.x, mousePoint.y);
+        robot.delay(2000);
+        robot.mousePress(InputEvent.BUTTON1_MASK);
+        robot.mouseRelease(InputEvent.BUTTON1_MASK);
+        robot.delay(2000);
+        checkText(textArea.getText());
+    }
+
+    private static void checkText(String text) throws Exception {
+        SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
+            public void run() {
+                if (TEST_STRING.equals(text)) {
+                    textArea.setText("");
+                } else {
+                    frame.dispose();
+                    throw new RuntimeException("Failed. "
+                            + " Menu item shortcut invoked twice");
+                }
+            }
+        });
+    }
+
+    private static void cleanUp() throws Exception {
+        SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
+            public void run() {
+                frame.dispose();
+            }
+        });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/undo/UndoManager/AbstractDocumentUndoConcurrentTest.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+   @bug 8030702
+   @summary Deadlock between subclass of AbstractDocument and UndoManager
+   @author Semyon Sadetsky
+  */
+
+import javax.swing.text.PlainDocument;
+import javax.swing.text.StringContent;
+import javax.swing.undo.UndoManager;
+import java.text.DecimalFormat;
+import java.text.Format;
+import java.util.concurrent.CyclicBarrier;
+
+public class AbstractDocumentUndoConcurrentTest {
+    static  CyclicBarrier barrier = new CyclicBarrier(3);
+
+    private static PlainDocument doc1;
+    private static PlainDocument doc2;
+    private static Format format1 = new DecimalFormat("<Test1 0000>");
+    private static Format format2 = new DecimalFormat("<Test22 0000>");
+
+    public static void main(String[] args) throws Exception {
+        test();
+        System.out.println(doc1.getText(0, doc1.getLength()));
+        System.out.println(doc2.getText(0, doc2.getLength()));
+        System.out.println("ok");
+    }
+
+    private static void test() throws Exception {
+        doc1 = new PlainDocument(new StringContent());
+        final UndoManager undoManager = new UndoManager();
+
+        doc1.addUndoableEditListener(undoManager);
+        doc1.insertString(0, "<Test1 XXXX>", null);
+
+        doc2 = new PlainDocument(new StringContent());
+
+        doc2.addUndoableEditListener(undoManager);
+        doc2.insertString(0, "<Test22 XXXX>", null);
+
+        Thread t1 = new Thread("Thread doc1") {
+            @Override
+            public void run() {
+                try {
+                    barrier.await();
+                    for (int i = 0; i < 1000; i++) {
+                        doc1.insertString(0, format1.format(i), null);
+                        if(doc1.getLength() > 100) doc1.remove(0, 12);
+                    }
+
+                } catch (Exception e) {
+                    throw new RuntimeException(e);
+                }
+                System.out.println("t1 done");
+            }
+        };
+
+        Thread t2 = new Thread("Thread doc2") {
+            @Override
+            public void run() {
+                try {
+                    barrier.await();
+                    for (int i = 0; i < 1000; i++) {
+                        doc2.insertString(0, format2.format(i), null);
+                        if(doc2.getLength() > 100) doc2.remove(0, 13);
+                    }
+
+                } catch (Exception e) {
+                    throw new RuntimeException(e);
+                }
+                System.out.println("t2 done");
+            }
+        };
+
+        Thread t3 = new Thread("Undo/Redo Thread") {
+            @Override
+            public void run() {
+                try {
+                    barrier.await();
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+                for (int i = 0; i < 1000; i++) {
+                    undoManager.undoOrRedo();
+                    undoManager.undo();
+                }
+                System.out.println("t3 done");
+            }
+        };
+
+        t1.start();
+        t2.start();
+        t3.start();
+
+        t1.join();
+        t2.join();
+        t3.join();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/internal/math/FloatingDecimal/OldFDBigIntForTest.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,491 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact 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.math;
+
+/*
+ * A really, really simple bigint package
+ * tailored to the needs of floating base conversion.
+ */
+class OldFDBigIntForTest {
+    int nWords; // number of words used
+    int data[]; // value: data[0] is least significant
+
+
+    public OldFDBigIntForTest( int v ){
+        nWords = 1;
+        data = new int[1];
+        data[0] = v;
+    }
+
+    public OldFDBigIntForTest( long v ){
+        data = new int[2];
+        data[0] = (int)v;
+        data[1] = (int)(v>>>32);
+        nWords = (data[1]==0) ? 1 : 2;
+    }
+
+    public OldFDBigIntForTest( OldFDBigIntForTest other ){
+        data = new int[nWords = other.nWords];
+        System.arraycopy( other.data, 0, data, 0, nWords );
+    }
+
+    private OldFDBigIntForTest( int [] d, int n ){
+        data = d;
+        nWords = n;
+    }
+
+    public OldFDBigIntForTest( long seed, char digit[], int nd0, int nd ){
+        int n= (nd+8)/9;        // estimate size needed.
+        if ( n < 2 ) n = 2;
+        data = new int[n];      // allocate enough space
+        data[0] = (int)seed;    // starting value
+        data[1] = (int)(seed>>>32);
+        nWords = (data[1]==0) ? 1 : 2;
+        int i = nd0;
+        int limit = nd-5;       // slurp digits 5 at a time.
+        int v;
+        while ( i < limit ){
+            int ilim = i+5;
+            v = (int)digit[i++]-(int)'0';
+            while( i <ilim ){
+                v = 10*v + (int)digit[i++]-(int)'0';
+            }
+            multaddMe( 100000, v); // ... where 100000 is 10^5.
+        }
+        int factor = 1;
+        v = 0;
+        while ( i < nd ){
+            v = 10*v + (int)digit[i++]-(int)'0';
+            factor *= 10;
+        }
+        if ( factor != 1 ){
+            multaddMe( factor, v );
+        }
+    }
+
+    /*
+     * Left shift by c bits.
+     * Shifts this in place.
+     */
+    public void
+    lshiftMe( int c )throws IllegalArgumentException {
+        if ( c <= 0 ){
+            if ( c == 0 )
+                return; // silly.
+            else
+                throw new IllegalArgumentException("negative shift count");
+        }
+        int wordcount = c>>5;
+        int bitcount  = c & 0x1f;
+        int anticount = 32-bitcount;
+        int t[] = data;
+        int s[] = data;
+        if ( nWords+wordcount+1 > t.length ){
+            // reallocate.
+            t = new int[ nWords+wordcount+1 ];
+        }
+        int target = nWords+wordcount;
+        int src    = nWords-1;
+        if ( bitcount == 0 ){
+            // special hack, since an anticount of 32 won't go!
+            System.arraycopy( s, 0, t, wordcount, nWords );
+            target = wordcount-1;
+        } else {
+            t[target--] = s[src]>>>anticount;
+            while ( src >= 1 ){
+                t[target--] = (s[src]<<bitcount) | (s[--src]>>>anticount);
+            }
+            t[target--] = s[src]<<bitcount;
+        }
+        while( target >= 0 ){
+            t[target--] = 0;
+        }
+        data = t;
+        nWords += wordcount + 1;
+        // may have constructed high-order word of 0.
+        // if so, trim it
+        while ( nWords > 1 && data[nWords-1] == 0 )
+            nWords--;
+    }
+
+    /*
+     * normalize this number by shifting until
+     * the MSB of the number is at 0x08000000.
+     * This is in preparation for quoRemIteration, below.
+     * The idea is that, to make division easier, we want the
+     * divisor to be "normalized" -- usually this means shifting
+     * the MSB into the high words sign bit. But because we know that
+     * the quotient will be 0 < q < 10, we would like to arrange that
+     * the dividend not span up into another word of precision.
+     * (This needs to be explained more clearly!)
+     */
+    public int
+    normalizeMe() throws IllegalArgumentException {
+        int src;
+        int wordcount = 0;
+        int bitcount  = 0;
+        int v = 0;
+        for ( src= nWords-1 ; src >= 0 && (v=data[src]) == 0 ; src--){
+            wordcount += 1;
+        }
+        if ( src < 0 ){
+            // oops. Value is zero. Cannot normalize it!
+            throw new IllegalArgumentException("zero value");
+        }
+        /*
+         * In most cases, we assume that wordcount is zero. This only
+         * makes sense, as we try not to maintain any high-order
+         * words full of zeros. In fact, if there are zeros, we will
+         * simply SHORTEN our number at this point. Watch closely...
+         */
+        nWords -= wordcount;
+        /*
+         * Compute how far left we have to shift v s.t. its highest-
+         * order bit is in the right place. Then call lshiftMe to
+         * do the work.
+         */
+        if ( (v & 0xf0000000) != 0 ){
+            // will have to shift up into the next word.
+            // too bad.
+            for( bitcount = 32 ; (v & 0xf0000000) != 0 ; bitcount-- )
+                v >>>= 1;
+        } else {
+            while ( v <= 0x000fffff ){
+                // hack: byte-at-a-time shifting
+                v <<= 8;
+                bitcount += 8;
+            }
+            while ( v <= 0x07ffffff ){
+                v <<= 1;
+                bitcount += 1;
+            }
+        }
+        if ( bitcount != 0 )
+            lshiftMe( bitcount );
+        return bitcount;
+    }
+
+    /*
+     * Multiply a OldFDBigIntForTest by an int.
+     * Result is a new OldFDBigIntForTest.
+     */
+    public OldFDBigIntForTest
+    mult( int iv ) {
+        long v = iv;
+        int r[];
+        long p;
+
+        // guess adequate size of r.
+        r = new int[ ( v * ((long)data[nWords-1]&0xffffffffL) > 0xfffffffL ) ? nWords+1 : nWords ];
+        p = 0L;
+        for( int i=0; i < nWords; i++ ) {
+            p += v * ((long)data[i]&0xffffffffL);
+            r[i] = (int)p;
+            p >>>= 32;
+        }
+        if ( p == 0L){
+            return new OldFDBigIntForTest( r, nWords );
+        } else {
+            r[nWords] = (int)p;
+            return new OldFDBigIntForTest( r, nWords+1 );
+        }
+    }
+
+    /*
+     * Multiply a OldFDBigIntForTest by an int and add another int.
+     * Result is computed in place.
+     * Hope it fits!
+     */
+    public void
+    multaddMe( int iv, int addend ) {
+        long v = iv;
+        long p;
+
+        // unroll 0th iteration, doing addition.
+        p = v * ((long)data[0]&0xffffffffL) + ((long)addend&0xffffffffL);
+        data[0] = (int)p;
+        p >>>= 32;
+        for( int i=1; i < nWords; i++ ) {
+            p += v * ((long)data[i]&0xffffffffL);
+            data[i] = (int)p;
+            p >>>= 32;
+        }
+        if ( p != 0L){
+            data[nWords] = (int)p; // will fail noisily if illegal!
+            nWords++;
+        }
+    }
+
+    /*
+     * Multiply a OldFDBigIntForTest by another OldFDBigIntForTest.
+     * Result is a new OldFDBigIntForTest.
+     */
+    public OldFDBigIntForTest
+    mult( OldFDBigIntForTest other ){
+        // crudely guess adequate size for r
+        int r[] = new int[ nWords + other.nWords ];
+        int i;
+        // I think I am promised zeros...
+
+        for( i = 0; i < this.nWords; i++ ){
+            long v = (long)this.data[i] & 0xffffffffL; // UNSIGNED CONVERSION
+            long p = 0L;
+            int j;
+            for( j = 0; j < other.nWords; j++ ){
+                p += ((long)r[i+j]&0xffffffffL) + v*((long)other.data[j]&0xffffffffL); // UNSIGNED CONVERSIONS ALL 'ROUND.
+                r[i+j] = (int)p;
+                p >>>= 32;
+            }
+            r[i+j] = (int)p;
+        }
+        // compute how much of r we actually needed for all that.
+        for ( i = r.length-1; i> 0; i--)
+            if ( r[i] != 0 )
+                break;
+        return new OldFDBigIntForTest( r, i+1 );
+    }
+
+    /*
+     * Add one OldFDBigIntForTest to another. Return a OldFDBigIntForTest
+     */
+    public OldFDBigIntForTest
+    add( OldFDBigIntForTest other ){
+        int i;
+        int a[], b[];
+        int n, m;
+        long c = 0L;
+        // arrange such that a.nWords >= b.nWords;
+        // n = a.nWords, m = b.nWords
+        if ( this.nWords >= other.nWords ){
+            a = this.data;
+            n = this.nWords;
+            b = other.data;
+            m = other.nWords;
+        } else {
+            a = other.data;
+            n = other.nWords;
+            b = this.data;
+            m = this.nWords;
+        }
+        int r[] = new int[ n ];
+        for ( i = 0; i < n; i++ ){
+            c += (long)a[i] & 0xffffffffL;
+            if ( i < m ){
+                c += (long)b[i] & 0xffffffffL;
+            }
+            r[i] = (int) c;
+            c >>= 32; // signed shift.
+        }
+        if ( c != 0L ){
+            // oops -- carry out -- need longer result.
+            int s[] = new int[ r.length+1 ];
+            System.arraycopy( r, 0, s, 0, r.length );
+            s[i++] = (int)c;
+            return new OldFDBigIntForTest( s, i );
+        }
+        return new OldFDBigIntForTest( r, i );
+    }
+
+    /*
+     * Subtract one OldFDBigIntForTest from another. Return a OldFDBigIntForTest
+     * Assert that the result is positive.
+     */
+    public OldFDBigIntForTest
+    sub( OldFDBigIntForTest other ){
+        int r[] = new int[ this.nWords ];
+        int i;
+        int n = this.nWords;
+        int m = other.nWords;
+        int nzeros = 0;
+        long c = 0L;
+        for ( i = 0; i < n; i++ ){
+            c += (long)this.data[i] & 0xffffffffL;
+            if ( i < m ){
+                c -= (long)other.data[i] & 0xffffffffL;
+            }
+            if ( ( r[i] = (int) c ) == 0 )
+                nzeros++;
+            else
+                nzeros = 0;
+            c >>= 32; // signed shift
+        }
+        assert c == 0L : c; // borrow out of subtract
+        assert dataInRangeIsZero(i, m, other); // negative result of subtract
+        return new OldFDBigIntForTest( r, n-nzeros );
+    }
+
+    private static boolean dataInRangeIsZero(int i, int m, OldFDBigIntForTest other) {
+        while ( i < m )
+            if (other.data[i++] != 0)
+                return false;
+        return true;
+    }
+
+    /*
+     * Compare OldFDBigIntForTest with another OldFDBigIntForTest. Return an integer
+     * >0: this > other
+     *  0: this == other
+     * <0: this < other
+     */
+    public int
+    cmp( OldFDBigIntForTest other ){
+        int i;
+        if ( this.nWords > other.nWords ){
+            // if any of my high-order words is non-zero,
+            // then the answer is evident
+            int j = other.nWords-1;
+            for ( i = this.nWords-1; i > j ; i-- )
+                if ( this.data[i] != 0 ) return 1;
+        }else if ( this.nWords < other.nWords ){
+            // if any of other's high-order words is non-zero,
+            // then the answer is evident
+            int j = this.nWords-1;
+            for ( i = other.nWords-1; i > j ; i-- )
+                if ( other.data[i] != 0 ) return -1;
+        } else{
+            i = this.nWords-1;
+        }
+        for ( ; i > 0 ; i-- )
+            if ( this.data[i] != other.data[i] )
+                break;
+        // careful! want unsigned compare!
+        // use brute force here.
+        int a = this.data[i];
+        int b = other.data[i];
+        if ( a < 0 ){
+            // a is really big, unsigned
+            if ( b < 0 ){
+                return a-b; // both big, negative
+            } else {
+                return 1; // b not big, answer is obvious;
+            }
+        } else {
+            // a is not really big
+            if ( b < 0 ) {
+                // but b is really big
+                return -1;
+            } else {
+                return a - b;
+            }
+        }
+    }
+
+    /*
+     * Compute
+     * q = (int)( this / S )
+     * this = 10 * ( this mod S )
+     * Return q.
+     * This is the iteration step of digit development for output.
+     * We assume that S has been normalized, as above, and that
+     * "this" has been lshift'ed accordingly.
+     * Also assume, of course, that the result, q, can be expressed
+     * as an integer, 0 <= q < 10.
+     */
+    public int
+    quoRemIteration( OldFDBigIntForTest S )throws IllegalArgumentException {
+        // ensure that this and S have the same number of
+        // digits. If S is properly normalized and q < 10 then
+        // this must be so.
+        if ( nWords != S.nWords ){
+            throw new IllegalArgumentException("disparate values");
+        }
+        // estimate q the obvious way. We will usually be
+        // right. If not, then we're only off by a little and
+        // will re-add.
+        int n = nWords-1;
+        long q = ((long)data[n]&0xffffffffL) / (long)S.data[n];
+        long diff = 0L;
+        for ( int i = 0; i <= n ; i++ ){
+            diff += ((long)data[i]&0xffffffffL) -  q*((long)S.data[i]&0xffffffffL);
+            data[i] = (int)diff;
+            diff >>= 32; // N.B. SIGNED shift.
+        }
+        if ( diff != 0L ) {
+            // damn, damn, damn. q is too big.
+            // add S back in until this turns +. This should
+            // not be very many times!
+            long sum = 0L;
+            while ( sum ==  0L ){
+                sum = 0L;
+                for ( int i = 0; i <= n; i++ ){
+                    sum += ((long)data[i]&0xffffffffL) +  ((long)S.data[i]&0xffffffffL);
+                    data[i] = (int) sum;
+                    sum >>= 32; // Signed or unsigned, answer is 0 or 1
+                }
+                /*
+                 * Originally the following line read
+                 * "if ( sum !=0 && sum != -1 )"
+                 * but that would be wrong, because of the
+                 * treatment of the two values as entirely unsigned,
+                 * it would be impossible for a carry-out to be interpreted
+                 * as -1 -- it would have to be a single-bit carry-out, or
+                 * +1.
+                 */
+                assert sum == 0 || sum == 1 : sum; // carry out of division correction
+                q -= 1;
+            }
+        }
+        // finally, we can multiply this by 10.
+        // it cannot overflow, right, as the high-order word has
+        // at least 4 high-order zeros!
+        long p = 0L;
+        for ( int i = 0; i <= n; i++ ){
+            p += 10*((long)data[i]&0xffffffffL);
+            data[i] = (int)p;
+            p >>= 32; // SIGNED shift.
+        }
+        assert p == 0L : p; // Carry out of *10
+        return (int)q;
+    }
+
+    public long
+    longValue(){
+        // if this can be represented as a long, return the value
+        assert this.nWords > 0 : this.nWords; // longValue confused
+
+        if (this.nWords == 1)
+            return ((long)data[0]&0xffffffffL);
+
+        assert dataInRangeIsZero(2, this.nWords, this); // value too big
+        assert data[1] >= 0;  // value too big
+        return ((long)(data[1]) << 32) | ((long)data[0]&0xffffffffL);
+    }
+
+    public String
+    toString() {
+        StringBuffer r = new StringBuffer(30);
+        r.append('[');
+        int i = Math.min( nWords-1, data.length-1) ;
+        if ( nWords > data.length ){
+            r.append( "("+data.length+"<"+nWords+"!)" );
+        }
+        for( ; i> 0 ; i-- ){
+            r.append( Integer.toHexString( data[i] ) );
+            r.append(' ');
+        }
+        r.append( Integer.toHexString( data[0] ) );
+        r.append(']');
+        return new String( r );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/internal/math/FloatingDecimal/OldFloatingDecimalForTest.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,2434 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact 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.math;
+
+import java.util.regex.*;
+
+public class OldFloatingDecimalForTest{
+    boolean     isExceptional;
+    boolean     isNegative;
+    int         decExponent;
+    char        digits[];
+    int         nDigits;
+    int         bigIntExp;
+    int         bigIntNBits;
+    boolean     mustSetRoundDir = false;
+    boolean     fromHex = false;
+    int         roundDir = 0; // set by doubleValue
+
+    /*
+     * The fields below provides additional information about the result of
+     * the binary to decimal digits conversion done in dtoa() and roundup()
+     * methods. They are changed if needed by those two methods.
+     */
+
+    // True if the dtoa() binary to decimal conversion was exact.
+    boolean     exactDecimalConversion = false;
+
+    // True if the result of the binary to decimal conversion was rounded-up
+    // at the end of the conversion process, i.e. roundUp() method was called.
+    boolean     decimalDigitsRoundedUp = false;
+
+    private     OldFloatingDecimalForTest( boolean negSign, int decExponent, char []digits, int n,  boolean e )
+    {
+        isNegative = negSign;
+        isExceptional = e;
+        this.decExponent = decExponent;
+        this.digits = digits;
+        this.nDigits = n;
+    }
+
+    /*
+     * Constants of the implementation
+     * Most are IEEE-754 related.
+     * (There are more really boring constants at the end.)
+     */
+    static final long   signMask = 0x8000000000000000L;
+    static final long   expMask  = 0x7ff0000000000000L;
+    static final long   fractMask= ~(signMask|expMask);
+    static final int    expShift = 52;
+    static final int    expBias  = 1023;
+    static final long   fractHOB = ( 1L<<expShift ); // assumed High-Order bit
+    static final long   expOne   = ((long)expBias)<<expShift; // exponent of 1.0
+    static final int    maxSmallBinExp = 62;
+    static final int    minSmallBinExp = -( 63 / 3 );
+    static final int    maxDecimalDigits = 15;
+    static final int    maxDecimalExponent = 308;
+    static final int    minDecimalExponent = -324;
+    static final int    bigDecimalExponent = 324; // i.e. abs(minDecimalExponent)
+
+    static final long   highbyte = 0xff00000000000000L;
+    static final long   highbit  = 0x8000000000000000L;
+    static final long   lowbytes = ~highbyte;
+
+    static final int    singleSignMask =    0x80000000;
+    static final int    singleExpMask  =    0x7f800000;
+    static final int    singleFractMask =   ~(singleSignMask|singleExpMask);
+    static final int    singleExpShift  =   23;
+    static final int    singleFractHOB  =   1<<singleExpShift;
+    static final int    singleExpBias   =   127;
+    static final int    singleMaxDecimalDigits = 7;
+    static final int    singleMaxDecimalExponent = 38;
+    static final int    singleMinDecimalExponent = -45;
+
+    static final int    intDecimalDigits = 9;
+
+
+    /*
+     * count number of bits from high-order 1 bit to low-order 1 bit,
+     * inclusive.
+     */
+    private static int
+    countBits( long v ){
+        //
+        // the strategy is to shift until we get a non-zero sign bit
+        // then shift until we have no bits left, counting the difference.
+        // we do byte shifting as a hack. Hope it helps.
+        //
+        if ( v == 0L ) return 0;
+
+        while ( ( v & highbyte ) == 0L ){
+            v <<= 8;
+        }
+        while ( v > 0L ) { // i.e. while ((v&highbit) == 0L )
+            v <<= 1;
+        }
+
+        int n = 0;
+        while (( v & lowbytes ) != 0L ){
+            v <<= 8;
+            n += 8;
+        }
+        while ( v != 0L ){
+            v <<= 1;
+            n += 1;
+        }
+        return n;
+    }
+
+    /*
+     * Keep big powers of 5 handy for future reference.
+     */
+    private static OldFDBigIntForTest b5p[];
+
+    private static synchronized OldFDBigIntForTest
+    big5pow( int p ){
+        assert p >= 0 : p; // negative power of 5
+        if ( b5p == null ){
+            b5p = new OldFDBigIntForTest[ p+1 ];
+        }else if (b5p.length <= p ){
+            OldFDBigIntForTest t[] = new OldFDBigIntForTest[ p+1 ];
+            System.arraycopy( b5p, 0, t, 0, b5p.length );
+            b5p = t;
+        }
+        if ( b5p[p] != null )
+            return b5p[p];
+        else if ( p < small5pow.length )
+            return b5p[p] = new OldFDBigIntForTest( small5pow[p] );
+        else if ( p < long5pow.length )
+            return b5p[p] = new OldFDBigIntForTest( long5pow[p] );
+        else {
+            // construct the value.
+            // recursively.
+            int q, r;
+            // in order to compute 5^p,
+            // compute its square root, 5^(p/2) and square.
+            // or, let q = p / 2, r = p -q, then
+            // 5^p = 5^(q+r) = 5^q * 5^r
+            q = p >> 1;
+            r = p - q;
+            OldFDBigIntForTest bigq =  b5p[q];
+            if ( bigq == null )
+                bigq = big5pow ( q );
+            if ( r < small5pow.length ){
+                return (b5p[p] = bigq.mult( small5pow[r] ) );
+            }else{
+                OldFDBigIntForTest bigr = b5p[ r ];
+                if ( bigr == null )
+                    bigr = big5pow( r );
+                return (b5p[p] = bigq.mult( bigr ) );
+            }
+        }
+    }
+
+    //
+    // a common operation
+    //
+    private static OldFDBigIntForTest
+    multPow52( OldFDBigIntForTest v, int p5, int p2 ){
+        if ( p5 != 0 ){
+            if ( p5 < small5pow.length ){
+                v = v.mult( small5pow[p5] );
+            } else {
+                v = v.mult( big5pow( p5 ) );
+            }
+        }
+        if ( p2 != 0 ){
+            v.lshiftMe( p2 );
+        }
+        return v;
+    }
+
+    //
+    // another common operation
+    //
+    private static OldFDBigIntForTest
+    constructPow52( int p5, int p2 ){
+        OldFDBigIntForTest v = new OldFDBigIntForTest( big5pow( p5 ) );
+        if ( p2 != 0 ){
+            v.lshiftMe( p2 );
+        }
+        return v;
+    }
+
+    /*
+     * Make a floating double into a OldFDBigIntForTest.
+     * This could also be structured as a OldFDBigIntForTest
+     * constructor, but we'd have to build a lot of knowledge
+     * about floating-point representation into it, and we don't want to.
+     *
+     * AS A SIDE EFFECT, THIS METHOD WILL SET THE INSTANCE VARIABLES
+     * bigIntExp and bigIntNBits
+     *
+     */
+    private OldFDBigIntForTest
+    doubleToBigInt( double dval ){
+        long lbits = Double.doubleToLongBits( dval ) & ~signMask;
+        int binexp = (int)(lbits >>> expShift);
+        lbits &= fractMask;
+        if ( binexp > 0 ){
+            lbits |= fractHOB;
+        } else {
+            assert lbits != 0L : lbits; // doubleToBigInt(0.0)
+            binexp +=1;
+            while ( (lbits & fractHOB ) == 0L){
+                lbits <<= 1;
+                binexp -= 1;
+            }
+        }
+        binexp -= expBias;
+        int nbits = countBits( lbits );
+        /*
+         * We now know where the high-order 1 bit is,
+         * and we know how many there are.
+         */
+        int lowOrderZeros = expShift+1-nbits;
+        lbits >>>= lowOrderZeros;
+
+        bigIntExp = binexp+1-nbits;
+        bigIntNBits = nbits;
+        return new OldFDBigIntForTest( lbits );
+    }
+
+    /*
+     * Compute a number that is the ULP of the given value,
+     * for purposes of addition/subtraction. Generally easy.
+     * More difficult if subtracting and the argument
+     * is a normalized a power of 2, as the ULP changes at these points.
+     */
+    private static double ulp( double dval, boolean subtracting ){
+        long lbits = Double.doubleToLongBits( dval ) & ~signMask;
+        int binexp = (int)(lbits >>> expShift);
+        double ulpval;
+        if ( subtracting && ( binexp >= expShift ) && ((lbits&fractMask) == 0L) ){
+            // for subtraction from normalized, powers of 2,
+            // use next-smaller exponent
+            binexp -= 1;
+        }
+        if ( binexp > expShift ){
+            ulpval = Double.longBitsToDouble( ((long)(binexp-expShift))<<expShift );
+        } else if ( binexp == 0 ){
+            ulpval = Double.MIN_VALUE;
+        } else {
+            ulpval = Double.longBitsToDouble( 1L<<(binexp-1) );
+        }
+        if ( subtracting ) ulpval = - ulpval;
+
+        return ulpval;
+    }
+
+    /*
+     * Round a double to a float.
+     * In addition to the fraction bits of the double,
+     * look at the class instance variable roundDir,
+     * which should help us avoid double-rounding error.
+     * roundDir was set in hardValueOf if the estimate was
+     * close enough, but not exact. It tells us which direction
+     * of rounding is preferred.
+     */
+    float
+    stickyRound( double dval ){
+        long lbits = Double.doubleToLongBits( dval );
+        long binexp = lbits & expMask;
+        if ( binexp == 0L || binexp == expMask ){
+            // what we have here is special.
+            // don't worry, the right thing will happen.
+            return (float) dval;
+        }
+        lbits += (long)roundDir; // hack-o-matic.
+        return (float)Double.longBitsToDouble( lbits );
+    }
+
+
+    /*
+     * This is the easy subcase --
+     * all the significant bits, after scaling, are held in lvalue.
+     * negSign and decExponent tell us what processing and scaling
+     * has already been done. Exceptional cases have already been
+     * stripped out.
+     * In particular:
+     * lvalue is a finite number (not Inf, nor NaN)
+     * lvalue > 0L (not zero, nor negative).
+     *
+     * The only reason that we develop the digits here, rather than
+     * calling on Long.toString() is that we can do it a little faster,
+     * and besides want to treat trailing 0s specially. If Long.toString
+     * changes, we should re-evaluate this strategy!
+     */
+    private void
+    developLongDigits( int decExponent, long lvalue, long insignificant ){
+        char digits[];
+        int  ndigits;
+        int  digitno;
+        int  c;
+        //
+        // Discard non-significant low-order bits, while rounding,
+        // up to insignificant value.
+        int i;
+        for ( i = 0; insignificant >= 10L; i++ )
+            insignificant /= 10L;
+        if ( i != 0 ){
+            long pow10 = long5pow[i] << i; // 10^i == 5^i * 2^i;
+            long residue = lvalue % pow10;
+            lvalue /= pow10;
+            decExponent += i;
+            if ( residue >= (pow10>>1) ){
+                // round up based on the low-order bits we're discarding
+                lvalue++;
+            }
+        }
+        if ( lvalue <= Integer.MAX_VALUE ){
+            assert lvalue > 0L : lvalue; // lvalue <= 0
+            // even easier subcase!
+            // can do int arithmetic rather than long!
+            int  ivalue = (int)lvalue;
+            ndigits = 10;
+            digits = perThreadBuffer.get();
+            digitno = ndigits-1;
+            c = ivalue%10;
+            ivalue /= 10;
+            while ( c == 0 ){
+                decExponent++;
+                c = ivalue%10;
+                ivalue /= 10;
+            }
+            while ( ivalue != 0){
+                digits[digitno--] = (char)(c+'0');
+                decExponent++;
+                c = ivalue%10;
+                ivalue /= 10;
+            }
+            digits[digitno] = (char)(c+'0');
+        } else {
+            // same algorithm as above (same bugs, too )
+            // but using long arithmetic.
+            ndigits = 20;
+            digits = perThreadBuffer.get();
+            digitno = ndigits-1;
+            c = (int)(lvalue%10L);
+            lvalue /= 10L;
+            while ( c == 0 ){
+                decExponent++;
+                c = (int)(lvalue%10L);
+                lvalue /= 10L;
+            }
+            while ( lvalue != 0L ){
+                digits[digitno--] = (char)(c+'0');
+                decExponent++;
+                c = (int)(lvalue%10L);
+                lvalue /= 10;
+            }
+            digits[digitno] = (char)(c+'0');
+        }
+        char result [];
+        ndigits -= digitno;
+        result = new char[ ndigits ];
+        System.arraycopy( digits, digitno, result, 0, ndigits );
+        this.digits = result;
+        this.decExponent = decExponent+1;
+        this.nDigits = ndigits;
+    }
+
+    //
+    // add one to the least significant digit.
+    // in the unlikely event there is a carry out,
+    // deal with it.
+    // assert that this will only happen where there
+    // is only one digit, e.g. (float)1e-44 seems to do it.
+    //
+    private void
+    roundup(){
+        int i;
+        int q = digits[ i = (nDigits-1)];
+        if ( q == '9' ){
+            while ( q == '9' && i > 0 ){
+                digits[i] = '0';
+                q = digits[--i];
+            }
+            if ( q == '9' ){
+                // carryout! High-order 1, rest 0s, larger exp.
+                decExponent += 1;
+                digits[0] = '1';
+                return;
+            }
+            // else fall through.
+        }
+        digits[i] = (char)(q+1);
+        decimalDigitsRoundedUp = true;
+    }
+
+    public boolean digitsRoundedUp() {
+        return decimalDigitsRoundedUp;
+    }
+
+    /*
+     * FIRST IMPORTANT CONSTRUCTOR: DOUBLE
+     */
+    public OldFloatingDecimalForTest( double d )
+    {
+        long    dBits = Double.doubleToLongBits( d );
+        long    fractBits;
+        int     binExp;
+        int     nSignificantBits;
+
+        // discover and delete sign
+        if ( (dBits&signMask) != 0 ){
+            isNegative = true;
+            dBits ^= signMask;
+        } else {
+            isNegative = false;
+        }
+        // Begin to unpack
+        // Discover obvious special cases of NaN and Infinity.
+        binExp = (int)( (dBits&expMask) >> expShift );
+        fractBits = dBits&fractMask;
+        if ( binExp == (int)(expMask>>expShift) ) {
+            isExceptional = true;
+            if ( fractBits == 0L ){
+                digits =  infinity;
+            } else {
+                digits = notANumber;
+                isNegative = false; // NaN has no sign!
+            }
+            nDigits = digits.length;
+            return;
+        }
+        isExceptional = false;
+        // Finish unpacking
+        // Normalize denormalized numbers.
+        // Insert assumed high-order bit for normalized numbers.
+        // Subtract exponent bias.
+        if ( binExp == 0 ){
+            if ( fractBits == 0L ){
+                // not a denorm, just a 0!
+                decExponent = 0;
+                digits = zero;
+                nDigits = 1;
+                return;
+            }
+            while ( (fractBits&fractHOB) == 0L ){
+                fractBits <<= 1;
+                binExp -= 1;
+            }
+            nSignificantBits = expShift + binExp +1; // recall binExp is  - shift count.
+            binExp += 1;
+        } else {
+            fractBits |= fractHOB;
+            nSignificantBits = expShift+1;
+        }
+        binExp -= expBias;
+        // call the routine that actually does all the hard work.
+        dtoa( binExp, fractBits, nSignificantBits );
+    }
+
+    /*
+     * SECOND IMPORTANT CONSTRUCTOR: SINGLE
+     */
+    public OldFloatingDecimalForTest( float f )
+    {
+        int     fBits = Float.floatToIntBits( f );
+        int     fractBits;
+        int     binExp;
+        int     nSignificantBits;
+
+        // discover and delete sign
+        if ( (fBits&singleSignMask) != 0 ){
+            isNegative = true;
+            fBits ^= singleSignMask;
+        } else {
+            isNegative = false;
+        }
+        // Begin to unpack
+        // Discover obvious special cases of NaN and Infinity.
+        binExp = (fBits&singleExpMask) >> singleExpShift;
+        fractBits = fBits&singleFractMask;
+        if ( binExp == (singleExpMask>>singleExpShift) ) {
+            isExceptional = true;
+            if ( fractBits == 0L ){
+                digits =  infinity;
+            } else {
+                digits = notANumber;
+                isNegative = false; // NaN has no sign!
+            }
+            nDigits = digits.length;
+            return;
+        }
+        isExceptional = false;
+        // Finish unpacking
+        // Normalize denormalized numbers.
+        // Insert assumed high-order bit for normalized numbers.
+        // Subtract exponent bias.
+        if ( binExp == 0 ){
+            if ( fractBits == 0 ){
+                // not a denorm, just a 0!
+                decExponent = 0;
+                digits = zero;
+                nDigits = 1;
+                return;
+            }
+            while ( (fractBits&singleFractHOB) == 0 ){
+                fractBits <<= 1;
+                binExp -= 1;
+            }
+            nSignificantBits = singleExpShift + binExp +1; // recall binExp is  - shift count.
+            binExp += 1;
+        } else {
+            fractBits |= singleFractHOB;
+            nSignificantBits = singleExpShift+1;
+        }
+        binExp -= singleExpBias;
+        // call the routine that actually does all the hard work.
+        dtoa( binExp, ((long)fractBits)<<(expShift-singleExpShift), nSignificantBits );
+    }
+
+    private void
+    dtoa( int binExp, long fractBits, int nSignificantBits )
+    {
+        int     nFractBits; // number of significant bits of fractBits;
+        int     nTinyBits;  // number of these to the right of the point.
+        int     decExp;
+
+        // Examine number. Determine if it is an easy case,
+        // which we can do pretty trivially using float/long conversion,
+        // or whether we must do real work.
+        nFractBits = countBits( fractBits );
+        nTinyBits = Math.max( 0, nFractBits - binExp - 1 );
+        if ( binExp <= maxSmallBinExp && binExp >= minSmallBinExp ){
+            // Look more closely at the number to decide if,
+            // with scaling by 10^nTinyBits, the result will fit in
+            // a long.
+            if ( (nTinyBits < long5pow.length) && ((nFractBits + n5bits[nTinyBits]) < 64 ) ){
+                /*
+                 * We can do this:
+                 * take the fraction bits, which are normalized.
+                 * (a) nTinyBits == 0: Shift left or right appropriately
+                 *     to align the binary point at the extreme right, i.e.
+                 *     where a long int point is expected to be. The integer
+                 *     result is easily converted to a string.
+                 * (b) nTinyBits > 0: Shift right by expShift-nFractBits,
+                 *     which effectively converts to long and scales by
+                 *     2^nTinyBits. Then multiply by 5^nTinyBits to
+                 *     complete the scaling. We know this won't overflow
+                 *     because we just counted the number of bits necessary
+                 *     in the result. The integer you get from this can
+                 *     then be converted to a string pretty easily.
+                 */
+                long halfULP;
+                if ( nTinyBits == 0 ) {
+                    if ( binExp > nSignificantBits ){
+                        halfULP = 1L << ( binExp-nSignificantBits-1);
+                    } else {
+                        halfULP = 0L;
+                    }
+                    if ( binExp >= expShift ){
+                        fractBits <<= (binExp-expShift);
+                    } else {
+                        fractBits >>>= (expShift-binExp) ;
+                    }
+                    developLongDigits( 0, fractBits, halfULP );
+                    return;
+                }
+                /*
+                 * The following causes excess digits to be printed
+                 * out in the single-float case. Our manipulation of
+                 * halfULP here is apparently not correct. If we
+                 * better understand how this works, perhaps we can
+                 * use this special case again. But for the time being,
+                 * we do not.
+                 * else {
+                 *     fractBits >>>= expShift+1-nFractBits;
+                 *     fractBits *= long5pow[ nTinyBits ];
+                 *     halfULP = long5pow[ nTinyBits ] >> (1+nSignificantBits-nFractBits);
+                 *     developLongDigits( -nTinyBits, fractBits, halfULP );
+                 *     return;
+                 * }
+                 */
+            }
+        }
+        /*
+         * This is the hard case. We are going to compute large positive
+         * integers B and S and integer decExp, s.t.
+         *      d = ( B / S ) * 10^decExp
+         *      1 <= B / S < 10
+         * Obvious choices are:
+         *      decExp = floor( log10(d) )
+         *      B      = d * 2^nTinyBits * 10^max( 0, -decExp )
+         *      S      = 10^max( 0, decExp) * 2^nTinyBits
+         * (noting that nTinyBits has already been forced to non-negative)
+         * I am also going to compute a large positive integer
+         *      M      = (1/2^nSignificantBits) * 2^nTinyBits * 10^max( 0, -decExp )
+         * i.e. M is (1/2) of the ULP of d, scaled like B.
+         * When we iterate through dividing B/S and picking off the
+         * quotient bits, we will know when to stop when the remainder
+         * is <= M.
+         *
+         * We keep track of powers of 2 and powers of 5.
+         */
+
+        /*
+         * Estimate decimal exponent. (If it is small-ish,
+         * we could double-check.)
+         *
+         * First, scale the mantissa bits such that 1 <= d2 < 2.
+         * We are then going to estimate
+         *          log10(d2) ~=~  (d2-1.5)/1.5 + log(1.5)
+         * and so we can estimate
+         *      log10(d) ~=~ log10(d2) + binExp * log10(2)
+         * take the floor and call it decExp.
+         * FIXME -- use more precise constants here. It costs no more.
+         */
+        double d2 = Double.longBitsToDouble(
+            expOne | ( fractBits &~ fractHOB ) );
+        decExp = (int)Math.floor(
+            (d2-1.5D)*0.289529654D + 0.176091259 + (double)binExp * 0.301029995663981 );
+        int B2, B5; // powers of 2 and powers of 5, respectively, in B
+        int S2, S5; // powers of 2 and powers of 5, respectively, in S
+        int M2, M5; // powers of 2 and powers of 5, respectively, in M
+        int Bbits; // binary digits needed to represent B, approx.
+        int tenSbits; // binary digits needed to represent 10*S, approx.
+        OldFDBigIntForTest Sval, Bval, Mval;
+
+        B5 = Math.max( 0, -decExp );
+        B2 = B5 + nTinyBits + binExp;
+
+        S5 = Math.max( 0, decExp );
+        S2 = S5 + nTinyBits;
+
+        M5 = B5;
+        M2 = B2 - nSignificantBits;
+
+        /*
+         * the long integer fractBits contains the (nFractBits) interesting
+         * bits from the mantissa of d ( hidden 1 added if necessary) followed
+         * by (expShift+1-nFractBits) zeros. In the interest of compactness,
+         * I will shift out those zeros before turning fractBits into a
+         * OldFDBigIntForTest. The resulting whole number will be
+         *      d * 2^(nFractBits-1-binExp).
+         */
+        fractBits >>>= (expShift+1-nFractBits);
+        B2 -= nFractBits-1;
+        int common2factor = Math.min( B2, S2 );
+        B2 -= common2factor;
+        S2 -= common2factor;
+        M2 -= common2factor;
+
+        /*
+         * HACK!! For exact powers of two, the next smallest number
+         * is only half as far away as we think (because the meaning of
+         * ULP changes at power-of-two bounds) for this reason, we
+         * hack M2. Hope this works.
+         */
+        if ( nFractBits == 1 )
+            M2 -= 1;
+
+        if ( M2 < 0 ){
+            // oops.
+            // since we cannot scale M down far enough,
+            // we must scale the other values up.
+            B2 -= M2;
+            S2 -= M2;
+            M2 =  0;
+        }
+        /*
+         * Construct, Scale, iterate.
+         * Some day, we'll write a stopping test that takes
+         * account of the asymmetry of the spacing of floating-point
+         * numbers below perfect powers of 2
+         * 26 Sept 96 is not that day.
+         * So we use a symmetric test.
+         */
+        char digits[] = this.digits = new char[18];
+        int  ndigit = 0;
+        boolean low, high;
+        long lowDigitDifference;
+        int  q;
+
+        /*
+         * Detect the special cases where all the numbers we are about
+         * to compute will fit in int or long integers.
+         * In these cases, we will avoid doing OldFDBigIntForTest arithmetic.
+         * We use the same algorithms, except that we "normalize"
+         * our OldFDBigIntForTests before iterating. This is to make division easier,
+         * as it makes our fist guess (quotient of high-order words)
+         * more accurate!
+         *
+         * Some day, we'll write a stopping test that takes
+         * account of the asymmetry of the spacing of floating-point
+         * numbers below perfect powers of 2
+         * 26 Sept 96 is not that day.
+         * So we use a symmetric test.
+         */
+        Bbits = nFractBits + B2 + (( B5 < n5bits.length )? n5bits[B5] : ( B5*3 ));
+        tenSbits = S2+1 + (( (S5+1) < n5bits.length )? n5bits[(S5+1)] : ( (S5+1)*3 ));
+        if ( Bbits < 64 && tenSbits < 64){
+            if ( Bbits < 32 && tenSbits < 32){
+                // wa-hoo! They're all ints!
+                int b = ((int)fractBits * small5pow[B5] ) << B2;
+                int s = small5pow[S5] << S2;
+                int m = small5pow[M5] << M2;
+                int tens = s * 10;
+                /*
+                 * Unroll the first iteration. If our decExp estimate
+                 * was too high, our first quotient will be zero. In this
+                 * case, we discard it and decrement decExp.
+                 */
+                ndigit = 0;
+                q = b / s;
+                b = 10 * ( b % s );
+                m *= 10;
+                low  = (b <  m );
+                high = (b+m > tens );
+                assert q < 10 : q; // excessively large digit
+                if ( (q == 0) && ! high ){
+                    // oops. Usually ignore leading zero.
+                    decExp--;
+                } else {
+                    digits[ndigit++] = (char)('0' + q);
+                }
+                /*
+                 * HACK! Java spec sez that we always have at least
+                 * one digit after the . in either F- or E-form output.
+                 * Thus we will need more than one digit if we're using
+                 * E-form
+                 */
+                if ( decExp < -3 || decExp >= 8 ){
+                    high = low = false;
+                }
+                while( ! low && ! high ){
+                    q = b / s;
+                    b = 10 * ( b % s );
+                    m *= 10;
+                    assert q < 10 : q; // excessively large digit
+                    if ( m > 0L ){
+                        low  = (b <  m );
+                        high = (b+m > tens );
+                    } else {
+                        // hack -- m might overflow!
+                        // in this case, it is certainly > b,
+                        // which won't
+                        // and b+m > tens, too, since that has overflowed
+                        // either!
+                        low = true;
+                        high = true;
+                    }
+                    digits[ndigit++] = (char)('0' + q);
+                }
+                lowDigitDifference = (b<<1) - tens;
+                exactDecimalConversion  = (b == 0);
+            } else {
+                // still good! they're all longs!
+                long b = (fractBits * long5pow[B5] ) << B2;
+                long s = long5pow[S5] << S2;
+                long m = long5pow[M5] << M2;
+                long tens = s * 10L;
+                /*
+                 * Unroll the first iteration. If our decExp estimate
+                 * was too high, our first quotient will be zero. In this
+                 * case, we discard it and decrement decExp.
+                 */
+                ndigit = 0;
+                q = (int) ( b / s );
+                b = 10L * ( b % s );
+                m *= 10L;
+                low  = (b <  m );
+                high = (b+m > tens );
+                assert q < 10 : q; // excessively large digit
+                if ( (q == 0) && ! high ){
+                    // oops. Usually ignore leading zero.
+                    decExp--;
+                } else {
+                    digits[ndigit++] = (char)('0' + q);
+                }
+                /*
+                 * HACK! Java spec sez that we always have at least
+                 * one digit after the . in either F- or E-form output.
+                 * Thus we will need more than one digit if we're using
+                 * E-form
+                 */
+                if ( decExp < -3 || decExp >= 8 ){
+                    high = low = false;
+                }
+                while( ! low && ! high ){
+                    q = (int) ( b / s );
+                    b = 10 * ( b % s );
+                    m *= 10;
+                    assert q < 10 : q;  // excessively large digit
+                    if ( m > 0L ){
+                        low  = (b <  m );
+                        high = (b+m > tens );
+                    } else {
+                        // hack -- m might overflow!
+                        // in this case, it is certainly > b,
+                        // which won't
+                        // and b+m > tens, too, since that has overflowed
+                        // either!
+                        low = true;
+                        high = true;
+                    }
+                    digits[ndigit++] = (char)('0' + q);
+                }
+                lowDigitDifference = (b<<1) - tens;
+                exactDecimalConversion  = (b == 0);
+            }
+        } else {
+            OldFDBigIntForTest ZeroVal = new OldFDBigIntForTest(0);
+            OldFDBigIntForTest tenSval;
+            int  shiftBias;
+
+            /*
+             * We really must do OldFDBigIntForTest arithmetic.
+             * Fist, construct our OldFDBigIntForTest initial values.
+             */
+            Bval = multPow52( new OldFDBigIntForTest( fractBits  ), B5, B2 );
+            Sval = constructPow52( S5, S2 );
+            Mval = constructPow52( M5, M2 );
+
+
+            // normalize so that division works better
+            Bval.lshiftMe( shiftBias = Sval.normalizeMe() );
+            Mval.lshiftMe( shiftBias );
+            tenSval = Sval.mult( 10 );
+            /*
+             * Unroll the first iteration. If our decExp estimate
+             * was too high, our first quotient will be zero. In this
+             * case, we discard it and decrement decExp.
+             */
+            ndigit = 0;
+            q = Bval.quoRemIteration( Sval );
+            Mval = Mval.mult( 10 );
+            low  = (Bval.cmp( Mval ) < 0);
+            high = (Bval.add( Mval ).cmp( tenSval ) > 0 );
+            assert q < 10 : q; // excessively large digit
+            if ( (q == 0) && ! high ){
+                // oops. Usually ignore leading zero.
+                decExp--;
+            } else {
+                digits[ndigit++] = (char)('0' + q);
+            }
+            /*
+             * HACK! Java spec sez that we always have at least
+             * one digit after the . in either F- or E-form output.
+             * Thus we will need more than one digit if we're using
+             * E-form
+             */
+            if ( decExp < -3 || decExp >= 8 ){
+                high = low = false;
+            }
+            while( ! low && ! high ){
+                q = Bval.quoRemIteration( Sval );
+                Mval = Mval.mult( 10 );
+                assert q < 10 : q;  // excessively large digit
+                low  = (Bval.cmp( Mval ) < 0);
+                high = (Bval.add( Mval ).cmp( tenSval ) > 0 );
+                digits[ndigit++] = (char)('0' + q);
+            }
+            if ( high && low ){
+                Bval.lshiftMe(1);
+                lowDigitDifference = Bval.cmp(tenSval);
+            } else {
+                lowDigitDifference = 0L; // this here only for flow analysis!
+            }
+            exactDecimalConversion  = (Bval.cmp( ZeroVal ) == 0);
+        }
+        this.decExponent = decExp+1;
+        this.digits = digits;
+        this.nDigits = ndigit;
+        /*
+         * Last digit gets rounded based on stopping condition.
+         */
+        if ( high ){
+            if ( low ){
+                if ( lowDigitDifference == 0L ){
+                    // it's a tie!
+                    // choose based on which digits we like.
+                    if ( (digits[nDigits-1]&1) != 0 ) roundup();
+                } else if ( lowDigitDifference > 0 ){
+                    roundup();
+                }
+            } else {
+                roundup();
+            }
+        }
+    }
+
+    public boolean decimalDigitsExact() {
+        return exactDecimalConversion;
+    }
+
+    public String
+    toString(){
+        // most brain-dead version
+        StringBuffer result = new StringBuffer( nDigits+8 );
+        if ( isNegative ){ result.append( '-' ); }
+        if ( isExceptional ){
+            result.append( digits, 0, nDigits );
+        } else {
+            result.append( "0.");
+            result.append( digits, 0, nDigits );
+            result.append('e');
+            result.append( decExponent );
+        }
+        return new String(result);
+    }
+
+    public String toJavaFormatString() {
+        char result[] = perThreadBuffer.get();
+        int i = getChars(result);
+        return new String(result, 0, i);
+    }
+
+    private int getChars(char[] result) {
+        assert nDigits <= 19 : nDigits; // generous bound on size of nDigits
+        int i = 0;
+        if (isNegative) { result[0] = '-'; i = 1; }
+        if (isExceptional) {
+            System.arraycopy(digits, 0, result, i, nDigits);
+            i += nDigits;
+        } else {
+            if (decExponent > 0 && decExponent < 8) {
+                // print digits.digits.
+                int charLength = Math.min(nDigits, decExponent);
+                System.arraycopy(digits, 0, result, i, charLength);
+                i += charLength;
+                if (charLength < decExponent) {
+                    charLength = decExponent-charLength;
+                    System.arraycopy(zero, 0, result, i, charLength);
+                    i += charLength;
+                    result[i++] = '.';
+                    result[i++] = '0';
+                } else {
+                    result[i++] = '.';
+                    if (charLength < nDigits) {
+                        int t = nDigits - charLength;
+                        System.arraycopy(digits, charLength, result, i, t);
+                        i += t;
+                    } else {
+                        result[i++] = '0';
+                    }
+                }
+            } else if (decExponent <=0 && decExponent > -3) {
+                result[i++] = '0';
+                result[i++] = '.';
+                if (decExponent != 0) {
+                    System.arraycopy(zero, 0, result, i, -decExponent);
+                    i -= decExponent;
+                }
+                System.arraycopy(digits, 0, result, i, nDigits);
+                i += nDigits;
+            } else {
+                result[i++] = digits[0];
+                result[i++] = '.';
+                if (nDigits > 1) {
+                    System.arraycopy(digits, 1, result, i, nDigits-1);
+                    i += nDigits-1;
+                } else {
+                    result[i++] = '0';
+                }
+                result[i++] = 'E';
+                int e;
+                if (decExponent <= 0) {
+                    result[i++] = '-';
+                    e = -decExponent+1;
+                } else {
+                    e = decExponent-1;
+                }
+                // decExponent has 1, 2, or 3, digits
+                if (e <= 9) {
+                    result[i++] = (char)(e+'0');
+                } else if (e <= 99) {
+                    result[i++] = (char)(e/10 +'0');
+                    result[i++] = (char)(e%10 + '0');
+                } else {
+                    result[i++] = (char)(e/100+'0');
+                    e %= 100;
+                    result[i++] = (char)(e/10+'0');
+                    result[i++] = (char)(e%10 + '0');
+                }
+            }
+        }
+        return i;
+    }
+
+    // Per-thread buffer for string/stringbuffer conversion
+    private static ThreadLocal<char[]> perThreadBuffer = new ThreadLocal<char[]>() {
+            protected synchronized char[] initialValue() {
+                return new char[26];
+            }
+        };
+
+    public void appendTo(Appendable buf) {
+          char result[] = perThreadBuffer.get();
+          int i = getChars(result);
+        if (buf instanceof StringBuilder)
+            ((StringBuilder) buf).append(result, 0, i);
+        else if (buf instanceof StringBuffer)
+            ((StringBuffer) buf).append(result, 0, i);
+        else
+            assert false;
+    }
+
+    @SuppressWarnings("fallthrough")
+    public static OldFloatingDecimalForTest
+    readJavaFormatString( String in ) throws NumberFormatException {
+        boolean isNegative = false;
+        boolean signSeen   = false;
+        int     decExp;
+        char    c;
+
+    parseNumber:
+        try{
+            in = in.trim(); // don't fool around with white space.
+                            // throws NullPointerException if null
+            int l = in.length();
+            if ( l == 0 ) throw new NumberFormatException("empty String");
+            int i = 0;
+            switch ( c = in.charAt( i ) ){
+            case '-':
+                isNegative = true;
+                //FALLTHROUGH
+            case '+':
+                i++;
+                signSeen = true;
+            }
+
+            // Check for NaN and Infinity strings
+            c = in.charAt(i);
+            if(c == 'N' || c == 'I') { // possible NaN or infinity
+                boolean potentialNaN = false;
+                char targetChars[] = null;  // char array of "NaN" or "Infinity"
+
+                if(c == 'N') {
+                    targetChars = notANumber;
+                    potentialNaN = true;
+                } else {
+                    targetChars = infinity;
+                }
+
+                // compare Input string to "NaN" or "Infinity"
+                int j = 0;
+                while(i < l && j < targetChars.length) {
+                    if(in.charAt(i) == targetChars[j]) {
+                        i++; j++;
+                    }
+                    else // something is amiss, throw exception
+                        break parseNumber;
+                }
+
+                // For the candidate string to be a NaN or infinity,
+                // all characters in input string and target char[]
+                // must be matched ==> j must equal targetChars.length
+                // and i must equal l
+                if( (j == targetChars.length) && (i == l) ) { // return NaN or infinity
+                    return (potentialNaN ? new OldFloatingDecimalForTest(Double.NaN) // NaN has no sign
+                            : new OldFloatingDecimalForTest(isNegative?
+                                                  Double.NEGATIVE_INFINITY:
+                                                  Double.POSITIVE_INFINITY)) ;
+                }
+                else { // something went wrong, throw exception
+                    break parseNumber;
+                }
+
+            } else if (c == '0')  { // check for hexadecimal floating-point number
+                if (l > i+1 ) {
+                    char ch = in.charAt(i+1);
+                    if (ch == 'x' || ch == 'X' ) // possible hex string
+                        return parseHexString(in);
+                }
+            }  // look for and process decimal floating-point string
+
+            char[] digits = new char[ l ];
+            int    nDigits= 0;
+            boolean decSeen = false;
+            int decPt = 0;
+            int nLeadZero = 0;
+            int nTrailZero= 0;
+        digitLoop:
+            while ( i < l ){
+                switch ( c = in.charAt( i ) ){
+                case '0':
+                    if ( nDigits > 0 ){
+                        nTrailZero += 1;
+                    } else {
+                        nLeadZero += 1;
+                    }
+                    break; // out of switch.
+                case '1':
+                case '2':
+                case '3':
+                case '4':
+                case '5':
+                case '6':
+                case '7':
+                case '8':
+                case '9':
+                    while ( nTrailZero > 0 ){
+                        digits[nDigits++] = '0';
+                        nTrailZero -= 1;
+                    }
+                    digits[nDigits++] = c;
+                    break; // out of switch.
+                case '.':
+                    if ( decSeen ){
+                        // already saw one ., this is the 2nd.
+                        throw new NumberFormatException("multiple points");
+                    }
+                    decPt = i;
+                    if ( signSeen ){
+                        decPt -= 1;
+                    }
+                    decSeen = true;
+                    break; // out of switch.
+                default:
+                    break digitLoop;
+                }
+                i++;
+            }
+            /*
+             * At this point, we've scanned all the digits and decimal
+             * point we're going to see. Trim off leading and trailing
+             * zeros, which will just confuse us later, and adjust
+             * our initial decimal exponent accordingly.
+             * To review:
+             * we have seen i total characters.
+             * nLeadZero of them were zeros before any other digits.
+             * nTrailZero of them were zeros after any other digits.
+             * if ( decSeen ), then a . was seen after decPt characters
+             * ( including leading zeros which have been discarded )
+             * nDigits characters were neither lead nor trailing
+             * zeros, nor point
+             */
+            /*
+             * special hack: if we saw no non-zero digits, then the
+             * answer is zero!
+             * Unfortunately, we feel honor-bound to keep parsing!
+             */
+            if ( nDigits == 0 ){
+                digits = zero;
+                nDigits = 1;
+                if ( nLeadZero == 0 ){
+                    // we saw NO DIGITS AT ALL,
+                    // not even a crummy 0!
+                    // this is not allowed.
+                    break parseNumber; // go throw exception
+                }
+
+            }
+
+            /* Our initial exponent is decPt, adjusted by the number of
+             * discarded zeros. Or, if there was no decPt,
+             * then its just nDigits adjusted by discarded trailing zeros.
+             */
+            if ( decSeen ){
+                decExp = decPt - nLeadZero;
+            } else {
+                decExp = nDigits+nTrailZero;
+            }
+
+            /*
+             * Look for 'e' or 'E' and an optionally signed integer.
+             */
+            if ( (i < l) &&  (((c = in.charAt(i) )=='e') || (c == 'E') ) ){
+                int expSign = 1;
+                int expVal  = 0;
+                int reallyBig = Integer.MAX_VALUE / 10;
+                boolean expOverflow = false;
+                switch( in.charAt(++i) ){
+                case '-':
+                    expSign = -1;
+                    //FALLTHROUGH
+                case '+':
+                    i++;
+                }
+                int expAt = i;
+            expLoop:
+                while ( i < l  ){
+                    if ( expVal >= reallyBig ){
+                        // the next character will cause integer
+                        // overflow.
+                        expOverflow = true;
+                    }
+                    switch ( c = in.charAt(i++) ){
+                    case '0':
+                    case '1':
+                    case '2':
+                    case '3':
+                    case '4':
+                    case '5':
+                    case '6':
+                    case '7':
+                    case '8':
+                    case '9':
+                        expVal = expVal*10 + ( (int)c - (int)'0' );
+                        continue;
+                    default:
+                        i--;           // back up.
+                        break expLoop; // stop parsing exponent.
+                    }
+                }
+                int expLimit = bigDecimalExponent+nDigits+nTrailZero;
+                if ( expOverflow || ( expVal > expLimit ) ){
+                    //
+                    // The intent here is to end up with
+                    // infinity or zero, as appropriate.
+                    // The reason for yielding such a small decExponent,
+                    // rather than something intuitive such as
+                    // expSign*Integer.MAX_VALUE, is that this value
+                    // is subject to further manipulation in
+                    // doubleValue() and floatValue(), and I don't want
+                    // it to be able to cause overflow there!
+                    // (The only way we can get into trouble here is for
+                    // really outrageous nDigits+nTrailZero, such as 2 billion. )
+                    //
+                    decExp = expSign*expLimit;
+                } else {
+                    // this should not overflow, since we tested
+                    // for expVal > (MAX+N), where N >= abs(decExp)
+                    decExp = decExp + expSign*expVal;
+                }
+
+                // if we saw something not a digit ( or end of string )
+                // after the [Ee][+-], without seeing any digits at all
+                // this is certainly an error. If we saw some digits,
+                // but then some trailing garbage, that might be ok.
+                // so we just fall through in that case.
+                // HUMBUG
+                if ( i == expAt )
+                    break parseNumber; // certainly bad
+            }
+            /*
+             * We parsed everything we could.
+             * If there are leftovers, then this is not good input!
+             */
+            if ( i < l &&
+                ((i != l - 1) ||
+                (in.charAt(i) != 'f' &&
+                 in.charAt(i) != 'F' &&
+                 in.charAt(i) != 'd' &&
+                 in.charAt(i) != 'D'))) {
+                break parseNumber; // go throw exception
+            }
+
+            return new OldFloatingDecimalForTest( isNegative, decExp, digits, nDigits,  false );
+        } catch ( StringIndexOutOfBoundsException e ){ }
+        throw new NumberFormatException("For input string: \"" + in + "\"");
+    }
+
+    /*
+     * Take a FloatingDecimal, which we presumably just scanned in,
+     * and find out what its value is, as a double.
+     *
+     * AS A SIDE EFFECT, SET roundDir TO INDICATE PREFERRED
+     * ROUNDING DIRECTION in case the result is really destined
+     * for a single-precision float.
+     */
+
+    public strictfp double doubleValue(){
+        int     kDigits = Math.min( nDigits, maxDecimalDigits+1 );
+        long    lValue;
+        double  dValue;
+        double  rValue, tValue;
+
+        // First, check for NaN and Infinity values
+        if(digits == infinity || digits == notANumber) {
+            if(digits == notANumber)
+                return Double.NaN;
+            else
+                return (isNegative?Double.NEGATIVE_INFINITY:Double.POSITIVE_INFINITY);
+        }
+        else {
+            if (mustSetRoundDir) {
+                roundDir = 0;
+            }
+            /*
+             * convert the lead kDigits to a long integer.
+             */
+            // (special performance hack: start to do it using int)
+            int iValue = (int)digits[0]-(int)'0';
+            int iDigits = Math.min( kDigits, intDecimalDigits );
+            for ( int i=1; i < iDigits; i++ ){
+                iValue = iValue*10 + (int)digits[i]-(int)'0';
+            }
+            lValue = (long)iValue;
+            for ( int i=iDigits; i < kDigits; i++ ){
+                lValue = lValue*10L + (long)((int)digits[i]-(int)'0');
+            }
+            dValue = (double)lValue;
+            int exp = decExponent-kDigits;
+            /*
+             * lValue now contains a long integer with the value of
+             * the first kDigits digits of the number.
+             * dValue contains the (double) of the same.
+             */
+
+            if ( nDigits <= maxDecimalDigits ){
+                /*
+                 * possibly an easy case.
+                 * We know that the digits can be represented
+                 * exactly. And if the exponent isn't too outrageous,
+                 * the whole thing can be done with one operation,
+                 * thus one rounding error.
+                 * Note that all our constructors trim all leading and
+                 * trailing zeros, so simple values (including zero)
+                 * will always end up here
+                 */
+                if (exp == 0 || dValue == 0.0)
+                    return (isNegative)? -dValue : dValue; // small floating integer
+                else if ( exp >= 0 ){
+                    if ( exp <= maxSmallTen ){
+                        /*
+                         * Can get the answer with one operation,
+                         * thus one roundoff.
+                         */
+                        rValue = dValue * small10pow[exp];
+                        if ( mustSetRoundDir ){
+                            tValue = rValue / small10pow[exp];
+                            roundDir = ( tValue ==  dValue ) ? 0
+                                :( tValue < dValue ) ? 1
+                                : -1;
+                        }
+                        return (isNegative)? -rValue : rValue;
+                    }
+                    int slop = maxDecimalDigits - kDigits;
+                    if ( exp <= maxSmallTen+slop ){
+                        /*
+                         * We can multiply dValue by 10^(slop)
+                         * and it is still "small" and exact.
+                         * Then we can multiply by 10^(exp-slop)
+                         * with one rounding.
+                         */
+                        dValue *= small10pow[slop];
+                        rValue = dValue * small10pow[exp-slop];
+
+                        if ( mustSetRoundDir ){
+                            tValue = rValue / small10pow[exp-slop];
+                            roundDir = ( tValue ==  dValue ) ? 0
+                                :( tValue < dValue ) ? 1
+                                : -1;
+                        }
+                        return (isNegative)? -rValue : rValue;
+                    }
+                    /*
+                     * Else we have a hard case with a positive exp.
+                     */
+                } else {
+                    if ( exp >= -maxSmallTen ){
+                        /*
+                         * Can get the answer in one division.
+                         */
+                        rValue = dValue / small10pow[-exp];
+                        tValue = rValue * small10pow[-exp];
+                        if ( mustSetRoundDir ){
+                            roundDir = ( tValue ==  dValue ) ? 0
+                                :( tValue < dValue ) ? 1
+                                : -1;
+                        }
+                        return (isNegative)? -rValue : rValue;
+                    }
+                    /*
+                     * Else we have a hard case with a negative exp.
+                     */
+                }
+            }
+
+            /*
+             * Harder cases:
+             * The sum of digits plus exponent is greater than
+             * what we think we can do with one error.
+             *
+             * Start by approximating the right answer by,
+             * naively, scaling by powers of 10.
+             */
+            if ( exp > 0 ){
+                if ( decExponent > maxDecimalExponent+1 ){
+                    /*
+                     * Lets face it. This is going to be
+                     * Infinity. Cut to the chase.
+                     */
+                    return (isNegative)? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
+                }
+                if ( (exp&15) != 0 ){
+                    dValue *= small10pow[exp&15];
+                }
+                if ( (exp>>=4) != 0 ){
+                    int j;
+                    for( j = 0; exp > 1; j++, exp>>=1 ){
+                        if ( (exp&1)!=0)
+                            dValue *= big10pow[j];
+                    }
+                    /*
+                     * The reason for the weird exp > 1 condition
+                     * in the above loop was so that the last multiply
+                     * would get unrolled. We handle it here.
+                     * It could overflow.
+                     */
+                    double t = dValue * big10pow[j];
+                    if ( Double.isInfinite( t ) ){
+                        /*
+                         * It did overflow.
+                         * Look more closely at the result.
+                         * If the exponent is just one too large,
+                         * then use the maximum finite as our estimate
+                         * value. Else call the result infinity
+                         * and punt it.
+                         * ( I presume this could happen because
+                         * rounding forces the result here to be
+                         * an ULP or two larger than
+                         * Double.MAX_VALUE ).
+                         */
+                        t = dValue / 2.0;
+                        t *= big10pow[j];
+                        if ( Double.isInfinite( t ) ){
+                            return (isNegative)? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
+                        }
+                        t = Double.MAX_VALUE;
+                    }
+                    dValue = t;
+                }
+            } else if ( exp < 0 ){
+                exp = -exp;
+                if ( decExponent < minDecimalExponent-1 ){
+                    /*
+                     * Lets face it. This is going to be
+                     * zero. Cut to the chase.
+                     */
+                    return (isNegative)? -0.0 : 0.0;
+                }
+                if ( (exp&15) != 0 ){
+                    dValue /= small10pow[exp&15];
+                }
+                if ( (exp>>=4) != 0 ){
+                    int j;
+                    for( j = 0; exp > 1; j++, exp>>=1 ){
+                        if ( (exp&1)!=0)
+                            dValue *= tiny10pow[j];
+                    }
+                    /*
+                     * The reason for the weird exp > 1 condition
+                     * in the above loop was so that the last multiply
+                     * would get unrolled. We handle it here.
+                     * It could underflow.
+                     */
+                    double t = dValue * tiny10pow[j];
+                    if ( t == 0.0 ){
+                        /*
+                         * It did underflow.
+                         * Look more closely at the result.
+                         * If the exponent is just one too small,
+                         * then use the minimum finite as our estimate
+                         * value. Else call the result 0.0
+                         * and punt it.
+                         * ( I presume this could happen because
+                         * rounding forces the result here to be
+                         * an ULP or two less than
+                         * Double.MIN_VALUE ).
+                         */
+                        t = dValue * 2.0;
+                        t *= tiny10pow[j];
+                        if ( t == 0.0 ){
+                            return (isNegative)? -0.0 : 0.0;
+                        }
+                        t = Double.MIN_VALUE;
+                    }
+                    dValue = t;
+                }
+            }
+
+            /*
+             * dValue is now approximately the result.
+             * The hard part is adjusting it, by comparison
+             * with OldFDBigIntForTest arithmetic.
+             * Formulate the EXACT big-number result as
+             * bigD0 * 10^exp
+             */
+            OldFDBigIntForTest bigD0 = new OldFDBigIntForTest( lValue, digits, kDigits, nDigits );
+            exp   = decExponent - nDigits;
+
+            correctionLoop:
+            while(true){
+                /* AS A SIDE EFFECT, THIS METHOD WILL SET THE INSTANCE VARIABLES
+                 * bigIntExp and bigIntNBits
+                 */
+                OldFDBigIntForTest bigB = doubleToBigInt( dValue );
+
+                /*
+                 * Scale bigD, bigB appropriately for
+                 * big-integer operations.
+                 * Naively, we multiply by powers of ten
+                 * and powers of two. What we actually do
+                 * is keep track of the powers of 5 and
+                 * powers of 2 we would use, then factor out
+                 * common divisors before doing the work.
+                 */
+                int B2, B5; // powers of 2, 5 in bigB
+                int     D2, D5; // powers of 2, 5 in bigD
+                int Ulp2;   // powers of 2 in halfUlp.
+                if ( exp >= 0 ){
+                    B2 = B5 = 0;
+                    D2 = D5 = exp;
+                } else {
+                    B2 = B5 = -exp;
+                    D2 = D5 = 0;
+                }
+                if ( bigIntExp >= 0 ){
+                    B2 += bigIntExp;
+                } else {
+                    D2 -= bigIntExp;
+                }
+                Ulp2 = B2;
+                // shift bigB and bigD left by a number s. t.
+                // halfUlp is still an integer.
+                int hulpbias;
+                if ( bigIntExp+bigIntNBits <= -expBias+1 ){
+                    // This is going to be a denormalized number
+                    // (if not actually zero).
+                    // half an ULP is at 2^-(expBias+expShift+1)
+                    hulpbias = bigIntExp+ expBias + expShift;
+                } else {
+                    hulpbias = expShift + 2 - bigIntNBits;
+                }
+                B2 += hulpbias;
+                D2 += hulpbias;
+                // if there are common factors of 2, we might just as well
+                // factor them out, as they add nothing useful.
+                int common2 = Math.min( B2, Math.min( D2, Ulp2 ) );
+                B2 -= common2;
+                D2 -= common2;
+                Ulp2 -= common2;
+                // do multiplications by powers of 5 and 2
+                bigB = multPow52( bigB, B5, B2 );
+                OldFDBigIntForTest bigD = multPow52( new OldFDBigIntForTest( bigD0 ), D5, D2 );
+                //
+                // to recap:
+                // bigB is the scaled-big-int version of our floating-point
+                // candidate.
+                // bigD is the scaled-big-int version of the exact value
+                // as we understand it.
+                // halfUlp is 1/2 an ulp of bigB, except for special cases
+                // of exact powers of 2
+                //
+                // the plan is to compare bigB with bigD, and if the difference
+                // is less than halfUlp, then we're satisfied. Otherwise,
+                // use the ratio of difference to halfUlp to calculate a fudge
+                // factor to add to the floating value, then go 'round again.
+                //
+                OldFDBigIntForTest diff;
+                int cmpResult;
+                boolean overvalue;
+                if ( (cmpResult = bigB.cmp( bigD ) ) > 0 ){
+                    overvalue = true; // our candidate is too big.
+                    diff = bigB.sub( bigD );
+                    if ( (bigIntNBits == 1) && (bigIntExp > -expBias+1) ){
+                        // candidate is a normalized exact power of 2 and
+                        // is too big. We will be subtracting.
+                        // For our purposes, ulp is the ulp of the
+                        // next smaller range.
+                        Ulp2 -= 1;
+                        if ( Ulp2 < 0 ){
+                            // rats. Cannot de-scale ulp this far.
+                            // must scale diff in other direction.
+                            Ulp2 = 0;
+                            diff.lshiftMe( 1 );
+                        }
+                    }
+                } else if ( cmpResult < 0 ){
+                    overvalue = false; // our candidate is too small.
+                    diff = bigD.sub( bigB );
+                } else {
+                    // the candidate is exactly right!
+                    // this happens with surprising frequency
+                    break correctionLoop;
+                }
+                OldFDBigIntForTest halfUlp = constructPow52( B5, Ulp2 );
+                if ( (cmpResult = diff.cmp( halfUlp ) ) < 0 ){
+                    // difference is small.
+                    // this is close enough
+                    if (mustSetRoundDir) {
+                        roundDir = overvalue ? -1 : 1;
+                    }
+                    break correctionLoop;
+                } else if ( cmpResult == 0 ){
+                    // difference is exactly half an ULP
+                    // round to some other value maybe, then finish
+                    dValue += 0.5*ulp( dValue, overvalue );
+                    // should check for bigIntNBits == 1 here??
+                    if (mustSetRoundDir) {
+                        roundDir = overvalue ? -1 : 1;
+                    }
+                    break correctionLoop;
+                } else {
+                    // difference is non-trivial.
+                    // could scale addend by ratio of difference to
+                    // halfUlp here, if we bothered to compute that difference.
+                    // Most of the time ( I hope ) it is about 1 anyway.
+                    dValue += ulp( dValue, overvalue );
+                    if ( dValue == 0.0 || dValue == Double.POSITIVE_INFINITY )
+                        break correctionLoop; // oops. Fell off end of range.
+                    continue; // try again.
+                }
+
+            }
+            return (isNegative)? -dValue : dValue;
+        }
+    }
+
+    /*
+     * Take a FloatingDecimal, which we presumably just scanned in,
+     * and find out what its value is, as a float.
+     * This is distinct from doubleValue() to avoid the extremely
+     * unlikely case of a double rounding error, wherein the conversion
+     * to double has one rounding error, and the conversion of that double
+     * to a float has another rounding error, IN THE WRONG DIRECTION,
+     * ( because of the preference to a zero low-order bit ).
+     */
+
+    public strictfp float floatValue(){
+        int     kDigits = Math.min( nDigits, singleMaxDecimalDigits+1 );
+        int     iValue;
+        float   fValue;
+
+        // First, check for NaN and Infinity values
+        if(digits == infinity || digits == notANumber) {
+            if(digits == notANumber)
+                return Float.NaN;
+            else
+                return (isNegative?Float.NEGATIVE_INFINITY:Float.POSITIVE_INFINITY);
+        }
+        else {
+            /*
+             * convert the lead kDigits to an integer.
+             */
+            iValue = (int)digits[0]-(int)'0';
+            for ( int i=1; i < kDigits; i++ ){
+                iValue = iValue*10 + (int)digits[i]-(int)'0';
+            }
+            fValue = (float)iValue;
+            int exp = decExponent-kDigits;
+            /*
+             * iValue now contains an integer with the value of
+             * the first kDigits digits of the number.
+             * fValue contains the (float) of the same.
+             */
+
+            if ( nDigits <= singleMaxDecimalDigits ){
+                /*
+                 * possibly an easy case.
+                 * We know that the digits can be represented
+                 * exactly. And if the exponent isn't too outrageous,
+                 * the whole thing can be done with one operation,
+                 * thus one rounding error.
+                 * Note that all our constructors trim all leading and
+                 * trailing zeros, so simple values (including zero)
+                 * will always end up here.
+                 */
+                if (exp == 0 || fValue == 0.0f)
+                    return (isNegative)? -fValue : fValue; // small floating integer
+                else if ( exp >= 0 ){
+                    if ( exp <= singleMaxSmallTen ){
+                        /*
+                         * Can get the answer with one operation,
+                         * thus one roundoff.
+                         */
+                        fValue *= singleSmall10pow[exp];
+                        return (isNegative)? -fValue : fValue;
+                    }
+                    int slop = singleMaxDecimalDigits - kDigits;
+                    if ( exp <= singleMaxSmallTen+slop ){
+                        /*
+                         * We can multiply dValue by 10^(slop)
+                         * and it is still "small" and exact.
+                         * Then we can multiply by 10^(exp-slop)
+                         * with one rounding.
+                         */
+                        fValue *= singleSmall10pow[slop];
+                        fValue *= singleSmall10pow[exp-slop];
+                        return (isNegative)? -fValue : fValue;
+                    }
+                    /*
+                     * Else we have a hard case with a positive exp.
+                     */
+                } else {
+                    if ( exp >= -singleMaxSmallTen ){
+                        /*
+                         * Can get the answer in one division.
+                         */
+                        fValue /= singleSmall10pow[-exp];
+                        return (isNegative)? -fValue : fValue;
+                    }
+                    /*
+                     * Else we have a hard case with a negative exp.
+                     */
+                }
+            } else if ( (decExponent >= nDigits) && (nDigits+decExponent <= maxDecimalDigits) ){
+                /*
+                 * In double-precision, this is an exact floating integer.
+                 * So we can compute to double, then shorten to float
+                 * with one round, and get the right answer.
+                 *
+                 * First, finish accumulating digits.
+                 * Then convert that integer to a double, multiply
+                 * by the appropriate power of ten, and convert to float.
+                 */
+                long lValue = (long)iValue;
+                for ( int i=kDigits; i < nDigits; i++ ){
+                    lValue = lValue*10L + (long)((int)digits[i]-(int)'0');
+                }
+                double dValue = (double)lValue;
+                exp = decExponent-nDigits;
+                dValue *= small10pow[exp];
+                fValue = (float)dValue;
+                return (isNegative)? -fValue : fValue;
+
+            }
+            /*
+             * Harder cases:
+             * The sum of digits plus exponent is greater than
+             * what we think we can do with one error.
+             *
+             * Start by weeding out obviously out-of-range
+             * results, then convert to double and go to
+             * common hard-case code.
+             */
+            if ( decExponent > singleMaxDecimalExponent+1 ){
+                /*
+                 * Lets face it. This is going to be
+                 * Infinity. Cut to the chase.
+                 */
+                return (isNegative)? Float.NEGATIVE_INFINITY : Float.POSITIVE_INFINITY;
+            } else if ( decExponent < singleMinDecimalExponent-1 ){
+                /*
+                 * Lets face it. This is going to be
+                 * zero. Cut to the chase.
+                 */
+                return (isNegative)? -0.0f : 0.0f;
+            }
+
+            /*
+             * Here, we do 'way too much work, but throwing away
+             * our partial results, and going and doing the whole
+             * thing as double, then throwing away half the bits that computes
+             * when we convert back to float.
+             *
+             * The alternative is to reproduce the whole multiple-precision
+             * algorithm for float precision, or to try to parameterize it
+             * for common usage. The former will take about 400 lines of code,
+             * and the latter I tried without success. Thus the semi-hack
+             * answer here.
+             */
+            mustSetRoundDir = !fromHex;
+            double dValue = doubleValue();
+            return stickyRound( dValue );
+        }
+    }
+
+
+    /*
+     * All the positive powers of 10 that can be
+     * represented exactly in double/float.
+     */
+    private static final double small10pow[] = {
+        1.0e0,
+        1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5,
+        1.0e6, 1.0e7, 1.0e8, 1.0e9, 1.0e10,
+        1.0e11, 1.0e12, 1.0e13, 1.0e14, 1.0e15,
+        1.0e16, 1.0e17, 1.0e18, 1.0e19, 1.0e20,
+        1.0e21, 1.0e22
+    };
+
+    private static final float singleSmall10pow[] = {
+        1.0e0f,
+        1.0e1f, 1.0e2f, 1.0e3f, 1.0e4f, 1.0e5f,
+        1.0e6f, 1.0e7f, 1.0e8f, 1.0e9f, 1.0e10f
+    };
+
+    private static final double big10pow[] = {
+        1e16, 1e32, 1e64, 1e128, 1e256 };
+    private static final double tiny10pow[] = {
+        1e-16, 1e-32, 1e-64, 1e-128, 1e-256 };
+
+    private static final int maxSmallTen = small10pow.length-1;
+    private static final int singleMaxSmallTen = singleSmall10pow.length-1;
+
+    private static final int small5pow[] = {
+        1,
+        5,
+        5*5,
+        5*5*5,
+        5*5*5*5,
+        5*5*5*5*5,
+        5*5*5*5*5*5,
+        5*5*5*5*5*5*5,
+        5*5*5*5*5*5*5*5,
+        5*5*5*5*5*5*5*5*5,
+        5*5*5*5*5*5*5*5*5*5,
+        5*5*5*5*5*5*5*5*5*5*5,
+        5*5*5*5*5*5*5*5*5*5*5*5,
+        5*5*5*5*5*5*5*5*5*5*5*5*5
+    };
+
+
+    private static final long long5pow[] = {
+        1L,
+        5L,
+        5L*5,
+        5L*5*5,
+        5L*5*5*5,
+        5L*5*5*5*5,
+        5L*5*5*5*5*5,
+        5L*5*5*5*5*5*5,
+        5L*5*5*5*5*5*5*5,
+        5L*5*5*5*5*5*5*5*5,
+        5L*5*5*5*5*5*5*5*5*5,
+        5L*5*5*5*5*5*5*5*5*5*5,
+        5L*5*5*5*5*5*5*5*5*5*5*5,
+        5L*5*5*5*5*5*5*5*5*5*5*5*5,
+        5L*5*5*5*5*5*5*5*5*5*5*5*5*5,
+        5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
+        5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
+        5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
+        5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
+        5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
+        5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
+        5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
+        5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
+        5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
+        5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
+        5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
+        5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
+    };
+
+    // approximately ceil( log2( long5pow[i] ) )
+    private static final int n5bits[] = {
+        0,
+        3,
+        5,
+        7,
+        10,
+        12,
+        14,
+        17,
+        19,
+        21,
+        24,
+        26,
+        28,
+        31,
+        33,
+        35,
+        38,
+        40,
+        42,
+        45,
+        47,
+        49,
+        52,
+        54,
+        56,
+        59,
+        61,
+    };
+
+    private static final char infinity[] = { 'I', 'n', 'f', 'i', 'n', 'i', 't', 'y' };
+    private static final char notANumber[] = { 'N', 'a', 'N' };
+    private static final char zero[] = { '0', '0', '0', '0', '0', '0', '0', '0' };
+
+
+    /*
+     * Grammar is compatible with hexadecimal floating-point constants
+     * described in section 6.4.4.2 of the C99 specification.
+     */
+    private static Pattern hexFloatPattern = null;
+    private static synchronized Pattern getHexFloatPattern() {
+        if (hexFloatPattern == null) {
+           hexFloatPattern = Pattern.compile(
+                   //1           234                   56                7                   8      9
+                    "([-+])?0[xX](((\\p{XDigit}+)\\.?)|((\\p{XDigit}*)\\.(\\p{XDigit}+)))[pP]([-+])?(\\p{Digit}+)[fFdD]?"
+                    );
+        }
+        return hexFloatPattern;
+    }
+
+    /*
+     * Convert string s to a suitable floating decimal; uses the
+     * double constructor and set the roundDir variable appropriately
+     * in case the value is later converted to a float.
+     */
+   static OldFloatingDecimalForTest parseHexString(String s) {
+        // Verify string is a member of the hexadecimal floating-point
+        // string language.
+        Matcher m = getHexFloatPattern().matcher(s);
+        boolean validInput = m.matches();
+
+        if (!validInput) {
+            // Input does not match pattern
+            throw new NumberFormatException("For input string: \"" + s + "\"");
+        } else { // validInput
+            /*
+             * We must isolate the sign, significand, and exponent
+             * fields.  The sign value is straightforward.  Since
+             * floating-point numbers are stored with a normalized
+             * representation, the significand and exponent are
+             * interrelated.
+             *
+             * After extracting the sign, we normalized the
+             * significand as a hexadecimal value, calculating an
+             * exponent adjust for any shifts made during
+             * normalization.  If the significand is zero, the
+             * exponent doesn't need to be examined since the output
+             * will be zero.
+             *
+             * Next the exponent in the input string is extracted.
+             * Afterwards, the significand is normalized as a *binary*
+             * value and the input value's normalized exponent can be
+             * computed.  The significand bits are copied into a
+             * double significand; if the string has more logical bits
+             * than can fit in a double, the extra bits affect the
+             * round and sticky bits which are used to round the final
+             * value.
+             */
+
+            //  Extract significand sign
+            String group1 = m.group(1);
+            double sign = (( group1 == null ) || group1.equals("+"))? 1.0 : -1.0;
+
+
+            //  Extract Significand magnitude
+            /*
+             * Based on the form of the significand, calculate how the
+             * binary exponent needs to be adjusted to create a
+             * normalized *hexadecimal* floating-point number; that
+             * is, a number where there is one nonzero hex digit to
+             * the left of the (hexa)decimal point.  Since we are
+             * adjusting a binary, not hexadecimal exponent, the
+             * exponent is adjusted by a multiple of 4.
+             *
+             * There are a number of significand scenarios to consider;
+             * letters are used in indicate nonzero digits:
+             *
+             * 1. 000xxxx       =>      x.xxx   normalized
+             *    increase exponent by (number of x's - 1)*4
+             *
+             * 2. 000xxx.yyyy =>        x.xxyyyy        normalized
+             *    increase exponent by (number of x's - 1)*4
+             *
+             * 3. .000yyy  =>   y.yy    normalized
+             *    decrease exponent by (number of zeros + 1)*4
+             *
+             * 4. 000.00000yyy => y.yy normalized
+             *    decrease exponent by (number of zeros to right of point + 1)*4
+             *
+             * If the significand is exactly zero, return a properly
+             * signed zero.
+             */
+
+            String significandString =null;
+            int signifLength = 0;
+            int exponentAdjust = 0;
+            {
+                int leftDigits  = 0; // number of meaningful digits to
+                                     // left of "decimal" point
+                                     // (leading zeros stripped)
+                int rightDigits = 0; // number of digits to right of
+                                     // "decimal" point; leading zeros
+                                     // must always be accounted for
+                /*
+                 * The significand is made up of either
+                 *
+                 * 1. group 4 entirely (integer portion only)
+                 *
+                 * OR
+                 *
+                 * 2. the fractional portion from group 7 plus any
+                 * (optional) integer portions from group 6.
+                 */
+                String group4;
+                if( (group4 = m.group(4)) != null) {  // Integer-only significand
+                    // Leading zeros never matter on the integer portion
+                    significandString = stripLeadingZeros(group4);
+                    leftDigits = significandString.length();
+                }
+                else {
+                    // Group 6 is the optional integer; leading zeros
+                    // never matter on the integer portion
+                    String group6 = stripLeadingZeros(m.group(6));
+                    leftDigits = group6.length();
+
+                    // fraction
+                    String group7 = m.group(7);
+                    rightDigits = group7.length();
+
+                    // Turn "integer.fraction" into "integer"+"fraction"
+                    significandString =
+                        ((group6 == null)?"":group6) + // is the null
+                        // check necessary?
+                        group7;
+                }
+
+                significandString = stripLeadingZeros(significandString);
+                signifLength  = significandString.length();
+
+                /*
+                 * Adjust exponent as described above
+                 */
+                if (leftDigits >= 1) {  // Cases 1 and 2
+                    exponentAdjust = 4*(leftDigits - 1);
+                } else {                // Cases 3 and 4
+                    exponentAdjust = -4*( rightDigits - signifLength + 1);
+                }
+
+                // If the significand is zero, the exponent doesn't
+                // matter; return a properly signed zero.
+
+                if (signifLength == 0) { // Only zeros in input
+                    return new OldFloatingDecimalForTest(sign * 0.0);
+                }
+            }
+
+            //  Extract Exponent
+            /*
+             * Use an int to read in the exponent value; this should
+             * provide more than sufficient range for non-contrived
+             * inputs.  If reading the exponent in as an int does
+             * overflow, examine the sign of the exponent and
+             * significand to determine what to do.
+             */
+            String group8 = m.group(8);
+            boolean positiveExponent = ( group8 == null ) || group8.equals("+");
+            long unsignedRawExponent;
+            try {
+                unsignedRawExponent = Integer.parseInt(m.group(9));
+            }
+            catch (NumberFormatException e) {
+                // At this point, we know the exponent is
+                // syntactically well-formed as a sequence of
+                // digits.  Therefore, if an NumberFormatException
+                // is thrown, it must be due to overflowing int's
+                // range.  Also, at this point, we have already
+                // checked for a zero significand.  Thus the signs
+                // of the exponent and significand determine the
+                // final result:
+                //
+                //                      significand
+                //                      +               -
+                // exponent     +       +infinity       -infinity
+                //              -       +0.0            -0.0
+                return new OldFloatingDecimalForTest(sign * (positiveExponent ?
+                                                   Double.POSITIVE_INFINITY : 0.0));
+            }
+
+            long rawExponent =
+                (positiveExponent ? 1L : -1L) * // exponent sign
+                unsignedRawExponent;            // exponent magnitude
+
+            // Calculate partially adjusted exponent
+            long exponent = rawExponent + exponentAdjust ;
+
+            // Starting copying non-zero bits into proper position in
+            // a long; copy explicit bit too; this will be masked
+            // later for normal values.
+
+            boolean round = false;
+            boolean sticky = false;
+            int bitsCopied=0;
+            int nextShift=0;
+            long significand=0L;
+            // First iteration is different, since we only copy
+            // from the leading significand bit; one more exponent
+            // adjust will be needed...
+
+            // IMPORTANT: make leadingDigit a long to avoid
+            // surprising shift semantics!
+            long leadingDigit = getHexDigit(significandString, 0);
+
+            /*
+             * Left shift the leading digit (53 - (bit position of
+             * leading 1 in digit)); this sets the top bit of the
+             * significand to 1.  The nextShift value is adjusted
+             * to take into account the number of bit positions of
+             * the leadingDigit actually used.  Finally, the
+             * exponent is adjusted to normalize the significand
+             * as a binary value, not just a hex value.
+             */
+            if (leadingDigit == 1) {
+                significand |= leadingDigit << 52;
+                nextShift = 52 - 4;
+                /* exponent += 0 */     }
+            else if (leadingDigit <= 3) { // [2, 3]
+                significand |= leadingDigit << 51;
+                nextShift = 52 - 5;
+                exponent += 1;
+            }
+            else if (leadingDigit <= 7) { // [4, 7]
+                significand |= leadingDigit << 50;
+                nextShift = 52 - 6;
+                exponent += 2;
+            }
+            else if (leadingDigit <= 15) { // [8, f]
+                significand |= leadingDigit << 49;
+                nextShift = 52 - 7;
+                exponent += 3;
+            } else {
+                throw new AssertionError("Result from digit conversion too large!");
+            }
+            // The preceding if-else could be replaced by a single
+            // code block based on the high-order bit set in
+            // leadingDigit.  Given leadingOnePosition,
+
+            // significand |= leadingDigit << (SIGNIFICAND_WIDTH - leadingOnePosition);
+            // nextShift = 52 - (3 + leadingOnePosition);
+            // exponent += (leadingOnePosition-1);
+
+
+            /*
+             * Now the exponent variable is equal to the normalized
+             * binary exponent.  Code below will make representation
+             * adjustments if the exponent is incremented after
+             * rounding (includes overflows to infinity) or if the
+             * result is subnormal.
+             */
+
+            // Copy digit into significand until the significand can't
+            // hold another full hex digit or there are no more input
+            // hex digits.
+            int i = 0;
+            for(i = 1;
+                i < signifLength && nextShift >= 0;
+                i++) {
+                long currentDigit = getHexDigit(significandString, i);
+                significand |= (currentDigit << nextShift);
+                nextShift-=4;
+            }
+
+            // After the above loop, the bulk of the string is copied.
+            // Now, we must copy any partial hex digits into the
+            // significand AND compute the round bit and start computing
+            // sticky bit.
+
+            if ( i < signifLength ) { // at least one hex input digit exists
+                long currentDigit = getHexDigit(significandString, i);
+
+                // from nextShift, figure out how many bits need
+                // to be copied, if any
+                switch(nextShift) { // must be negative
+                case -1:
+                    // three bits need to be copied in; can
+                    // set round bit
+                    significand |= ((currentDigit & 0xEL) >> 1);
+                    round = (currentDigit & 0x1L)  != 0L;
+                    break;
+
+                case -2:
+                    // two bits need to be copied in; can
+                    // set round and start sticky
+                    significand |= ((currentDigit & 0xCL) >> 2);
+                    round = (currentDigit &0x2L)  != 0L;
+                    sticky = (currentDigit & 0x1L) != 0;
+                    break;
+
+                case -3:
+                    // one bit needs to be copied in
+                    significand |= ((currentDigit & 0x8L)>>3);
+                    // Now set round and start sticky, if possible
+                    round = (currentDigit &0x4L)  != 0L;
+                    sticky = (currentDigit & 0x3L) != 0;
+                    break;
+
+                case -4:
+                    // all bits copied into significand; set
+                    // round and start sticky
+                    round = ((currentDigit & 0x8L) != 0);  // is top bit set?
+                    // nonzeros in three low order bits?
+                    sticky = (currentDigit & 0x7L) != 0;
+                    break;
+
+                default:
+                    throw new AssertionError("Unexpected shift distance remainder.");
+                    // break;
+                }
+
+                // Round is set; sticky might be set.
+
+                // For the sticky bit, it suffices to check the
+                // current digit and test for any nonzero digits in
+                // the remaining unprocessed input.
+                i++;
+                while(i < signifLength && !sticky) {
+                    currentDigit =  getHexDigit(significandString,i);
+                    sticky = sticky || (currentDigit != 0);
+                    i++;
+                }
+
+            }
+            // else all of string was seen, round and sticky are
+            // correct as false.
+
+
+            // Check for overflow and update exponent accordingly.
+
+            if (exponent > Double.MAX_EXPONENT) {         // Infinite result
+                // overflow to properly signed infinity
+                return new OldFloatingDecimalForTest(sign * Double.POSITIVE_INFINITY);
+            } else {  // Finite return value
+                if (exponent <= Double.MAX_EXPONENT && // (Usually) normal result
+                    exponent >= Double.MIN_EXPONENT) {
+
+                    // The result returned in this block cannot be a
+                    // zero or subnormal; however after the
+                    // significand is adjusted from rounding, we could
+                    // still overflow in infinity.
+
+                    // AND exponent bits into significand; if the
+                    // significand is incremented and overflows from
+                    // rounding, this combination will update the
+                    // exponent correctly, even in the case of
+                    // Double.MAX_VALUE overflowing to infinity.
+
+                    significand = (( (exponent +
+                                     (long)DoubleConsts.EXP_BIAS) <<
+                                     (DoubleConsts.SIGNIFICAND_WIDTH-1))
+                                   & DoubleConsts.EXP_BIT_MASK) |
+                        (DoubleConsts.SIGNIF_BIT_MASK & significand);
+
+                }  else  {  // Subnormal or zero
+                    // (exponent < Double.MIN_EXPONENT)
+
+                    if (exponent < (DoubleConsts.MIN_SUB_EXPONENT -1 )) {
+                        // No way to round back to nonzero value
+                        // regardless of significand if the exponent is
+                        // less than -1075.
+                        return new OldFloatingDecimalForTest(sign * 0.0);
+                    } else { //  -1075 <= exponent <= MIN_EXPONENT -1 = -1023
+                        /*
+                         * Find bit position to round to; recompute
+                         * round and sticky bits, and shift
+                         * significand right appropriately.
+                         */
+
+                        sticky = sticky || round;
+                        round = false;
+
+                        // Number of bits of significand to preserve is
+                        // exponent - abs_min_exp +1
+                        // check:
+                        // -1075 +1074 + 1 = 0
+                        // -1023 +1074 + 1 = 52
+
+                        int bitsDiscarded = 53 -
+                            ((int)exponent - DoubleConsts.MIN_SUB_EXPONENT + 1);
+                        assert bitsDiscarded >= 1 && bitsDiscarded <= 53;
+
+                        // What to do here:
+                        // First, isolate the new round bit
+                        round = (significand & (1L << (bitsDiscarded -1))) != 0L;
+                        if (bitsDiscarded > 1) {
+                            // create mask to update sticky bits; low
+                            // order bitsDiscarded bits should be 1
+                            long mask = ~((~0L) << (bitsDiscarded -1));
+                            sticky = sticky || ((significand & mask) != 0L ) ;
+                        }
+
+                        // Now, discard the bits
+                        significand = significand >> bitsDiscarded;
+
+                        significand = (( ((long)(Double.MIN_EXPONENT -1) + // subnorm exp.
+                                          (long)DoubleConsts.EXP_BIAS) <<
+                                         (DoubleConsts.SIGNIFICAND_WIDTH-1))
+                                       & DoubleConsts.EXP_BIT_MASK) |
+                            (DoubleConsts.SIGNIF_BIT_MASK & significand);
+                    }
+                }
+
+                // The significand variable now contains the currently
+                // appropriate exponent bits too.
+
+                /*
+                 * Determine if significand should be incremented;
+                 * making this determination depends on the least
+                 * significant bit and the round and sticky bits.
+                 *
+                 * Round to nearest even rounding table, adapted from
+                 * table 4.7 in "Computer Arithmetic" by IsraelKoren.
+                 * The digit to the left of the "decimal" point is the
+                 * least significant bit, the digits to the right of
+                 * the point are the round and sticky bits
+                 *
+                 * Number       Round(x)
+                 * x0.00        x0.
+                 * x0.01        x0.
+                 * x0.10        x0.
+                 * x0.11        x1. = x0. +1
+                 * x1.00        x1.
+                 * x1.01        x1.
+                 * x1.10        x1. + 1
+                 * x1.11        x1. + 1
+                 */
+                boolean incremented = false;
+                boolean leastZero  = ((significand & 1L) == 0L);
+                if( (  leastZero  && round && sticky ) ||
+                    ((!leastZero) && round )) {
+                    incremented = true;
+                    significand++;
+                }
+
+                OldFloatingDecimalForTest fd = new OldFloatingDecimalForTest(Math.copySign(
+                                                              Double.longBitsToDouble(significand),
+                                                              sign));
+
+                /*
+                 * Set roundingDir variable field of fd properly so
+                 * that the input string can be properly rounded to a
+                 * float value.  There are two cases to consider:
+                 *
+                 * 1. rounding to double discards sticky bit
+                 * information that would change the result of a float
+                 * rounding (near halfway case between two floats)
+                 *
+                 * 2. rounding to double rounds up when rounding up
+                 * would not occur when rounding to float.
+                 *
+                 * For former case only needs to be considered when
+                 * the bits rounded away when casting to float are all
+                 * zero; otherwise, float round bit is properly set
+                 * and sticky will already be true.
+                 *
+                 * The lower exponent bound for the code below is the
+                 * minimum (normalized) subnormal exponent - 1 since a
+                 * value with that exponent can round up to the
+                 * minimum subnormal value and the sticky bit
+                 * information must be preserved (i.e. case 1).
+                 */
+                if ((exponent >= FloatConsts.MIN_SUB_EXPONENT-1) &&
+                    (exponent <= Float.MAX_EXPONENT ) ){
+                    // Outside above exponent range, the float value
+                    // will be zero or infinity.
+
+                    /*
+                     * If the low-order 28 bits of a rounded double
+                     * significand are 0, the double could be a
+                     * half-way case for a rounding to float.  If the
+                     * double value is a half-way case, the double
+                     * significand may have to be modified to round
+                     * the the right float value (see the stickyRound
+                     * method).  If the rounding to double has lost
+                     * what would be float sticky bit information, the
+                     * double significand must be incremented.  If the
+                     * double value's significand was itself
+                     * incremented, the float value may end up too
+                     * large so the increment should be undone.
+                     */
+                    if ((significand & 0xfffffffL) ==  0x0L) {
+                        // For negative values, the sign of the
+                        // roundDir is the same as for positive values
+                        // since adding 1 increasing the significand's
+                        // magnitude and subtracting 1 decreases the
+                        // significand's magnitude.  If neither round
+                        // nor sticky is true, the double value is
+                        // exact and no adjustment is required for a
+                        // proper float rounding.
+                        if( round || sticky) {
+                            if (leastZero) { // prerounding lsb is 0
+                                // If round and sticky were both true,
+                                // and the least significant
+                                // significand bit were 0, the rounded
+                                // significand would not have its
+                                // low-order bits be zero.  Therefore,
+                                // we only need to adjust the
+                                // significand if round XOR sticky is
+                                // true.
+                                if (round ^ sticky) {
+                                    fd.roundDir =  1;
+                                }
+                            }
+                            else { // prerounding lsb is 1
+                                // If the prerounding lsb is 1 and the
+                                // resulting significand has its
+                                // low-order bits zero, the significand
+                                // was incremented.  Here, we undo the
+                                // increment, which will ensure the
+                                // right guard and sticky bits for the
+                                // float rounding.
+                                if (round)
+                                    fd.roundDir =  -1;
+                            }
+                        }
+                    }
+                }
+
+                fd.fromHex = true;
+                return fd;
+            }
+        }
+    }
+
+    /**
+     * Return <code>s</code> with any leading zeros removed.
+     */
+    static String stripLeadingZeros(String s) {
+        return  s.replaceFirst("^0+", "");
+    }
+
+    /**
+     * Extract a hexadecimal digit from position <code>position</code>
+     * of string <code>s</code>.
+     */
+    static int getHexDigit(String s, int position) {
+        int value = Character.digit(s.charAt(position), 16);
+        if (value <= -1 || value >= 16) {
+            throw new AssertionError("Unexpected failure of digit conversion of " +
+                                     s.charAt(position));
+        }
+        return value;
+    }
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/internal/math/FloatingDecimal/TestFDBigInteger.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,435 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.math.BigInteger;
+import java.util.Random;
+import jdk.internal.math.FDBigInteger;
+
+/**
+ * @test
+ * @bug 7032154
+ * @summary unit testys of FDBigInteger
+ * @modules java.base/jdk.internal.math
+ * @author Dmitry Nadezhin
+ */
+public class TestFDBigInteger {
+
+    private static final int MAX_P5 = 413;
+    private static final int MAX_P2 = 65;
+    private static final long LONG_SIGN_MASK = (1L << 63);
+    private static final BigInteger FIVE = BigInteger.valueOf(5);
+    private static final FDBigInteger MUTABLE_ZERO = FDBigInteger.valueOfPow52(0, 0).leftInplaceSub(FDBigInteger.valueOfPow52(0, 0));
+    private static final FDBigInteger IMMUTABLE_ZERO = FDBigInteger.valueOfPow52(0, 0).leftInplaceSub(FDBigInteger.valueOfPow52(0, 0));
+    private static final FDBigInteger IMMUTABLE_MILLION = genMillion1();
+    private static final FDBigInteger IMMUTABLE_BILLION = genBillion1();
+    private static final FDBigInteger IMMUTABLE_TEN18 = genTen18();
+
+    static {
+        IMMUTABLE_ZERO.makeImmutable();
+        IMMUTABLE_MILLION.makeImmutable();
+        IMMUTABLE_BILLION.makeImmutable();
+        IMMUTABLE_TEN18.makeImmutable();
+    }
+
+    private static FDBigInteger mutable(String hex, int offset) {
+        char[] chars = new BigInteger(hex, 16).toString().toCharArray();
+        return new FDBigInteger(0, chars, 0, chars.length).multByPow52(0, offset * 32);
+    }
+
+    private static FDBigInteger immutable(String hex, int offset) {
+        FDBigInteger fd = mutable(hex, offset);
+        fd.makeImmutable();
+        return fd;
+    }
+
+    private static BigInteger biPow52(int p5, int p2) {
+        return FIVE.pow(p5).shiftLeft(p2);
+    }
+
+    // data.length == 1, nWords == 1, offset == 0
+    private static FDBigInteger genMillion1() {
+        return FDBigInteger.valueOfPow52(6, 0).leftShift(6);
+    }
+
+    // data.length == 2, nWords == 1, offset == 0
+    private static FDBigInteger genMillion2() {
+        return FDBigInteger.valueOfMulPow52(1000000L, 0, 0);
+    }
+
+    // data.length == 1, nWords == 1, offset == 0
+    private static FDBigInteger genBillion1() {
+        return FDBigInteger.valueOfPow52(9, 0).leftShift(9);
+    }
+
+    // data.length == 2, nWords == 2, offset == 0
+    private static FDBigInteger genTen18() {
+        return FDBigInteger.valueOfPow52(18, 0).leftShift(18);
+    }
+
+    private static void check(BigInteger expected, FDBigInteger actual, String message) throws Exception {
+        if (!expected.equals(actual.toBigInteger())) {
+            throw new Exception(message + " result " + actual.toHexString() + " expected " + expected.toString(16));
+        }
+    }
+
+    private static void testValueOfPow52(int p5, int p2) throws Exception {
+        check(biPow52(p5, p2), FDBigInteger.valueOfPow52(p5, p2),
+                "valueOfPow52(" + p5 + "," + p2 + ")");
+    }
+
+    private static void testValueOfPow52() throws Exception {
+        for (int p5 = 0; p5 <= MAX_P5; p5++) {
+            for (int p2 = 0; p2 <= MAX_P2; p2++) {
+                testValueOfPow52(p5, p2);
+            }
+        }
+    }
+
+    private static void testValueOfMulPow52(long value, int p5, int p2) throws Exception {
+        BigInteger bi = BigInteger.valueOf(value & ~LONG_SIGN_MASK);
+        if (value < 0) {
+            bi = bi.setBit(63);
+        }
+        check(biPow52(p5, p2).multiply(bi), FDBigInteger.valueOfMulPow52(value, p5, p2),
+                "valueOfMulPow52(" + Long.toHexString(value) + "." + p5 + "," + p2 + ")");
+    }
+
+    private static void testValueOfMulPow52(long value, int p5) throws Exception {
+        testValueOfMulPow52(value, p5, 0);
+        testValueOfMulPow52(value, p5, 1);
+        testValueOfMulPow52(value, p5, 30);
+        testValueOfMulPow52(value, p5, 31);
+        testValueOfMulPow52(value, p5, 33);
+        testValueOfMulPow52(value, p5, 63);
+    }
+
+    private static void testValueOfMulPow52() throws Exception {
+        for (int p5 = 0; p5 <= MAX_P5; p5++) {
+            testValueOfMulPow52(0xFFFFFFFFL, p5);
+            testValueOfMulPow52(0x123456789AL, p5);
+            testValueOfMulPow52(0x7FFFFFFFFFFFFFFFL, p5);
+            testValueOfMulPow52(0xFFFFFFFFFFF54321L, p5);
+        }
+    }
+
+    private static void testLeftShift(FDBigInteger t, int shift, boolean isImmutable) throws Exception {
+        BigInteger bt = t.toBigInteger();
+        FDBigInteger r = t.leftShift(shift);
+        if ((bt.signum() == 0 || shift == 0 || !isImmutable) && r != t) {
+            throw new Exception("leftShift doesn't reuse its argument");
+        }
+        if (isImmutable) {
+            check(bt, t, "leftShift corrupts its argument");
+        }
+        check(bt.shiftLeft(shift), r, "leftShift returns wrong result");
+    }
+
+    private static void testLeftShift() throws Exception {
+        testLeftShift(IMMUTABLE_ZERO, 0, true);
+        testLeftShift(IMMUTABLE_ZERO, 10, true);
+        testLeftShift(MUTABLE_ZERO, 0, false);
+        testLeftShift(MUTABLE_ZERO, 10, false);
+
+        testLeftShift(IMMUTABLE_MILLION, 0, true);
+        testLeftShift(IMMUTABLE_MILLION, 1, true);
+        testLeftShift(IMMUTABLE_MILLION, 12, true);
+        testLeftShift(IMMUTABLE_MILLION, 13, true);
+        testLeftShift(IMMUTABLE_MILLION, 32, true);
+        testLeftShift(IMMUTABLE_MILLION, 33, true);
+        testLeftShift(IMMUTABLE_MILLION, 44, true);
+        testLeftShift(IMMUTABLE_MILLION, 45, true);
+
+        testLeftShift(genMillion1(), 0, false);
+        testLeftShift(genMillion1(), 1, false);
+        testLeftShift(genMillion1(), 12, false);
+        testLeftShift(genMillion1(), 13, false);
+        testLeftShift(genMillion1(), 25, false);
+        testLeftShift(genMillion1(), 26, false);
+        testLeftShift(genMillion1(), 32, false);
+        testLeftShift(genMillion1(), 33, false);
+        testLeftShift(genMillion1(), 44, false);
+        testLeftShift(genMillion1(), 45, false);
+
+        testLeftShift(genMillion2(), 0, false);
+        testLeftShift(genMillion2(), 1, false);
+        testLeftShift(genMillion2(), 12, false);
+        testLeftShift(genMillion2(), 13, false);
+        testLeftShift(genMillion2(), 25, false);
+        testLeftShift(genMillion2(), 26, false);
+        testLeftShift(genMillion2(), 32, false);
+        testLeftShift(genMillion2(), 33, false);
+        testLeftShift(genMillion2(), 44, false);
+        testLeftShift(genMillion2(), 45, false);
+    }
+
+    private static void testQuoRemIteration(FDBigInteger t, FDBigInteger s) throws Exception {
+        BigInteger bt = t.toBigInteger();
+        BigInteger bs = s.toBigInteger();
+        int q = t.quoRemIteration(s);
+        BigInteger[] qr = bt.divideAndRemainder(bs);
+        if (!BigInteger.valueOf(q).equals(qr[0])) {
+            throw new Exception("quoRemIteration returns incorrect quo");
+        }
+        check(qr[1].multiply(BigInteger.TEN), t, "quoRemIteration returns incorrect rem");
+    }
+
+    private static void testQuoRemIteration() throws Exception {
+        // IMMUTABLE_TEN18 == 0de0b6b3a7640000
+        // q = 0
+        testQuoRemIteration(mutable("00000001", 0), IMMUTABLE_TEN18);
+        testQuoRemIteration(mutable("00000001", 1), IMMUTABLE_TEN18);
+        testQuoRemIteration(mutable("0de0b6b2", 1), IMMUTABLE_TEN18);
+        // q = 1 -> q = 0
+        testQuoRemIteration(mutable("0de0b6b3", 1), IMMUTABLE_TEN18);
+        testQuoRemIteration(mutable("0de0b6b3a763FFFF", 0), IMMUTABLE_TEN18);
+        // q = 1
+        testQuoRemIteration(mutable("0de0b6b3a7640000", 0), IMMUTABLE_TEN18);
+        testQuoRemIteration(mutable("0de0b6b3FFFFFFFF", 0), IMMUTABLE_TEN18);
+        testQuoRemIteration(mutable("8ac72304", 1), IMMUTABLE_TEN18);
+        testQuoRemIteration(mutable("0de0b6b400000000", 0), IMMUTABLE_TEN18);
+        testQuoRemIteration(mutable("8ac72305", 1), IMMUTABLE_TEN18);
+        // q = 18
+        testQuoRemIteration(mutable("FFFFFFFF", 1), IMMUTABLE_TEN18);
+    }
+
+    private static void testCmp(FDBigInteger t, FDBigInteger o) throws Exception {
+        BigInteger bt = t.toBigInteger();
+        BigInteger bo = o.toBigInteger();
+        int cmp = t.cmp(o);
+        int bcmp = bt.compareTo(bo);
+        if (bcmp != cmp) {
+            throw new Exception("cmp returns " + cmp + " expected " + bcmp);
+        }
+        check(bt, t, "cmp corrupts this");
+        check(bo, o, "cmp corrupts other");
+        if (o.cmp(t) != -cmp) {
+            throw new Exception("asymmetrical cmp");
+        }
+        check(bt, t, "cmp corrupts this");
+        check(bo, o, "cmp corrupts other");
+    }
+
+    private static void testCmp() throws Exception {
+        testCmp(mutable("FFFFFFFF", 0), mutable("100000000", 0));
+        testCmp(mutable("FFFFFFFF", 0), mutable("1", 1));
+        testCmp(mutable("5", 0), mutable("6", 0));
+        testCmp(mutable("5", 0), mutable("5", 0));
+        testCmp(mutable("5000000001", 0), mutable("500000001", 0));
+        testCmp(mutable("5000000001", 0), mutable("6", 1));
+        testCmp(mutable("5000000001", 0), mutable("5", 1));
+        testCmp(mutable("5000000000", 0), mutable("5", 1));
+    }
+
+    private static void testCmpPow52(FDBigInteger t, int p5, int p2) throws Exception {
+        FDBigInteger o = FDBigInteger.valueOfPow52(p5, p2);
+        BigInteger bt = t.toBigInteger();
+        BigInteger bo = biPow52(p5, p2);
+        int cmp = t.cmp(o);
+        int bcmp = bt.compareTo(bo);
+        if (bcmp != cmp) {
+            throw new Exception("cmpPow52 returns " + cmp + " expected " + bcmp);
+        }
+        check(bt, t, "cmpPow52 corrupts this");
+        check(bo, o, "cmpPow5 corrupts other");
+    }
+
+    private static void testCmpPow52() throws Exception {
+        testCmpPow52(mutable("00000002", 1), 0, 31);
+        testCmpPow52(mutable("00000002", 1), 0, 32);
+        testCmpPow52(mutable("00000002", 1), 0, 33);
+        testCmpPow52(mutable("00000002", 1), 0, 34);
+        testCmpPow52(mutable("00000002", 1), 0, 64);
+        testCmpPow52(mutable("00000003", 1), 0, 32);
+        testCmpPow52(mutable("00000003", 1), 0, 33);
+        testCmpPow52(mutable("00000003", 1), 0, 34);
+    }
+
+    private static void testAddAndCmp(FDBigInteger t, FDBigInteger x, FDBigInteger y) throws Exception {
+        BigInteger bt = t.toBigInteger();
+        BigInteger bx = x.toBigInteger();
+        BigInteger by = y.toBigInteger();
+        int cmp = t.addAndCmp(x, y);
+        int bcmp = bt.compareTo(bx.add(by));
+        if (bcmp != cmp) {
+            throw new Exception("addAndCmp returns " + cmp + " expected " + bcmp);
+        }
+        check(bt, t, "addAndCmp corrupts this");
+        check(bx, x, "addAndCmp corrupts x");
+        check(by, y, "addAndCmp corrupts y");
+    }
+
+    private static void testAddAndCmp() throws Exception {
+        testAddAndCmp(MUTABLE_ZERO, MUTABLE_ZERO, MUTABLE_ZERO);
+        testAddAndCmp(mutable("00000001", 0), MUTABLE_ZERO, MUTABLE_ZERO);
+        testAddAndCmp(mutable("00000001", 0), mutable("00000001", 0), MUTABLE_ZERO);
+        testAddAndCmp(mutable("00000001", 0), MUTABLE_ZERO, mutable("00000001", 0));
+        testAddAndCmp(mutable("00000001", 0), mutable("00000002", 0), MUTABLE_ZERO);
+        testAddAndCmp(mutable("00000001", 0), MUTABLE_ZERO, mutable("00000002", 0));
+        testAddAndCmp(mutable("00000001", 2), mutable("FFFFFFFF", 0), mutable("FFFFFFFF", 0));
+        testAddAndCmp(mutable("00000001", 0), mutable("00000001", 1), mutable("00000001", 0));
+
+        testAddAndCmp(mutable("00000001", 2), mutable("0F0F0F0F80000000", 1), mutable("F0F0F0F080000000", 1));
+        testAddAndCmp(mutable("00000001", 2), mutable("0F0F0F0E80000000", 1), mutable("F0F0F0F080000000", 1));
+
+        testAddAndCmp(mutable("00000002", 1), mutable("0000000180000000", 1), mutable("0000000280000000", 1));
+        testAddAndCmp(mutable("00000003", 1), mutable("0000000180000000", 1), mutable("0000000280000000", 1));
+        testAddAndCmp(mutable("00000004", 1), mutable("0000000180000000", 1), mutable("0000000280000000", 1));
+        testAddAndCmp(mutable("00000005", 1), mutable("0000000180000000", 1), mutable("0000000280000000", 1));
+
+        testAddAndCmp(mutable("00000001", 2), mutable("8000000000000000", 0), mutable("8000000000000000", 0));
+        testAddAndCmp(mutable("00000001", 2), mutable("8000000000000000", 0), mutable("8000000000000001", 0));
+        testAddAndCmp(mutable("00000002", 2), mutable("8000000000000000", 0), mutable("8000000000000000", 0));
+        testAddAndCmp(mutable("00000003", 2), mutable("8000000000000000", 0), mutable("8000000000000000", 0));
+    }
+
+    private static void testMultBy10(FDBigInteger t, boolean isImmutable) throws Exception {
+        BigInteger bt = t.toBigInteger();
+        FDBigInteger r = t.multBy10();
+        if ((bt.signum() == 0 || !isImmutable) && r != t) {
+            throw new Exception("multBy10 of doesn't reuse its argument");
+        }
+        if (isImmutable) {
+            check(bt, t, "multBy10 corrupts its argument");
+        }
+        check(bt.multiply(BigInteger.TEN), r, "multBy10 returns wrong result");
+    }
+
+    private static void testMultBy10() throws Exception {
+        for (int p5 = 0; p5 <= MAX_P5; p5++) {
+            for (int p2 = 0; p2 <= MAX_P2; p2++) {
+                // This strange way of creating a value ensures that it is mutable.
+                FDBigInteger value = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5, p2);
+                testMultBy10(value, false);
+                value.makeImmutable();
+                testMultBy10(value, true);
+            }
+        }
+    }
+
+    private static void testMultByPow52(FDBigInteger t, int p5, int p2) throws Exception {
+        BigInteger bt = t.toBigInteger();
+        FDBigInteger r = t.multByPow52(p5, p2);
+        if (bt.signum() == 0 && r != t) {
+            throw new Exception("multByPow52 of doesn't reuse its argument");
+        }
+        check(bt.multiply(biPow52(p5, p2)), r, "multByPow52 returns wrong result");
+    }
+
+    private static void testMultByPow52() throws Exception {
+        for (int p5 = 0; p5 <= MAX_P5; p5++) {
+            for (int p2 = 0; p2 <= MAX_P2; p2++) {
+                // This strange way of creating a value ensures that it is mutable.
+                FDBigInteger value = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5, p2);
+                testMultByPow52(value, p5, p2);
+            }
+        }
+    }
+
+    private static void testLeftInplaceSub(FDBigInteger left, FDBigInteger right, boolean isImmutable) throws Exception {
+        BigInteger biLeft = left.toBigInteger();
+        BigInteger biRight = right.toBigInteger();
+        FDBigInteger diff = left.leftInplaceSub(right);
+        if (!isImmutable && diff != left) {
+            throw new Exception("leftInplaceSub of doesn't reuse its argument");
+        }
+        if (isImmutable) {
+            check(biLeft, left, "leftInplaceSub corrupts its left immutable argument");
+        }
+        check(biRight, right, "leftInplaceSub corrupts its right argument");
+        check(biLeft.subtract(biRight), diff, "leftInplaceSub returns wrong result");
+    }
+
+    private static void testLeftInplaceSub() throws Exception {
+        for (int p5 = 0; p5 <= MAX_P5; p5++) {
+            for (int p2 = 0; p2 <= MAX_P2; p2++) {
+//                for (int p5r = 0; p5r <= p5; p5r += 10) {
+//                    for (int p2r = 0; p2r <= p2; p2r += 10) {
+                for (int p5r = 0; p5r <= p5; p5r++) {
+                    for (int p2r = 0; p2r <= p2; p2r++) {
+                        // This strange way of creating a value ensures that it is mutable.
+                        FDBigInteger left = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5, p2);
+                        FDBigInteger right = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5r, p2r);
+                        testLeftInplaceSub(left, right, false);
+                        left = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5, p2);
+                        left.makeImmutable();
+                        testLeftInplaceSub(left, right, true);
+                    }
+                }
+            }
+        }
+    }
+
+    private static void testRightInplaceSub(FDBigInteger left, FDBigInteger right, boolean isImmutable) throws Exception {
+        BigInteger biLeft = left.toBigInteger();
+        BigInteger biRight = right.toBigInteger();
+        FDBigInteger diff = left.rightInplaceSub(right);
+        if (!isImmutable && diff != right) {
+            throw new Exception("rightInplaceSub of doesn't reuse its argument");
+        }
+        check(biLeft, left, "leftInplaceSub corrupts its left argument");
+        if (isImmutable) {
+            check(biRight, right, "leftInplaceSub corrupts its right immutable argument");
+        }
+        try {
+            check(biLeft.subtract(biRight), diff, "rightInplaceSub returns wrong result");
+        } catch (Exception e) {
+            System.out.println(biLeft+" - "+biRight+" = "+biLeft.subtract(biRight));
+            throw e;
+        }
+    }
+
+    private static void testRightInplaceSub() throws Exception {
+        for (int p5 = 0; p5 <= MAX_P5; p5++) {
+            for (int p2 = 0; p2 <= MAX_P2; p2++) {
+//                for (int p5r = 0; p5r <= p5; p5r += 10) {
+//                    for (int p2r = 0; p2r <= p2; p2r += 10) {
+                for (int p5r = 0; p5r <= p5; p5r++) {
+                    for (int p2r = 0; p2r <= p2; p2r++) {
+                        // This strange way of creating a value ensures that it is mutable.
+                        FDBigInteger left = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5, p2);
+                        FDBigInteger right = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5r, p2r);
+                        testRightInplaceSub(left, right, false);
+                        right = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5r, p2r);
+                        right.makeImmutable();
+                        testRightInplaceSub(left, right, true);
+                    }
+                }
+            }
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        testValueOfPow52();
+        testValueOfMulPow52();
+        testLeftShift();
+        testQuoRemIteration();
+        testCmp();
+        testCmpPow52();
+        testAddAndCmp();
+        // Uncomment the following for more comprehensize but slow testing.
+        // testLeftInplaceSub();
+        // testMultBy10();
+        // testMultByPow52();
+        // testRightInplaceSub();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/internal/math/FloatingDecimal/TestFloatingDecimal.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.util.Random;
+import jdk.internal.math.FloatingDecimal;
+
+/*
+OldFloatingDecimalForTest
+
+public class OldFloatingDecimalForTest {
+  public boolean digitsRoundedUp();
+  public OldFloatingDecimalForTest(double);
+  public OldFloatingDecimalForTest(float);
+  public boolean decimalDigitsExact();
+  public java.lang.String toString();
+  public java.lang.String toJavaFormatString();
+  public void appendTo(java.lang.Appendable);
+  public static OldFloatingDecimalForTest readJavaFormatString(java.lang.String) throws java.lang.NumberFormatException;
+  public strictfp double doubleValue();
+  public strictfp float floatValue();
+}
+
+jdk.internal.math.FloatingDecimal
+
+public class jdk.internal.math.FloatingDecimal {
+  public jdk.internal.math.FloatingDecimal();
+  public static java.lang.String toJavaFormatString(double);
+  public static java.lang.String toJavaFormatString(float);
+  public static void appendTo(double, java.lang.Appendable);
+  public static void appendTo(float, java.lang.Appendable);
+  public static double parseDouble(java.lang.String) throws java.lang.NumberFormatException;
+  public static float parseFloat(java.lang.String) throws java.lang.NumberFormatException;
+  public static jdk.internal.math.FloatingDecimal$AbstractD2ABuffer getD2ABuffer(double);
+}
+*/
+
+/**
+ * @test
+ * @bug 7032154
+ * @summary unit tests of FloatingDecimal
+ * @modules java.base/jdk.internal.math
+ * @library /java/lang/Math
+ * @build DoubleConsts FloatConsts
+ * @run main TestFloatingDecimal
+ * @author Brian Burkhalter
+ * @key randomness
+ */
+public class TestFloatingDecimal {
+    private static enum ResultType {
+        RESULT_EXCEPTION,
+        RESULT_PRINT
+    }
+
+    private static final ResultType RESULT_TYPE = ResultType.RESULT_PRINT;
+    private static final int NUM_RANDOM_TESTS = 100000;
+
+    private static final Random RANDOM = new Random();
+
+    private static void result(String message) {
+        switch (RESULT_TYPE) {
+            case RESULT_EXCEPTION:
+                throw new RuntimeException(message);
+            case RESULT_PRINT:
+                System.err.println(message);
+                break;
+            default:
+                assert false;
+        }
+    }
+
+    private static int check(String test, Object expected, Object actual) {
+        int failures = 0;
+        if(!actual.equals(expected)) {
+            failures++;
+            result("Test "+test+" expected "+expected+" but obtained "+actual);
+        }
+        return failures;
+    }
+
+    private static int testAppendToDouble() {
+        System.out.println("  testAppendToDouble");
+        int failures = 0;
+
+        for(int i = 0; i < NUM_RANDOM_TESTS; i++) {
+            double[] d = new double[] {
+                RANDOM.nextLong(),
+                RANDOM.nextGaussian(),
+                RANDOM.nextDouble()*Double.MAX_VALUE
+            };
+            for(int j = 0; j < d.length; j++) {
+                OldFloatingDecimalForTest ofd = new OldFloatingDecimalForTest(d[j]);
+                StringBuilder sb = new StringBuilder();
+                ofd.appendTo(sb);
+                String oldString = sb.toString();
+                sb = new StringBuilder();
+                FloatingDecimal.appendTo(d[j], sb);
+                String newString = sb.toString();
+                failures += check("testAppendToDouble", oldString, newString);
+            }
+        }
+
+        return failures;
+    }
+
+    private static int testAppendToFloat() {
+        System.out.println("  testAppendToFloat");
+        int failures = 0;
+
+        for(int i = 0; i < NUM_RANDOM_TESTS; i++) {
+            float[] f = new float[] {
+                RANDOM.nextLong(),
+                (float)RANDOM.nextGaussian(),
+                RANDOM.nextFloat()*Float.MAX_VALUE
+            };
+            for(int j = 0; j < f.length; j++) {
+                OldFloatingDecimalForTest ofd = new OldFloatingDecimalForTest(f[j]);
+                StringBuilder sb = new StringBuilder();
+                ofd.appendTo(sb);
+                String oldString = sb.toString();
+                sb = new StringBuilder();
+                FloatingDecimal.appendTo(f[j], sb);
+                String newString = sb.toString();
+                failures += check("testAppendToFloat", oldString, newString);
+            }
+        }
+
+        return failures;
+    }
+
+    private static int testAppendTo() {
+        System.out.println("testAppendTo");
+        int failures = 0;
+
+        failures += testAppendToDouble();
+        failures += testAppendToFloat();
+
+        return failures;
+    }
+
+    private static int testParseDouble() {
+        System.out.println("  testParseDouble");
+        int failures = 0;
+
+        for(int i = 0; i < NUM_RANDOM_TESTS; i++) {
+            double[] d = new double[] {
+                RANDOM.nextLong(),
+                RANDOM.nextGaussian(),
+                RANDOM.nextDouble()*Double.MAX_VALUE
+            };
+            for(int j = 0; j < d.length; j++) {
+                OldFloatingDecimalForTest ofd = new OldFloatingDecimalForTest(d[j]);
+                String javaFormatString = ofd.toJavaFormatString();
+                ofd = OldFloatingDecimalForTest.readJavaFormatString(javaFormatString);
+                double oldDouble = ofd.doubleValue();
+                double newDouble = FloatingDecimal.parseDouble(javaFormatString);
+                failures += check("testParseDouble", oldDouble, newDouble);
+            }
+        }
+
+        return failures;
+    }
+
+    private static int testParseFloat() {
+        System.out.println("  testParseFloat");
+        int failures = 0;
+
+        for(int i = 0; i < NUM_RANDOM_TESTS; i++) {
+            float[] f = new float[] {
+                RANDOM.nextInt(),
+                (float)RANDOM.nextGaussian(),
+                RANDOM.nextFloat()*Float.MAX_VALUE
+            };
+            for(int j = 0; j < f.length; j++) {
+                OldFloatingDecimalForTest ofd = new OldFloatingDecimalForTest(f[j]);
+                String javaFormatString = ofd.toJavaFormatString();
+                ofd = OldFloatingDecimalForTest.readJavaFormatString(javaFormatString);
+                float oldFloat = ofd.floatValue();
+                float newFloat = FloatingDecimal.parseFloat(javaFormatString);
+                failures += check("testParseFloat", oldFloat, newFloat);
+            }
+        }
+
+        return failures;
+    }
+
+    private static int testParse() {
+        System.out.println("testParse");
+        int failures = 0;
+
+        failures += testParseDouble();
+        failures += testParseFloat();
+
+        return failures;
+    }
+
+    private static int testToJavaFormatStringDoubleFixed() {
+        System.out.println("    testToJavaFormatStringDoubleFixed");
+        int failures = 0;
+
+        double[] d = new double [] {
+            -5.9522650387500933e18, // dtoa() fast path
+            0.872989018674569,      // dtoa() fast iterative - long
+            1.1317400099603851e308  // dtoa() slow iterative
+        };
+
+        for(int i = 0; i < d.length; i++) {
+            OldFloatingDecimalForTest ofd = new OldFloatingDecimalForTest(d[i]);
+            failures += check("testToJavaFormatStringDoubleFixed", ofd.toJavaFormatString(), FloatingDecimal.toJavaFormatString(d[i]));
+        }
+
+        return failures;
+    }
+
+    private static int testToJavaFormatStringDoubleRandom() {
+        System.out.println("    testToJavaFormatStringDoubleRandom");
+        int failures = 0;
+
+        for(int i = 0; i < NUM_RANDOM_TESTS; i++) {
+            double[] d = new double[] {
+                RANDOM.nextLong(),
+                RANDOM.nextGaussian(),
+                RANDOM.nextDouble()*Double.MAX_VALUE
+            };
+            for(int j = 0; j < d.length; j++) {
+                OldFloatingDecimalForTest ofd = new OldFloatingDecimalForTest(d[j]);
+                failures += check("testToJavaFormatStringDoubleRandom", ofd.toJavaFormatString(), FloatingDecimal.toJavaFormatString(d[j]));
+            }
+        }
+
+        return failures;
+    }
+
+    private static int testToJavaFormatStringDouble() {
+        System.out.println("  testToJavaFormatStringDouble");
+        int failures = 0;
+        failures += testToJavaFormatStringDoubleFixed();
+        failures += testToJavaFormatStringDoubleRandom();
+        return failures;
+    }
+
+    private static int testToJavaFormatStringFloatFixed() {
+        System.out.println("    testToJavaFormatStringFloatFixed");
+        int failures = 0;
+
+        float[] f = new float[] {
+            -9.8784166e8f, // dtoa() fast path
+            0.70443946f,   // dtoa() fast iterative - int
+            1.8254228e37f  // dtoa() slow iterative
+        };
+
+        for(int i = 0; i < f.length; i++) {
+            OldFloatingDecimalForTest ofd = new OldFloatingDecimalForTest(f[i]);
+            failures += check("testToJavaFormatStringFloatFixed", ofd.toJavaFormatString(), FloatingDecimal.toJavaFormatString(f[i]));
+        }
+
+        return failures;
+    }
+
+    private static int testToJavaFormatStringFloatRandom() {
+        System.out.println("    testToJavaFormatStringFloatRandom");
+        int failures = 0;
+
+        for(int i = 0; i < NUM_RANDOM_TESTS; i++) {
+            float[] f = new float[] {
+                RANDOM.nextInt(),
+                (float)RANDOM.nextGaussian(),
+                RANDOM.nextFloat()*Float.MAX_VALUE
+            };
+            for(int j = 0; j < f.length; j++) {
+                OldFloatingDecimalForTest ofd = new OldFloatingDecimalForTest(f[j]);
+                failures += check("testToJavaFormatStringFloatRandom", ofd.toJavaFormatString(), FloatingDecimal.toJavaFormatString(f[j]));
+            }
+        }
+
+        return failures;
+    }
+
+    private static int testToJavaFormatStringFloat() {
+        System.out.println("  testToJavaFormatStringFloat");
+        int failures = 0;
+
+        failures += testToJavaFormatStringFloatFixed();
+        failures += testToJavaFormatStringFloatRandom();
+
+        return failures;
+    }
+
+    private static int testToJavaFormatString() {
+        System.out.println("testToJavaFormatString");
+        int failures = 0;
+
+        failures += testToJavaFormatStringDouble();
+        failures += testToJavaFormatStringFloat();
+
+        return failures;
+    }
+
+    public static void main(String[] args) {
+        int failures = 0;
+
+        failures += testAppendTo();
+        failures += testParse();
+        failures += testToJavaFormatString();
+
+        if (failures != 0) {
+            throw new RuntimeException("" + failures + " failures while testing FloatingDecimal");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/nio/zipfs/MultiReleaseJarTest.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8144355
+ * @summary Test aliasing additions to ZipFileSystem for multi-release jar files
+ * @library /lib/testlibrary/java/util/jar
+ * @build Compiler JarBuilder CreateMultiReleaseTestJars
+ * @run testng MultiReleaseJarTest
+ */
+
+import java.io.IOException;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.net.URI;
+import java.nio.file.*;
+import java.util.HashMap;
+import java.util.Map;
+
+import static sun.misc.Version.jdkMajorVersion;
+
+import org.testng.Assert;
+import org.testng.annotations.*;
+
+public class MultiReleaseJarTest {
+    final private String userdir = System.getProperty("user.dir",".");
+    final private Map<String,String> stringEnv = new HashMap<>();
+    final private Map<String,Integer> integerEnv = new HashMap<>();
+    final private String className = "version.Version";
+    final private MethodType mt = MethodType.methodType(int.class);
+
+    private String entryName;
+    private URI uvuri;
+    private URI mruri;
+    private URI smruri;
+
+    @BeforeClass
+    public void initialize() throws Exception {
+        CreateMultiReleaseTestJars creator =  new CreateMultiReleaseTestJars();
+        creator.compileEntries();
+        creator.buildUnversionedJar();
+        creator.buildMultiReleaseJar();
+        creator.buildShortMultiReleaseJar();
+        String ssp = Paths.get(userdir, "unversioned.jar").toUri().toString();
+        uvuri = new URI("jar", ssp , null);
+        ssp = Paths.get(userdir, "multi-release.jar").toUri().toString();
+        mruri = new URI("jar", ssp, null);
+        ssp = Paths.get(userdir, "short-multi-release.jar").toUri().toString();
+        smruri = new URI("jar", ssp, null);
+        entryName = className.replace('.', '/') + ".class";
+    }
+
+    public void close() throws IOException {
+        Files.delete(Paths.get(userdir, "unversioned.jar"));
+        Files.delete(Paths.get(userdir, "multi-release.jar"));
+        Files.delete(Paths.get(userdir, "short-multi-release.jar"));
+    }
+
+    @DataProvider(name="strings")
+    public Object[][] createStrings() {
+        return new Object[][]{
+                {"runtime", jdkMajorVersion()},
+                {"-20", 8},
+                {"0", 8},
+                {"8", 8},
+                {"9", 9},
+                {"10", 10},
+                {"11", 10},
+                {"50", 10}
+        };
+    }
+
+    @DataProvider(name="integers")
+    public Object[][] createIntegers() {
+        return new Object[][] {
+                {new Integer(-5), 8},
+                {new Integer(0), 8},
+                {new Integer(8), 8},
+                {new Integer(9), 9},
+                {new Integer(10), 10},
+                {new Integer(11), 10},
+                {new Integer(100), 10}
+        };
+    }
+
+    // Not the best test but all I can do since ZipFileSystem and JarFileSystem
+    // are not public, so I can't use (fs instanceof ...)
+    @Test
+    public void testNewFileSystem() throws Exception {
+        Map<String,String> env = new HashMap<>();
+        // no configuration, treat multi-release jar as unversioned
+        try (FileSystem fs = FileSystems.newFileSystem(mruri, env)) {
+            Assert.assertTrue(readAndCompare(fs, 8));
+        }
+        env.put("multi-release", "runtime");
+        // a configuration and jar file is multi-release
+        try (FileSystem fs = FileSystems.newFileSystem(mruri, env)) {
+            Assert.assertTrue(readAndCompare(fs, jdkMajorVersion()));
+        }
+        // a configuration but jar file is unversioned
+        try (FileSystem fs = FileSystems.newFileSystem(uvuri, env)) {
+            Assert.assertTrue(readAndCompare(fs, 8));
+        }
+    }
+
+    private boolean readAndCompare(FileSystem fs, int expected) throws IOException {
+        Path path = fs.getPath("version/Version.java");
+        String src = new String(Files.readAllBytes(path));
+        return src.contains("return " + expected);
+    }
+
+    @Test(dataProvider="strings")
+    public void testStrings(String value, int expected) throws Throwable {
+        stringEnv.put("multi-release", value);
+        runTest(stringEnv, expected);
+    }
+
+    @Test(dataProvider="integers")
+    public void testIntegers(Integer value, int expected) throws Throwable {
+        integerEnv.put("multi-release", value);
+        runTest(integerEnv, expected);
+    }
+
+    @Test
+    public void testShortJar() throws Throwable {
+        integerEnv.put("multi-release", Integer.valueOf(10));
+        runTest(smruri, integerEnv, 10);
+        integerEnv.put("multi-release", Integer.valueOf(9));
+        runTest(smruri, integerEnv, 8);
+    }
+
+    private void runTest(Map<String,?> env, int expected) throws Throwable {
+        runTest(mruri, env, expected);
+    }
+
+    private void runTest(URI uri, Map<String,?> env, int expected) throws Throwable {
+        try (FileSystem fs = FileSystems.newFileSystem(uri, env)) {
+            Path version = fs.getPath(entryName);
+            byte [] bytes = Files.readAllBytes(version);
+            Class<?> vcls = (new ByteArrayClassLoader(fs)).defineClass(className, bytes);
+            MethodHandle mh = MethodHandles.lookup().findVirtual(vcls, "getVersion", mt);
+            Assert.assertEquals((int)mh.invoke(vcls.newInstance()), expected);
+        }
+    }
+
+    private static class ByteArrayClassLoader extends ClassLoader {
+        final private FileSystem fs;
+
+        ByteArrayClassLoader(FileSystem fs) {
+            super(null);
+            this.fs = fs;
+        }
+
+        @Override
+        public Class<?> loadClass(String name) throws ClassNotFoundException {
+            try {
+                return super.loadClass(name);
+            } catch (ClassNotFoundException x) {}
+            Path cls = fs.getPath(name.replace('.', '/') + ".class");
+            try {
+                byte[] bytes = Files.readAllBytes(cls);
+                return defineClass(name, bytes);
+            } catch (IOException x) {
+                throw new ClassNotFoundException(x.getMessage());
+            }
+        }
+
+        public Class<?> defineClass(String name, byte[] bytes) throws ClassNotFoundException {
+            if (bytes == null) throw new ClassNotFoundException("No bytes for " + name);
+            return defineClass(name, bytes, 0, bytes.length);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/lib/testlibrary/java/util/jar/Compiler.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import javax.tools.*;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+class Compiler {
+    final private Map<String,String> input;
+    private List<String> options;
+
+    Compiler(Map<String,String> input) {
+        this.input = input;
+    }
+
+    Compiler setRelease(int release) {
+        // Setting the -release option does not work for some reason
+        // so do it the old fashioned way
+        // options = Arrays.asList("-release", String.valueOf(release));
+        String target = String.valueOf(release);
+        options = Arrays.asList("-source", target, "-target", target);
+        return this;
+    }
+
+    Map<String,byte[]> compile() {
+        List<SourceFileObject> cunits = createCompilationUnits();
+        Map<String,ClassFileObject> cfos = createClassFileObjects();
+        JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
+        JavaFileManager jfm = new CustomFileManager(jc.getStandardFileManager(null, null, null), cfos);
+        jc.getTask(null, jfm, null, options, null, cunits).call();
+        return createOutput(cfos);
+    }
+
+    private List<SourceFileObject> createCompilationUnits() {
+        return input.entrySet().stream()
+                .map(e -> new SourceFileObject(e.getKey(), e.getValue())).collect(Collectors.toList());
+    }
+
+    private Map<String,ClassFileObject> createClassFileObjects() {
+        return input.keySet().stream()
+                .collect(Collectors.toMap(k -> k, k -> new ClassFileObject(k)));
+    }
+
+    private Map<String,byte[]> createOutput(Map<String,ClassFileObject> cfos) {
+        return cfos.keySet().stream().collect(Collectors.toMap(k -> k, k -> cfos.get(k).getBytes()));
+    }
+
+    private static class SourceFileObject extends SimpleJavaFileObject {
+        private final String source;
+
+        SourceFileObject(String name, String source) {
+            super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
+            this.source = source;
+        }
+
+        @Override
+        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+            return source;
+        }
+    }
+
+    private static class ClassFileObject extends SimpleJavaFileObject {
+        private final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+        ClassFileObject(String className) {
+            super(URI.create(className), Kind.CLASS);
+        }
+
+        @Override
+        public OutputStream openOutputStream() throws IOException {
+            return baos;
+        }
+
+        public byte[] getBytes() {
+            return baos.toByteArray();
+        }
+    }
+
+    private static class CustomFileManager extends ForwardingJavaFileManager<JavaFileManager> {
+        private final Map<String,ClassFileObject> cfos;
+
+        CustomFileManager(JavaFileManager jfm, Map<String,ClassFileObject> cfos) {
+            super(jfm);
+            this.cfos = cfos;
+        }
+
+        @Override
+        public JavaFileObject getJavaFileForOutput(JavaFileManager.Location loc, String name,
+                                                   JavaFileObject.Kind kind, FileObject sibling) throws IOException {
+            ClassFileObject cfo = cfos.get(name);
+            return cfo;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/lib/testlibrary/java/util/jar/CreateMultiReleaseTestJars.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.Map;
+
+public class CreateMultiReleaseTestJars {
+    final private String main =
+            "package version;\n\n"
+            + "public class Main {\n"
+            + "    public static void main(String[] args) {\n"
+            + "        Version v = new Version();\n"
+            + "        System.out.println(\"I am running on version \" + v.getVersion());\n"
+            + "    }\n"
+            + "}\n";
+    final private String java8 =
+            "package version;\n\n"
+            + "public class Version {\n"
+            + "    public int getVersion() {\n"
+            + "        return 8;\n"
+            + "    }\n"
+            + "}\n";
+    final private String java9 =
+            "package version;\n\n"
+            + "public class Version {\n"
+            + "    public int getVersion() {\n"
+            + "        int version = (new PackagePrivate()).getVersion();\n"
+            + "        if (version == 9) return 9;\n"  // strange I know, but easy to test
+            + "        return version;\n"
+            + "    }\n"
+            + "}\n";
+    final private String ppjava9 =
+            "package version;\n\n"
+            + "class PackagePrivate {\n"
+            + "    int getVersion() {\n"
+            + "        return 9;\n"
+            + "    }\n"
+            + "}\n";
+    final private String java10 = java8.replace("8", "10");
+    final String readme8 = "This is the root readme file";
+    final String readme9 = "This is the version nine readme file";
+    final String readme10 = "This is the version ten readme file";
+    private Map<String,byte[]> rootClasses;
+    private Map<String,byte[]> version9Classes;
+    private Map<String,byte[]> version10Classes;
+
+    public void buildUnversionedJar() throws IOException {
+        JarBuilder jb = new JarBuilder("unversioned.jar");
+        jb.addEntry("README", readme8.getBytes());
+        jb.addEntry("version/Main.java", main.getBytes());
+        jb.addEntry("version/Main.class", rootClasses.get("version.Main"));
+        jb.addEntry("version/Version.java", java8.getBytes());
+        jb.addEntry("version/Version.class", rootClasses.get("version.Version"));
+        jb.build();
+    }
+
+    public void buildMultiReleaseJar() throws IOException {
+        JarBuilder jb = new JarBuilder("multi-release.jar");
+        jb.addAttribute("Multi-Release", "true");
+        jb.addEntry("README", readme8.getBytes());
+        jb.addEntry("version/Main.java", main.getBytes());
+        jb.addEntry("version/Main.class", rootClasses.get("version.Main"));
+        jb.addEntry("version/Version.java", java8.getBytes());
+        jb.addEntry("version/Version.class", rootClasses.get("version.Version"));
+        jb.addEntry("META-INF/versions/9/README", readme9.getBytes());
+        jb.addEntry("META-INF/versions/9/version/Version.java", java9.getBytes());
+        jb.addEntry("META-INF/versions/9/version/PackagePrivate.java", ppjava9.getBytes());
+        jb.addEntry("META-INF/versions/9/version/Version.class", version9Classes.get("version.Version"));
+        jb.addEntry("META-INF/versions/9/version/PackagePrivate.class", version9Classes.get("version.PackagePrivate"));
+        jb.addEntry("META-INF/versions/10/README", readme10.getBytes());
+        jb.addEntry("META-INF/versions/10/version/Version.java", java10.getBytes());
+        jb.addEntry("META-INF/versions/10/version/Version.class", version10Classes.get("version.Version"));
+        jb.build();
+    }
+
+    public void buildShortMultiReleaseJar() throws IOException {
+        JarBuilder jb = new JarBuilder("short-multi-release.jar");
+        jb.addAttribute("Multi-Release", "true");
+        jb.addEntry("README", readme8.getBytes());
+        jb.addEntry("version/Main.java", main.getBytes());
+        jb.addEntry("version/Main.class", rootClasses.get("version.Main"));
+        jb.addEntry("version/Version.java", java8.getBytes());
+        jb.addEntry("version/Version.class", rootClasses.get("version.Version"));
+        jb.addEntry("META-INF/versions/9/README", readme9.getBytes());
+        jb.addEntry("META-INF/versions/9/version/Version.java", java9.getBytes());
+        jb.addEntry("META-INF/versions/9/version/PackagePrivate.java", ppjava9.getBytes());
+        // no entry for META-INF/versions/9/version/Version.class
+        jb.addEntry("META-INF/versions/9/version/PackagePrivate.class", version9Classes.get("version.PackagePrivate"));
+        jb.addEntry("META-INF/versions/10/README", readme10.getBytes());
+        jb.addEntry("META-INF/versions/10/version/Version.java", java10.getBytes());
+        jb.addEntry("META-INF/versions/10/version/Version.class", version10Classes.get("version.Version"));
+        jb.build();
+    }
+
+    public void buildSignedMultiReleaseJar() throws Exception {
+        String testsrc = System.getProperty("test.src",".");
+        String testdir = findTestDir(testsrc);
+        String keystore = testdir + "/sun/security/tools/jarsigner/JarSigning.keystore";
+        String[] jsArgs = {
+                "-keystore", keystore,
+                "-storepass", "bbbbbb",
+                "-signedJar", "signed-multi-release.jar",
+                "multi-release.jar", "b"
+        };
+        sun.security.tools.jarsigner.Main.main(jsArgs);
+
+    }
+
+    String findTestDir(String dir) throws IOException {
+        Path path = Paths.get(dir).toAbsolutePath();
+        while (path != null && !path.endsWith("test")) {
+            path = path.getParent();
+        }
+        if (path == null) {
+            throw new IllegalArgumentException(dir + " is not in a test directory");
+        }
+        if (!Files.isDirectory(path)) {
+            throw new IOException(path.toString() + " is not a directory");
+        }
+        return path.toString();
+    }
+
+    void compileEntries() {
+        Map<String,String> input = new HashMap<>();
+        input.put("version.Main", main);
+        input.put("version.Version", java8);
+        rootClasses = (new Compiler(input)).setRelease(8).compile();
+        input.clear();
+        input.put("version.Version", java9);
+        input.put("version.PackagePrivate", ppjava9);
+        version9Classes = (new Compiler(input)).setRelease(9).compile();
+        input.clear();
+        input.put("version.Version", java10);
+        version10Classes = (new Compiler(input)).setRelease(9).compile();  // fixme in JDK 10
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/lib/testlibrary/java/util/jar/JarBuilder.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+
+public class JarBuilder {
+    final private String name;
+    final private Attributes attributes = new Attributes();
+    final private List<Entry> entries = new ArrayList<>();
+
+    public JarBuilder(String name) {
+        this.name = name;
+        attributes.putValue("Manifest-Version", "1.0");
+        attributes.putValue("Created-By", "1.9.0-internal (Oracle Corporation)");
+    }
+
+    public JarBuilder addAttribute(String name, String value) {
+        attributes.putValue(name, value);
+        return this;
+    }
+
+    public JarBuilder addEntry(String name, byte[] bytes) {
+        entries.add(new Entry(name, bytes));
+        return this;
+    }
+
+    public void build() throws IOException {
+        try (OutputStream os = Files.newOutputStream(Paths.get(name));
+             JarOutputStream jos = new JarOutputStream(os)) {
+            JarEntry me = new JarEntry("META-INF/MANIFEST.MF");
+            jos.putNextEntry(me);
+            Manifest manifest = new Manifest();
+            manifest.getMainAttributes().putAll(attributes);
+            manifest.write(jos);
+            jos.closeEntry();
+            entries.forEach(e -> {
+                JarEntry je = new JarEntry(e.name);
+                try {
+                    jos.putNextEntry(je);
+                    jos.write(e.bytes);
+                    jos.closeEntry();
+                } catch (IOException iox) {
+                    throw new RuntimeException(iox);
+                }
+            });
+        } catch (RuntimeException x) {
+            Throwable t = x.getCause();
+            if (t instanceof IOException) {
+                IOException iox = (IOException)t;
+                throw iox;
+            }
+            throw x;
+        }
+    }
+
+    private static class Entry {
+        String name;
+        byte[] bytes;
+
+        Entry(String name, byte[] bytes) {
+            this.name = name;
+            this.bytes = bytes;
+        }
+    }
+
+    public static void main(String[] args) throws IOException {
+        JarBuilder jb = new JarBuilder("version.jar");
+        jb.addAttribute("Multi-Release", "true");
+        String s = "something to say";
+        byte[] bytes = s.getBytes();
+        jb.addEntry("version/Version.class", bytes);
+        jb.addEntry("README", bytes);
+        jb.addEntry("version/Version.java", bytes);
+        jb.build();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/java2d/marlin/ArrayCacheSizeTest.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import sun.java2d.marlin.ArrayCache;
+
+/**
+ * @test
+ * @bug 8144445
+ * @summary Check the ArrayCache getNewLargeSize() method
+ * @run main ArrayCacheSizeTest
+ */
+public class ArrayCacheSizeTest {
+
+    public static void main(String[] args) {
+        testNewSize();
+        testNewLargeSize();
+    }
+
+    private static void testNewSize() {
+        testNewSize(0, 1);
+        testNewSize(0, 100000);
+
+        testNewSize(4096, 4097);
+        testNewSize(4096 * 16, 4096 * 16 + 1);
+
+        testNewSize(4096 * 4096 * 4, 4096 * 4096 * 4 + 1);
+
+        testNewSize(4096 * 4096 * 4, Integer.MAX_VALUE);
+
+        testNewSize(Integer.MAX_VALUE - 1000, Integer.MAX_VALUE);
+
+        testNewSizeExpectAIOB(Integer.MAX_VALUE - 1000, Integer.MAX_VALUE + 1);
+        testNewSizeExpectAIOB(1, -1);
+        testNewSizeExpectAIOB(Integer.MAX_VALUE, -1);
+    }
+
+    private static void testNewSizeExpectAIOB(final int curSize,
+                                              final int needSize) {
+        try {
+            testNewSize(curSize, needSize);
+            throw new RuntimeException("ArrayIndexOutOfBoundsException not thrown");
+        } catch (ArrayIndexOutOfBoundsException aiobe) {
+            System.out.println("ArrayIndexOutOfBoundsException expected.");
+        } catch (RuntimeException re) {
+            throw re;
+        } catch (Throwable th) {
+            throw new RuntimeException("Unexpected exception", th);
+        }
+    }
+
+    private static void testNewSize(final int curSize,
+                                    final int needSize) {
+
+        int size = ArrayCache.getNewSize(curSize, needSize);
+
+        System.out.println("getNewSize(" + curSize + ", " + needSize
+            + ") = " + size);
+
+        if (size < 0 || size < needSize) {
+            throw new IllegalStateException("Invalid getNewSize("
+                + curSize + ", " + needSize + ") = " + size + " !");
+        }
+    }
+
+    private static void testNewLargeSize() {
+        testNewLargeSize(0, 1);
+        testNewLargeSize(0, 100000);
+
+        testNewLargeSize(4096, 4097);
+        testNewLargeSize(4096 * 16, 4096 * 16 + 1);
+
+        testNewLargeSize(4096 * 4096 * 4, 4096 * 4096 * 4 + 1);
+
+        testNewLargeSize(4096 * 4096 * 4, Integer.MAX_VALUE);
+
+        testNewLargeSize(Integer.MAX_VALUE - 1000, Integer.MAX_VALUE);
+
+        testNewLargeSizeExpectAIOB(Integer.MAX_VALUE - 1000, Integer.MAX_VALUE + 1L);
+        testNewLargeSizeExpectAIOB(1, -1L);
+        testNewLargeSizeExpectAIOB(Integer.MAX_VALUE, -1L);
+    }
+
+    private static void testNewLargeSizeExpectAIOB(final long curSize,
+                                                   final long needSize) {
+        try {
+            testNewLargeSize(curSize, needSize);
+            throw new RuntimeException("ArrayIndexOutOfBoundsException not thrown");
+        } catch (ArrayIndexOutOfBoundsException aiobe) {
+            System.out.println("ArrayIndexOutOfBoundsException expected.");
+        } catch (RuntimeException re) {
+            throw re;
+        } catch (Throwable th) {
+            throw new RuntimeException("Unexpected exception", th);
+        }
+    }
+
+    private static void testNewLargeSize(final long curSize,
+                                         final long needSize) {
+
+        long size = ArrayCache.getNewLargeSize(curSize, needSize);
+
+        System.out.println("getNewLargeSize(" + curSize + ", " + needSize
+            + ") = " + size);
+
+        if (size < 0 || size < needSize || size > Integer.MAX_VALUE) {
+            throw new IllegalStateException("Invalid getNewLargeSize("
+                + curSize + ", " + needSize + ") = " + size + " !");
+        }
+    }
+
+}
--- a/jdk/test/sun/java2d/marlin/CrashTest.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/test/sun/java2d/marlin/CrashTest.java	Wed Jul 05 21:10:50 2017 +0200
@@ -31,31 +31,44 @@
 import java.io.File;
 import java.io.IOException;
 import javax.imageio.ImageIO;
-import sun.java2d.pipe.RenderingEngine;
 
 /**
- * Simple crash rendering test using huge GeneralPaths with marlin renderer
- *
- * run it with large heap (2g):
- * java -Dsun.java2d.renderer=sun.java2d.marlin.MarlinRenderingEngine marlin.CrashTest
- *
- * @author bourgesl
- */
+ * @test
+ * @summary Simple crash rendering test using huge GeneralPaths with the Marlin renderer
+ * @run main/othervm -mx512m CrashTest
+ * @ignore tests that take a long time and consumes 5Gb memory
+ * @run main/othervm -ms4g -mx4g CrashTest -slow
+*/
 public class CrashTest {
 
     static final boolean SAVE_IMAGE = false;
     static boolean USE_ROUND_CAPS_AND_JOINS = true;
 
     public static void main(String[] args) {
+        boolean runSlowTests = (args.length != 0 && "-slow".equals(args[0]));
+
+        // First display which renderer is tested:
+        System.setProperty("sun.java2d.renderer.verbose", "true");
+
         // try insane image sizes:
 
         // subpixel coords may overflow:
-//        testHugeImage((Integer.MAX_VALUE >> 3) + 1, 6);
+        // check MAX_VALUE / (8 * 2); overflow may happen due to orientation flag
+        // But as it is impossible to allocate an image larger than 2Gb (byte) then
+        // it is also impossible to have rowAAChunk larger than 2Gb !
+
+        // Disabled test as it consumes 4GB heap + offheap (2Gb) ie > 6Gb !
+        if (runSlowTests) {
+            testHugeImage((Integer.MAX_VALUE >> 4) - 100, 16);
+        }
+
         // larger than 23 bits: (RLE)
         testHugeImage(8388608 + 1, 10);
 
-        test(0.1f, false, 0);
-        test(0.1f, true, 7f);
+        if (runSlowTests) {
+            test(0.1f, false, 0);
+            test(0.1f, true, 7f);
+        }
 
         // Exceed 2Gb OffHeap buffer for edges:
         try {
@@ -67,17 +80,15 @@
             if (th instanceof ArrayIndexOutOfBoundsException) {
                 System.out.println("ArrayIndexOutOfBoundsException expected.");
             } else {
-                System.out.println("Exception occured:");
-                th.printStackTrace();
+                throw new RuntimeException("Unexpected exception", th);
             }
         }
-
     }
 
     private static void test(final float lineStroke,
                              final boolean useDashes,
                              final float dashMinLen)
-    throws ArrayIndexOutOfBoundsException
+        throws ArrayIndexOutOfBoundsException
     {
         System.out.println("---\n" + "test: "
             + "lineStroke=" + lineStroke
@@ -85,9 +96,6 @@
             +", dashMinLen=" + dashMinLen
         );
 
-        final String renderer = RenderingEngine.getInstance().getClass().getSimpleName();
-        System.out.println("Testing renderer = " + renderer);
-
         final BasicStroke stroke = createStroke(lineStroke, useDashes, dashMinLen);
 
         // TODO: test Dasher.firstSegmentsBuffer resizing ?
@@ -135,7 +143,7 @@
 
             if (SAVE_IMAGE) {
                 try {
-                    final File file = new File("CrashTest-" + renderer + "-dash-" + useDashes + ".bmp");
+                    final File file = new File("CrashTest-dash-" + useDashes + ".bmp");
 
                     System.out.println("Writing file: " + file.getAbsolutePath());
                     ImageIO.write(image, "BMP", file);
@@ -150,15 +158,10 @@
     }
 
     private static void testHugeImage(final int width, final int height)
-    throws ArrayIndexOutOfBoundsException
+        throws ArrayIndexOutOfBoundsException
     {
         System.out.println("---\n" + "testHugeImage: "
-            + "width=" + width
-            + ", height=" + height
-        );
-
-        final String renderer = RenderingEngine.getInstance().getClass().getSimpleName();
-        System.out.println("Testing renderer = " + renderer);
+            + "width=" + width + ", height=" + height);
 
         final BasicStroke stroke = createStroke(2.5f, false, 0);
 
@@ -195,8 +198,8 @@
 
             if (SAVE_IMAGE) {
                 try {
-                    final File file = new File("CrashTest-" + renderer +
-                                               "-huge-" + width + "x" +height + ".bmp");
+                    final File file = new File("CrashTest-huge-"
+                        + width + "x" +height + ".bmp");
 
                     System.out.println("Writing file: " + file.getAbsolutePath());
                     ImageIO.write(image, "BMP", file);
--- a/jdk/test/sun/management/jmxremote/startstop/JMXStartStopTest.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/test/sun/management/jmxremote/startstop/JMXStartStopTest.java	Wed Jul 05 21:10:50 2017 +0200
@@ -58,7 +58,7 @@
  * @run main/othervm/timeout=600 -XX:+UsePerfData JMXStartStopTest
  * @summary Makes sure that enabling/disabling the management agent through JCMD
  *          achieves the desired results
- * @key randomness
+ * @key randomness intermittent
  */
 public class JMXStartStopTest {
     private static final String TEST_APP_NAME = "TestApp";
--- a/jdk/test/sun/misc/FloatingDecimal/OldFDBigIntForTest.java	Thu Dec 24 10:33:21 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,491 +0,0 @@
-/*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-//package sun.misc;
-
-/*
- * A really, really simple bigint package
- * tailored to the needs of floating base conversion.
- */
-class OldFDBigIntForTest {
-    int nWords; // number of words used
-    int data[]; // value: data[0] is least significant
-
-
-    public OldFDBigIntForTest( int v ){
-        nWords = 1;
-        data = new int[1];
-        data[0] = v;
-    }
-
-    public OldFDBigIntForTest( long v ){
-        data = new int[2];
-        data[0] = (int)v;
-        data[1] = (int)(v>>>32);
-        nWords = (data[1]==0) ? 1 : 2;
-    }
-
-    public OldFDBigIntForTest( OldFDBigIntForTest other ){
-        data = new int[nWords = other.nWords];
-        System.arraycopy( other.data, 0, data, 0, nWords );
-    }
-
-    private OldFDBigIntForTest( int [] d, int n ){
-        data = d;
-        nWords = n;
-    }
-
-    public OldFDBigIntForTest( long seed, char digit[], int nd0, int nd ){
-        int n= (nd+8)/9;        // estimate size needed.
-        if ( n < 2 ) n = 2;
-        data = new int[n];      // allocate enough space
-        data[0] = (int)seed;    // starting value
-        data[1] = (int)(seed>>>32);
-        nWords = (data[1]==0) ? 1 : 2;
-        int i = nd0;
-        int limit = nd-5;       // slurp digits 5 at a time.
-        int v;
-        while ( i < limit ){
-            int ilim = i+5;
-            v = (int)digit[i++]-(int)'0';
-            while( i <ilim ){
-                v = 10*v + (int)digit[i++]-(int)'0';
-            }
-            multaddMe( 100000, v); // ... where 100000 is 10^5.
-        }
-        int factor = 1;
-        v = 0;
-        while ( i < nd ){
-            v = 10*v + (int)digit[i++]-(int)'0';
-            factor *= 10;
-        }
-        if ( factor != 1 ){
-            multaddMe( factor, v );
-        }
-    }
-
-    /*
-     * Left shift by c bits.
-     * Shifts this in place.
-     */
-    public void
-    lshiftMe( int c )throws IllegalArgumentException {
-        if ( c <= 0 ){
-            if ( c == 0 )
-                return; // silly.
-            else
-                throw new IllegalArgumentException("negative shift count");
-        }
-        int wordcount = c>>5;
-        int bitcount  = c & 0x1f;
-        int anticount = 32-bitcount;
-        int t[] = data;
-        int s[] = data;
-        if ( nWords+wordcount+1 > t.length ){
-            // reallocate.
-            t = new int[ nWords+wordcount+1 ];
-        }
-        int target = nWords+wordcount;
-        int src    = nWords-1;
-        if ( bitcount == 0 ){
-            // special hack, since an anticount of 32 won't go!
-            System.arraycopy( s, 0, t, wordcount, nWords );
-            target = wordcount-1;
-        } else {
-            t[target--] = s[src]>>>anticount;
-            while ( src >= 1 ){
-                t[target--] = (s[src]<<bitcount) | (s[--src]>>>anticount);
-            }
-            t[target--] = s[src]<<bitcount;
-        }
-        while( target >= 0 ){
-            t[target--] = 0;
-        }
-        data = t;
-        nWords += wordcount + 1;
-        // may have constructed high-order word of 0.
-        // if so, trim it
-        while ( nWords > 1 && data[nWords-1] == 0 )
-            nWords--;
-    }
-
-    /*
-     * normalize this number by shifting until
-     * the MSB of the number is at 0x08000000.
-     * This is in preparation for quoRemIteration, below.
-     * The idea is that, to make division easier, we want the
-     * divisor to be "normalized" -- usually this means shifting
-     * the MSB into the high words sign bit. But because we know that
-     * the quotient will be 0 < q < 10, we would like to arrange that
-     * the dividend not span up into another word of precision.
-     * (This needs to be explained more clearly!)
-     */
-    public int
-    normalizeMe() throws IllegalArgumentException {
-        int src;
-        int wordcount = 0;
-        int bitcount  = 0;
-        int v = 0;
-        for ( src= nWords-1 ; src >= 0 && (v=data[src]) == 0 ; src--){
-            wordcount += 1;
-        }
-        if ( src < 0 ){
-            // oops. Value is zero. Cannot normalize it!
-            throw new IllegalArgumentException("zero value");
-        }
-        /*
-         * In most cases, we assume that wordcount is zero. This only
-         * makes sense, as we try not to maintain any high-order
-         * words full of zeros. In fact, if there are zeros, we will
-         * simply SHORTEN our number at this point. Watch closely...
-         */
-        nWords -= wordcount;
-        /*
-         * Compute how far left we have to shift v s.t. its highest-
-         * order bit is in the right place. Then call lshiftMe to
-         * do the work.
-         */
-        if ( (v & 0xf0000000) != 0 ){
-            // will have to shift up into the next word.
-            // too bad.
-            for( bitcount = 32 ; (v & 0xf0000000) != 0 ; bitcount-- )
-                v >>>= 1;
-        } else {
-            while ( v <= 0x000fffff ){
-                // hack: byte-at-a-time shifting
-                v <<= 8;
-                bitcount += 8;
-            }
-            while ( v <= 0x07ffffff ){
-                v <<= 1;
-                bitcount += 1;
-            }
-        }
-        if ( bitcount != 0 )
-            lshiftMe( bitcount );
-        return bitcount;
-    }
-
-    /*
-     * Multiply a OldFDBigIntForTest by an int.
-     * Result is a new OldFDBigIntForTest.
-     */
-    public OldFDBigIntForTest
-    mult( int iv ) {
-        long v = iv;
-        int r[];
-        long p;
-
-        // guess adequate size of r.
-        r = new int[ ( v * ((long)data[nWords-1]&0xffffffffL) > 0xfffffffL ) ? nWords+1 : nWords ];
-        p = 0L;
-        for( int i=0; i < nWords; i++ ) {
-            p += v * ((long)data[i]&0xffffffffL);
-            r[i] = (int)p;
-            p >>>= 32;
-        }
-        if ( p == 0L){
-            return new OldFDBigIntForTest( r, nWords );
-        } else {
-            r[nWords] = (int)p;
-            return new OldFDBigIntForTest( r, nWords+1 );
-        }
-    }
-
-    /*
-     * Multiply a OldFDBigIntForTest by an int and add another int.
-     * Result is computed in place.
-     * Hope it fits!
-     */
-    public void
-    multaddMe( int iv, int addend ) {
-        long v = iv;
-        long p;
-
-        // unroll 0th iteration, doing addition.
-        p = v * ((long)data[0]&0xffffffffL) + ((long)addend&0xffffffffL);
-        data[0] = (int)p;
-        p >>>= 32;
-        for( int i=1; i < nWords; i++ ) {
-            p += v * ((long)data[i]&0xffffffffL);
-            data[i] = (int)p;
-            p >>>= 32;
-        }
-        if ( p != 0L){
-            data[nWords] = (int)p; // will fail noisily if illegal!
-            nWords++;
-        }
-    }
-
-    /*
-     * Multiply a OldFDBigIntForTest by another OldFDBigIntForTest.
-     * Result is a new OldFDBigIntForTest.
-     */
-    public OldFDBigIntForTest
-    mult( OldFDBigIntForTest other ){
-        // crudely guess adequate size for r
-        int r[] = new int[ nWords + other.nWords ];
-        int i;
-        // I think I am promised zeros...
-
-        for( i = 0; i < this.nWords; i++ ){
-            long v = (long)this.data[i] & 0xffffffffL; // UNSIGNED CONVERSION
-            long p = 0L;
-            int j;
-            for( j = 0; j < other.nWords; j++ ){
-                p += ((long)r[i+j]&0xffffffffL) + v*((long)other.data[j]&0xffffffffL); // UNSIGNED CONVERSIONS ALL 'ROUND.
-                r[i+j] = (int)p;
-                p >>>= 32;
-            }
-            r[i+j] = (int)p;
-        }
-        // compute how much of r we actually needed for all that.
-        for ( i = r.length-1; i> 0; i--)
-            if ( r[i] != 0 )
-                break;
-        return new OldFDBigIntForTest( r, i+1 );
-    }
-
-    /*
-     * Add one OldFDBigIntForTest to another. Return a OldFDBigIntForTest
-     */
-    public OldFDBigIntForTest
-    add( OldFDBigIntForTest other ){
-        int i;
-        int a[], b[];
-        int n, m;
-        long c = 0L;
-        // arrange such that a.nWords >= b.nWords;
-        // n = a.nWords, m = b.nWords
-        if ( this.nWords >= other.nWords ){
-            a = this.data;
-            n = this.nWords;
-            b = other.data;
-            m = other.nWords;
-        } else {
-            a = other.data;
-            n = other.nWords;
-            b = this.data;
-            m = this.nWords;
-        }
-        int r[] = new int[ n ];
-        for ( i = 0; i < n; i++ ){
-            c += (long)a[i] & 0xffffffffL;
-            if ( i < m ){
-                c += (long)b[i] & 0xffffffffL;
-            }
-            r[i] = (int) c;
-            c >>= 32; // signed shift.
-        }
-        if ( c != 0L ){
-            // oops -- carry out -- need longer result.
-            int s[] = new int[ r.length+1 ];
-            System.arraycopy( r, 0, s, 0, r.length );
-            s[i++] = (int)c;
-            return new OldFDBigIntForTest( s, i );
-        }
-        return new OldFDBigIntForTest( r, i );
-    }
-
-    /*
-     * Subtract one OldFDBigIntForTest from another. Return a OldFDBigIntForTest
-     * Assert that the result is positive.
-     */
-    public OldFDBigIntForTest
-    sub( OldFDBigIntForTest other ){
-        int r[] = new int[ this.nWords ];
-        int i;
-        int n = this.nWords;
-        int m = other.nWords;
-        int nzeros = 0;
-        long c = 0L;
-        for ( i = 0; i < n; i++ ){
-            c += (long)this.data[i] & 0xffffffffL;
-            if ( i < m ){
-                c -= (long)other.data[i] & 0xffffffffL;
-            }
-            if ( ( r[i] = (int) c ) == 0 )
-                nzeros++;
-            else
-                nzeros = 0;
-            c >>= 32; // signed shift
-        }
-        assert c == 0L : c; // borrow out of subtract
-        assert dataInRangeIsZero(i, m, other); // negative result of subtract
-        return new OldFDBigIntForTest( r, n-nzeros );
-    }
-
-    private static boolean dataInRangeIsZero(int i, int m, OldFDBigIntForTest other) {
-        while ( i < m )
-            if (other.data[i++] != 0)
-                return false;
-        return true;
-    }
-
-    /*
-     * Compare OldFDBigIntForTest with another OldFDBigIntForTest. Return an integer
-     * >0: this > other
-     *  0: this == other
-     * <0: this < other
-     */
-    public int
-    cmp( OldFDBigIntForTest other ){
-        int i;
-        if ( this.nWords > other.nWords ){
-            // if any of my high-order words is non-zero,
-            // then the answer is evident
-            int j = other.nWords-1;
-            for ( i = this.nWords-1; i > j ; i-- )
-                if ( this.data[i] != 0 ) return 1;
-        }else if ( this.nWords < other.nWords ){
-            // if any of other's high-order words is non-zero,
-            // then the answer is evident
-            int j = this.nWords-1;
-            for ( i = other.nWords-1; i > j ; i-- )
-                if ( other.data[i] != 0 ) return -1;
-        } else{
-            i = this.nWords-1;
-        }
-        for ( ; i > 0 ; i-- )
-            if ( this.data[i] != other.data[i] )
-                break;
-        // careful! want unsigned compare!
-        // use brute force here.
-        int a = this.data[i];
-        int b = other.data[i];
-        if ( a < 0 ){
-            // a is really big, unsigned
-            if ( b < 0 ){
-                return a-b; // both big, negative
-            } else {
-                return 1; // b not big, answer is obvious;
-            }
-        } else {
-            // a is not really big
-            if ( b < 0 ) {
-                // but b is really big
-                return -1;
-            } else {
-                return a - b;
-            }
-        }
-    }
-
-    /*
-     * Compute
-     * q = (int)( this / S )
-     * this = 10 * ( this mod S )
-     * Return q.
-     * This is the iteration step of digit development for output.
-     * We assume that S has been normalized, as above, and that
-     * "this" has been lshift'ed accordingly.
-     * Also assume, of course, that the result, q, can be expressed
-     * as an integer, 0 <= q < 10.
-     */
-    public int
-    quoRemIteration( OldFDBigIntForTest S )throws IllegalArgumentException {
-        // ensure that this and S have the same number of
-        // digits. If S is properly normalized and q < 10 then
-        // this must be so.
-        if ( nWords != S.nWords ){
-            throw new IllegalArgumentException("disparate values");
-        }
-        // estimate q the obvious way. We will usually be
-        // right. If not, then we're only off by a little and
-        // will re-add.
-        int n = nWords-1;
-        long q = ((long)data[n]&0xffffffffL) / (long)S.data[n];
-        long diff = 0L;
-        for ( int i = 0; i <= n ; i++ ){
-            diff += ((long)data[i]&0xffffffffL) -  q*((long)S.data[i]&0xffffffffL);
-            data[i] = (int)diff;
-            diff >>= 32; // N.B. SIGNED shift.
-        }
-        if ( diff != 0L ) {
-            // damn, damn, damn. q is too big.
-            // add S back in until this turns +. This should
-            // not be very many times!
-            long sum = 0L;
-            while ( sum ==  0L ){
-                sum = 0L;
-                for ( int i = 0; i <= n; i++ ){
-                    sum += ((long)data[i]&0xffffffffL) +  ((long)S.data[i]&0xffffffffL);
-                    data[i] = (int) sum;
-                    sum >>= 32; // Signed or unsigned, answer is 0 or 1
-                }
-                /*
-                 * Originally the following line read
-                 * "if ( sum !=0 && sum != -1 )"
-                 * but that would be wrong, because of the
-                 * treatment of the two values as entirely unsigned,
-                 * it would be impossible for a carry-out to be interpreted
-                 * as -1 -- it would have to be a single-bit carry-out, or
-                 * +1.
-                 */
-                assert sum == 0 || sum == 1 : sum; // carry out of division correction
-                q -= 1;
-            }
-        }
-        // finally, we can multiply this by 10.
-        // it cannot overflow, right, as the high-order word has
-        // at least 4 high-order zeros!
-        long p = 0L;
-        for ( int i = 0; i <= n; i++ ){
-            p += 10*((long)data[i]&0xffffffffL);
-            data[i] = (int)p;
-            p >>= 32; // SIGNED shift.
-        }
-        assert p == 0L : p; // Carry out of *10
-        return (int)q;
-    }
-
-    public long
-    longValue(){
-        // if this can be represented as a long, return the value
-        assert this.nWords > 0 : this.nWords; // longValue confused
-
-        if (this.nWords == 1)
-            return ((long)data[0]&0xffffffffL);
-
-        assert dataInRangeIsZero(2, this.nWords, this); // value too big
-        assert data[1] >= 0;  // value too big
-        return ((long)(data[1]) << 32) | ((long)data[0]&0xffffffffL);
-    }
-
-    public String
-    toString() {
-        StringBuffer r = new StringBuffer(30);
-        r.append('[');
-        int i = Math.min( nWords-1, data.length-1) ;
-        if ( nWords > data.length ){
-            r.append( "("+data.length+"<"+nWords+"!)" );
-        }
-        for( ; i> 0 ; i-- ){
-            r.append( Integer.toHexString( data[i] ) );
-            r.append(' ');
-        }
-        r.append( Integer.toHexString( data[0] ) );
-        r.append(']');
-        return new String( r );
-    }
-}
--- a/jdk/test/sun/misc/FloatingDecimal/OldFloatingDecimalForTest.java	Thu Dec 24 10:33:21 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2434 +0,0 @@
-/*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-//package sun.misc;
-
-import java.util.regex.*;
-
-public class OldFloatingDecimalForTest{
-    boolean     isExceptional;
-    boolean     isNegative;
-    int         decExponent;
-    char        digits[];
-    int         nDigits;
-    int         bigIntExp;
-    int         bigIntNBits;
-    boolean     mustSetRoundDir = false;
-    boolean     fromHex = false;
-    int         roundDir = 0; // set by doubleValue
-
-    /*
-     * The fields below provides additional information about the result of
-     * the binary to decimal digits conversion done in dtoa() and roundup()
-     * methods. They are changed if needed by those two methods.
-     */
-
-    // True if the dtoa() binary to decimal conversion was exact.
-    boolean     exactDecimalConversion = false;
-
-    // True if the result of the binary to decimal conversion was rounded-up
-    // at the end of the conversion process, i.e. roundUp() method was called.
-    boolean     decimalDigitsRoundedUp = false;
-
-    private     OldFloatingDecimalForTest( boolean negSign, int decExponent, char []digits, int n,  boolean e )
-    {
-        isNegative = negSign;
-        isExceptional = e;
-        this.decExponent = decExponent;
-        this.digits = digits;
-        this.nDigits = n;
-    }
-
-    /*
-     * Constants of the implementation
-     * Most are IEEE-754 related.
-     * (There are more really boring constants at the end.)
-     */
-    static final long   signMask = 0x8000000000000000L;
-    static final long   expMask  = 0x7ff0000000000000L;
-    static final long   fractMask= ~(signMask|expMask);
-    static final int    expShift = 52;
-    static final int    expBias  = 1023;
-    static final long   fractHOB = ( 1L<<expShift ); // assumed High-Order bit
-    static final long   expOne   = ((long)expBias)<<expShift; // exponent of 1.0
-    static final int    maxSmallBinExp = 62;
-    static final int    minSmallBinExp = -( 63 / 3 );
-    static final int    maxDecimalDigits = 15;
-    static final int    maxDecimalExponent = 308;
-    static final int    minDecimalExponent = -324;
-    static final int    bigDecimalExponent = 324; // i.e. abs(minDecimalExponent)
-
-    static final long   highbyte = 0xff00000000000000L;
-    static final long   highbit  = 0x8000000000000000L;
-    static final long   lowbytes = ~highbyte;
-
-    static final int    singleSignMask =    0x80000000;
-    static final int    singleExpMask  =    0x7f800000;
-    static final int    singleFractMask =   ~(singleSignMask|singleExpMask);
-    static final int    singleExpShift  =   23;
-    static final int    singleFractHOB  =   1<<singleExpShift;
-    static final int    singleExpBias   =   127;
-    static final int    singleMaxDecimalDigits = 7;
-    static final int    singleMaxDecimalExponent = 38;
-    static final int    singleMinDecimalExponent = -45;
-
-    static final int    intDecimalDigits = 9;
-
-
-    /*
-     * count number of bits from high-order 1 bit to low-order 1 bit,
-     * inclusive.
-     */
-    private static int
-    countBits( long v ){
-        //
-        // the strategy is to shift until we get a non-zero sign bit
-        // then shift until we have no bits left, counting the difference.
-        // we do byte shifting as a hack. Hope it helps.
-        //
-        if ( v == 0L ) return 0;
-
-        while ( ( v & highbyte ) == 0L ){
-            v <<= 8;
-        }
-        while ( v > 0L ) { // i.e. while ((v&highbit) == 0L )
-            v <<= 1;
-        }
-
-        int n = 0;
-        while (( v & lowbytes ) != 0L ){
-            v <<= 8;
-            n += 8;
-        }
-        while ( v != 0L ){
-            v <<= 1;
-            n += 1;
-        }
-        return n;
-    }
-
-    /*
-     * Keep big powers of 5 handy for future reference.
-     */
-    private static OldFDBigIntForTest b5p[];
-
-    private static synchronized OldFDBigIntForTest
-    big5pow( int p ){
-        assert p >= 0 : p; // negative power of 5
-        if ( b5p == null ){
-            b5p = new OldFDBigIntForTest[ p+1 ];
-        }else if (b5p.length <= p ){
-            OldFDBigIntForTest t[] = new OldFDBigIntForTest[ p+1 ];
-            System.arraycopy( b5p, 0, t, 0, b5p.length );
-            b5p = t;
-        }
-        if ( b5p[p] != null )
-            return b5p[p];
-        else if ( p < small5pow.length )
-            return b5p[p] = new OldFDBigIntForTest( small5pow[p] );
-        else if ( p < long5pow.length )
-            return b5p[p] = new OldFDBigIntForTest( long5pow[p] );
-        else {
-            // construct the value.
-            // recursively.
-            int q, r;
-            // in order to compute 5^p,
-            // compute its square root, 5^(p/2) and square.
-            // or, let q = p / 2, r = p -q, then
-            // 5^p = 5^(q+r) = 5^q * 5^r
-            q = p >> 1;
-            r = p - q;
-            OldFDBigIntForTest bigq =  b5p[q];
-            if ( bigq == null )
-                bigq = big5pow ( q );
-            if ( r < small5pow.length ){
-                return (b5p[p] = bigq.mult( small5pow[r] ) );
-            }else{
-                OldFDBigIntForTest bigr = b5p[ r ];
-                if ( bigr == null )
-                    bigr = big5pow( r );
-                return (b5p[p] = bigq.mult( bigr ) );
-            }
-        }
-    }
-
-    //
-    // a common operation
-    //
-    private static OldFDBigIntForTest
-    multPow52( OldFDBigIntForTest v, int p5, int p2 ){
-        if ( p5 != 0 ){
-            if ( p5 < small5pow.length ){
-                v = v.mult( small5pow[p5] );
-            } else {
-                v = v.mult( big5pow( p5 ) );
-            }
-        }
-        if ( p2 != 0 ){
-            v.lshiftMe( p2 );
-        }
-        return v;
-    }
-
-    //
-    // another common operation
-    //
-    private static OldFDBigIntForTest
-    constructPow52( int p5, int p2 ){
-        OldFDBigIntForTest v = new OldFDBigIntForTest( big5pow( p5 ) );
-        if ( p2 != 0 ){
-            v.lshiftMe( p2 );
-        }
-        return v;
-    }
-
-    /*
-     * Make a floating double into a OldFDBigIntForTest.
-     * This could also be structured as a OldFDBigIntForTest
-     * constructor, but we'd have to build a lot of knowledge
-     * about floating-point representation into it, and we don't want to.
-     *
-     * AS A SIDE EFFECT, THIS METHOD WILL SET THE INSTANCE VARIABLES
-     * bigIntExp and bigIntNBits
-     *
-     */
-    private OldFDBigIntForTest
-    doubleToBigInt( double dval ){
-        long lbits = Double.doubleToLongBits( dval ) & ~signMask;
-        int binexp = (int)(lbits >>> expShift);
-        lbits &= fractMask;
-        if ( binexp > 0 ){
-            lbits |= fractHOB;
-        } else {
-            assert lbits != 0L : lbits; // doubleToBigInt(0.0)
-            binexp +=1;
-            while ( (lbits & fractHOB ) == 0L){
-                lbits <<= 1;
-                binexp -= 1;
-            }
-        }
-        binexp -= expBias;
-        int nbits = countBits( lbits );
-        /*
-         * We now know where the high-order 1 bit is,
-         * and we know how many there are.
-         */
-        int lowOrderZeros = expShift+1-nbits;
-        lbits >>>= lowOrderZeros;
-
-        bigIntExp = binexp+1-nbits;
-        bigIntNBits = nbits;
-        return new OldFDBigIntForTest( lbits );
-    }
-
-    /*
-     * Compute a number that is the ULP of the given value,
-     * for purposes of addition/subtraction. Generally easy.
-     * More difficult if subtracting and the argument
-     * is a normalized a power of 2, as the ULP changes at these points.
-     */
-    private static double ulp( double dval, boolean subtracting ){
-        long lbits = Double.doubleToLongBits( dval ) & ~signMask;
-        int binexp = (int)(lbits >>> expShift);
-        double ulpval;
-        if ( subtracting && ( binexp >= expShift ) && ((lbits&fractMask) == 0L) ){
-            // for subtraction from normalized, powers of 2,
-            // use next-smaller exponent
-            binexp -= 1;
-        }
-        if ( binexp > expShift ){
-            ulpval = Double.longBitsToDouble( ((long)(binexp-expShift))<<expShift );
-        } else if ( binexp == 0 ){
-            ulpval = Double.MIN_VALUE;
-        } else {
-            ulpval = Double.longBitsToDouble( 1L<<(binexp-1) );
-        }
-        if ( subtracting ) ulpval = - ulpval;
-
-        return ulpval;
-    }
-
-    /*
-     * Round a double to a float.
-     * In addition to the fraction bits of the double,
-     * look at the class instance variable roundDir,
-     * which should help us avoid double-rounding error.
-     * roundDir was set in hardValueOf if the estimate was
-     * close enough, but not exact. It tells us which direction
-     * of rounding is preferred.
-     */
-    float
-    stickyRound( double dval ){
-        long lbits = Double.doubleToLongBits( dval );
-        long binexp = lbits & expMask;
-        if ( binexp == 0L || binexp == expMask ){
-            // what we have here is special.
-            // don't worry, the right thing will happen.
-            return (float) dval;
-        }
-        lbits += (long)roundDir; // hack-o-matic.
-        return (float)Double.longBitsToDouble( lbits );
-    }
-
-
-    /*
-     * This is the easy subcase --
-     * all the significant bits, after scaling, are held in lvalue.
-     * negSign and decExponent tell us what processing and scaling
-     * has already been done. Exceptional cases have already been
-     * stripped out.
-     * In particular:
-     * lvalue is a finite number (not Inf, nor NaN)
-     * lvalue > 0L (not zero, nor negative).
-     *
-     * The only reason that we develop the digits here, rather than
-     * calling on Long.toString() is that we can do it a little faster,
-     * and besides want to treat trailing 0s specially. If Long.toString
-     * changes, we should re-evaluate this strategy!
-     */
-    private void
-    developLongDigits( int decExponent, long lvalue, long insignificant ){
-        char digits[];
-        int  ndigits;
-        int  digitno;
-        int  c;
-        //
-        // Discard non-significant low-order bits, while rounding,
-        // up to insignificant value.
-        int i;
-        for ( i = 0; insignificant >= 10L; i++ )
-            insignificant /= 10L;
-        if ( i != 0 ){
-            long pow10 = long5pow[i] << i; // 10^i == 5^i * 2^i;
-            long residue = lvalue % pow10;
-            lvalue /= pow10;
-            decExponent += i;
-            if ( residue >= (pow10>>1) ){
-                // round up based on the low-order bits we're discarding
-                lvalue++;
-            }
-        }
-        if ( lvalue <= Integer.MAX_VALUE ){
-            assert lvalue > 0L : lvalue; // lvalue <= 0
-            // even easier subcase!
-            // can do int arithmetic rather than long!
-            int  ivalue = (int)lvalue;
-            ndigits = 10;
-            digits = perThreadBuffer.get();
-            digitno = ndigits-1;
-            c = ivalue%10;
-            ivalue /= 10;
-            while ( c == 0 ){
-                decExponent++;
-                c = ivalue%10;
-                ivalue /= 10;
-            }
-            while ( ivalue != 0){
-                digits[digitno--] = (char)(c+'0');
-                decExponent++;
-                c = ivalue%10;
-                ivalue /= 10;
-            }
-            digits[digitno] = (char)(c+'0');
-        } else {
-            // same algorithm as above (same bugs, too )
-            // but using long arithmetic.
-            ndigits = 20;
-            digits = perThreadBuffer.get();
-            digitno = ndigits-1;
-            c = (int)(lvalue%10L);
-            lvalue /= 10L;
-            while ( c == 0 ){
-                decExponent++;
-                c = (int)(lvalue%10L);
-                lvalue /= 10L;
-            }
-            while ( lvalue != 0L ){
-                digits[digitno--] = (char)(c+'0');
-                decExponent++;
-                c = (int)(lvalue%10L);
-                lvalue /= 10;
-            }
-            digits[digitno] = (char)(c+'0');
-        }
-        char result [];
-        ndigits -= digitno;
-        result = new char[ ndigits ];
-        System.arraycopy( digits, digitno, result, 0, ndigits );
-        this.digits = result;
-        this.decExponent = decExponent+1;
-        this.nDigits = ndigits;
-    }
-
-    //
-    // add one to the least significant digit.
-    // in the unlikely event there is a carry out,
-    // deal with it.
-    // assert that this will only happen where there
-    // is only one digit, e.g. (float)1e-44 seems to do it.
-    //
-    private void
-    roundup(){
-        int i;
-        int q = digits[ i = (nDigits-1)];
-        if ( q == '9' ){
-            while ( q == '9' && i > 0 ){
-                digits[i] = '0';
-                q = digits[--i];
-            }
-            if ( q == '9' ){
-                // carryout! High-order 1, rest 0s, larger exp.
-                decExponent += 1;
-                digits[0] = '1';
-                return;
-            }
-            // else fall through.
-        }
-        digits[i] = (char)(q+1);
-        decimalDigitsRoundedUp = true;
-    }
-
-    public boolean digitsRoundedUp() {
-        return decimalDigitsRoundedUp;
-    }
-
-    /*
-     * FIRST IMPORTANT CONSTRUCTOR: DOUBLE
-     */
-    public OldFloatingDecimalForTest( double d )
-    {
-        long    dBits = Double.doubleToLongBits( d );
-        long    fractBits;
-        int     binExp;
-        int     nSignificantBits;
-
-        // discover and delete sign
-        if ( (dBits&signMask) != 0 ){
-            isNegative = true;
-            dBits ^= signMask;
-        } else {
-            isNegative = false;
-        }
-        // Begin to unpack
-        // Discover obvious special cases of NaN and Infinity.
-        binExp = (int)( (dBits&expMask) >> expShift );
-        fractBits = dBits&fractMask;
-        if ( binExp == (int)(expMask>>expShift) ) {
-            isExceptional = true;
-            if ( fractBits == 0L ){
-                digits =  infinity;
-            } else {
-                digits = notANumber;
-                isNegative = false; // NaN has no sign!
-            }
-            nDigits = digits.length;
-            return;
-        }
-        isExceptional = false;
-        // Finish unpacking
-        // Normalize denormalized numbers.
-        // Insert assumed high-order bit for normalized numbers.
-        // Subtract exponent bias.
-        if ( binExp == 0 ){
-            if ( fractBits == 0L ){
-                // not a denorm, just a 0!
-                decExponent = 0;
-                digits = zero;
-                nDigits = 1;
-                return;
-            }
-            while ( (fractBits&fractHOB) == 0L ){
-                fractBits <<= 1;
-                binExp -= 1;
-            }
-            nSignificantBits = expShift + binExp +1; // recall binExp is  - shift count.
-            binExp += 1;
-        } else {
-            fractBits |= fractHOB;
-            nSignificantBits = expShift+1;
-        }
-        binExp -= expBias;
-        // call the routine that actually does all the hard work.
-        dtoa( binExp, fractBits, nSignificantBits );
-    }
-
-    /*
-     * SECOND IMPORTANT CONSTRUCTOR: SINGLE
-     */
-    public OldFloatingDecimalForTest( float f )
-    {
-        int     fBits = Float.floatToIntBits( f );
-        int     fractBits;
-        int     binExp;
-        int     nSignificantBits;
-
-        // discover and delete sign
-        if ( (fBits&singleSignMask) != 0 ){
-            isNegative = true;
-            fBits ^= singleSignMask;
-        } else {
-            isNegative = false;
-        }
-        // Begin to unpack
-        // Discover obvious special cases of NaN and Infinity.
-        binExp = (fBits&singleExpMask) >> singleExpShift;
-        fractBits = fBits&singleFractMask;
-        if ( binExp == (singleExpMask>>singleExpShift) ) {
-            isExceptional = true;
-            if ( fractBits == 0L ){
-                digits =  infinity;
-            } else {
-                digits = notANumber;
-                isNegative = false; // NaN has no sign!
-            }
-            nDigits = digits.length;
-            return;
-        }
-        isExceptional = false;
-        // Finish unpacking
-        // Normalize denormalized numbers.
-        // Insert assumed high-order bit for normalized numbers.
-        // Subtract exponent bias.
-        if ( binExp == 0 ){
-            if ( fractBits == 0 ){
-                // not a denorm, just a 0!
-                decExponent = 0;
-                digits = zero;
-                nDigits = 1;
-                return;
-            }
-            while ( (fractBits&singleFractHOB) == 0 ){
-                fractBits <<= 1;
-                binExp -= 1;
-            }
-            nSignificantBits = singleExpShift + binExp +1; // recall binExp is  - shift count.
-            binExp += 1;
-        } else {
-            fractBits |= singleFractHOB;
-            nSignificantBits = singleExpShift+1;
-        }
-        binExp -= singleExpBias;
-        // call the routine that actually does all the hard work.
-        dtoa( binExp, ((long)fractBits)<<(expShift-singleExpShift), nSignificantBits );
-    }
-
-    private void
-    dtoa( int binExp, long fractBits, int nSignificantBits )
-    {
-        int     nFractBits; // number of significant bits of fractBits;
-        int     nTinyBits;  // number of these to the right of the point.
-        int     decExp;
-
-        // Examine number. Determine if it is an easy case,
-        // which we can do pretty trivially using float/long conversion,
-        // or whether we must do real work.
-        nFractBits = countBits( fractBits );
-        nTinyBits = Math.max( 0, nFractBits - binExp - 1 );
-        if ( binExp <= maxSmallBinExp && binExp >= minSmallBinExp ){
-            // Look more closely at the number to decide if,
-            // with scaling by 10^nTinyBits, the result will fit in
-            // a long.
-            if ( (nTinyBits < long5pow.length) && ((nFractBits + n5bits[nTinyBits]) < 64 ) ){
-                /*
-                 * We can do this:
-                 * take the fraction bits, which are normalized.
-                 * (a) nTinyBits == 0: Shift left or right appropriately
-                 *     to align the binary point at the extreme right, i.e.
-                 *     where a long int point is expected to be. The integer
-                 *     result is easily converted to a string.
-                 * (b) nTinyBits > 0: Shift right by expShift-nFractBits,
-                 *     which effectively converts to long and scales by
-                 *     2^nTinyBits. Then multiply by 5^nTinyBits to
-                 *     complete the scaling. We know this won't overflow
-                 *     because we just counted the number of bits necessary
-                 *     in the result. The integer you get from this can
-                 *     then be converted to a string pretty easily.
-                 */
-                long halfULP;
-                if ( nTinyBits == 0 ) {
-                    if ( binExp > nSignificantBits ){
-                        halfULP = 1L << ( binExp-nSignificantBits-1);
-                    } else {
-                        halfULP = 0L;
-                    }
-                    if ( binExp >= expShift ){
-                        fractBits <<= (binExp-expShift);
-                    } else {
-                        fractBits >>>= (expShift-binExp) ;
-                    }
-                    developLongDigits( 0, fractBits, halfULP );
-                    return;
-                }
-                /*
-                 * The following causes excess digits to be printed
-                 * out in the single-float case. Our manipulation of
-                 * halfULP here is apparently not correct. If we
-                 * better understand how this works, perhaps we can
-                 * use this special case again. But for the time being,
-                 * we do not.
-                 * else {
-                 *     fractBits >>>= expShift+1-nFractBits;
-                 *     fractBits *= long5pow[ nTinyBits ];
-                 *     halfULP = long5pow[ nTinyBits ] >> (1+nSignificantBits-nFractBits);
-                 *     developLongDigits( -nTinyBits, fractBits, halfULP );
-                 *     return;
-                 * }
-                 */
-            }
-        }
-        /*
-         * This is the hard case. We are going to compute large positive
-         * integers B and S and integer decExp, s.t.
-         *      d = ( B / S ) * 10^decExp
-         *      1 <= B / S < 10
-         * Obvious choices are:
-         *      decExp = floor( log10(d) )
-         *      B      = d * 2^nTinyBits * 10^max( 0, -decExp )
-         *      S      = 10^max( 0, decExp) * 2^nTinyBits
-         * (noting that nTinyBits has already been forced to non-negative)
-         * I am also going to compute a large positive integer
-         *      M      = (1/2^nSignificantBits) * 2^nTinyBits * 10^max( 0, -decExp )
-         * i.e. M is (1/2) of the ULP of d, scaled like B.
-         * When we iterate through dividing B/S and picking off the
-         * quotient bits, we will know when to stop when the remainder
-         * is <= M.
-         *
-         * We keep track of powers of 2 and powers of 5.
-         */
-
-        /*
-         * Estimate decimal exponent. (If it is small-ish,
-         * we could double-check.)
-         *
-         * First, scale the mantissa bits such that 1 <= d2 < 2.
-         * We are then going to estimate
-         *          log10(d2) ~=~  (d2-1.5)/1.5 + log(1.5)
-         * and so we can estimate
-         *      log10(d) ~=~ log10(d2) + binExp * log10(2)
-         * take the floor and call it decExp.
-         * FIXME -- use more precise constants here. It costs no more.
-         */
-        double d2 = Double.longBitsToDouble(
-            expOne | ( fractBits &~ fractHOB ) );
-        decExp = (int)Math.floor(
-            (d2-1.5D)*0.289529654D + 0.176091259 + (double)binExp * 0.301029995663981 );
-        int B2, B5; // powers of 2 and powers of 5, respectively, in B
-        int S2, S5; // powers of 2 and powers of 5, respectively, in S
-        int M2, M5; // powers of 2 and powers of 5, respectively, in M
-        int Bbits; // binary digits needed to represent B, approx.
-        int tenSbits; // binary digits needed to represent 10*S, approx.
-        OldFDBigIntForTest Sval, Bval, Mval;
-
-        B5 = Math.max( 0, -decExp );
-        B2 = B5 + nTinyBits + binExp;
-
-        S5 = Math.max( 0, decExp );
-        S2 = S5 + nTinyBits;
-
-        M5 = B5;
-        M2 = B2 - nSignificantBits;
-
-        /*
-         * the long integer fractBits contains the (nFractBits) interesting
-         * bits from the mantissa of d ( hidden 1 added if necessary) followed
-         * by (expShift+1-nFractBits) zeros. In the interest of compactness,
-         * I will shift out those zeros before turning fractBits into a
-         * OldFDBigIntForTest. The resulting whole number will be
-         *      d * 2^(nFractBits-1-binExp).
-         */
-        fractBits >>>= (expShift+1-nFractBits);
-        B2 -= nFractBits-1;
-        int common2factor = Math.min( B2, S2 );
-        B2 -= common2factor;
-        S2 -= common2factor;
-        M2 -= common2factor;
-
-        /*
-         * HACK!! For exact powers of two, the next smallest number
-         * is only half as far away as we think (because the meaning of
-         * ULP changes at power-of-two bounds) for this reason, we
-         * hack M2. Hope this works.
-         */
-        if ( nFractBits == 1 )
-            M2 -= 1;
-
-        if ( M2 < 0 ){
-            // oops.
-            // since we cannot scale M down far enough,
-            // we must scale the other values up.
-            B2 -= M2;
-            S2 -= M2;
-            M2 =  0;
-        }
-        /*
-         * Construct, Scale, iterate.
-         * Some day, we'll write a stopping test that takes
-         * account of the asymmetry of the spacing of floating-point
-         * numbers below perfect powers of 2
-         * 26 Sept 96 is not that day.
-         * So we use a symmetric test.
-         */
-        char digits[] = this.digits = new char[18];
-        int  ndigit = 0;
-        boolean low, high;
-        long lowDigitDifference;
-        int  q;
-
-        /*
-         * Detect the special cases where all the numbers we are about
-         * to compute will fit in int or long integers.
-         * In these cases, we will avoid doing OldFDBigIntForTest arithmetic.
-         * We use the same algorithms, except that we "normalize"
-         * our OldFDBigIntForTests before iterating. This is to make division easier,
-         * as it makes our fist guess (quotient of high-order words)
-         * more accurate!
-         *
-         * Some day, we'll write a stopping test that takes
-         * account of the asymmetry of the spacing of floating-point
-         * numbers below perfect powers of 2
-         * 26 Sept 96 is not that day.
-         * So we use a symmetric test.
-         */
-        Bbits = nFractBits + B2 + (( B5 < n5bits.length )? n5bits[B5] : ( B5*3 ));
-        tenSbits = S2+1 + (( (S5+1) < n5bits.length )? n5bits[(S5+1)] : ( (S5+1)*3 ));
-        if ( Bbits < 64 && tenSbits < 64){
-            if ( Bbits < 32 && tenSbits < 32){
-                // wa-hoo! They're all ints!
-                int b = ((int)fractBits * small5pow[B5] ) << B2;
-                int s = small5pow[S5] << S2;
-                int m = small5pow[M5] << M2;
-                int tens = s * 10;
-                /*
-                 * Unroll the first iteration. If our decExp estimate
-                 * was too high, our first quotient will be zero. In this
-                 * case, we discard it and decrement decExp.
-                 */
-                ndigit = 0;
-                q = b / s;
-                b = 10 * ( b % s );
-                m *= 10;
-                low  = (b <  m );
-                high = (b+m > tens );
-                assert q < 10 : q; // excessively large digit
-                if ( (q == 0) && ! high ){
-                    // oops. Usually ignore leading zero.
-                    decExp--;
-                } else {
-                    digits[ndigit++] = (char)('0' + q);
-                }
-                /*
-                 * HACK! Java spec sez that we always have at least
-                 * one digit after the . in either F- or E-form output.
-                 * Thus we will need more than one digit if we're using
-                 * E-form
-                 */
-                if ( decExp < -3 || decExp >= 8 ){
-                    high = low = false;
-                }
-                while( ! low && ! high ){
-                    q = b / s;
-                    b = 10 * ( b % s );
-                    m *= 10;
-                    assert q < 10 : q; // excessively large digit
-                    if ( m > 0L ){
-                        low  = (b <  m );
-                        high = (b+m > tens );
-                    } else {
-                        // hack -- m might overflow!
-                        // in this case, it is certainly > b,
-                        // which won't
-                        // and b+m > tens, too, since that has overflowed
-                        // either!
-                        low = true;
-                        high = true;
-                    }
-                    digits[ndigit++] = (char)('0' + q);
-                }
-                lowDigitDifference = (b<<1) - tens;
-                exactDecimalConversion  = (b == 0);
-            } else {
-                // still good! they're all longs!
-                long b = (fractBits * long5pow[B5] ) << B2;
-                long s = long5pow[S5] << S2;
-                long m = long5pow[M5] << M2;
-                long tens = s * 10L;
-                /*
-                 * Unroll the first iteration. If our decExp estimate
-                 * was too high, our first quotient will be zero. In this
-                 * case, we discard it and decrement decExp.
-                 */
-                ndigit = 0;
-                q = (int) ( b / s );
-                b = 10L * ( b % s );
-                m *= 10L;
-                low  = (b <  m );
-                high = (b+m > tens );
-                assert q < 10 : q; // excessively large digit
-                if ( (q == 0) && ! high ){
-                    // oops. Usually ignore leading zero.
-                    decExp--;
-                } else {
-                    digits[ndigit++] = (char)('0' + q);
-                }
-                /*
-                 * HACK! Java spec sez that we always have at least
-                 * one digit after the . in either F- or E-form output.
-                 * Thus we will need more than one digit if we're using
-                 * E-form
-                 */
-                if ( decExp < -3 || decExp >= 8 ){
-                    high = low = false;
-                }
-                while( ! low && ! high ){
-                    q = (int) ( b / s );
-                    b = 10 * ( b % s );
-                    m *= 10;
-                    assert q < 10 : q;  // excessively large digit
-                    if ( m > 0L ){
-                        low  = (b <  m );
-                        high = (b+m > tens );
-                    } else {
-                        // hack -- m might overflow!
-                        // in this case, it is certainly > b,
-                        // which won't
-                        // and b+m > tens, too, since that has overflowed
-                        // either!
-                        low = true;
-                        high = true;
-                    }
-                    digits[ndigit++] = (char)('0' + q);
-                }
-                lowDigitDifference = (b<<1) - tens;
-                exactDecimalConversion  = (b == 0);
-            }
-        } else {
-            OldFDBigIntForTest ZeroVal = new OldFDBigIntForTest(0);
-            OldFDBigIntForTest tenSval;
-            int  shiftBias;
-
-            /*
-             * We really must do OldFDBigIntForTest arithmetic.
-             * Fist, construct our OldFDBigIntForTest initial values.
-             */
-            Bval = multPow52( new OldFDBigIntForTest( fractBits  ), B5, B2 );
-            Sval = constructPow52( S5, S2 );
-            Mval = constructPow52( M5, M2 );
-
-
-            // normalize so that division works better
-            Bval.lshiftMe( shiftBias = Sval.normalizeMe() );
-            Mval.lshiftMe( shiftBias );
-            tenSval = Sval.mult( 10 );
-            /*
-             * Unroll the first iteration. If our decExp estimate
-             * was too high, our first quotient will be zero. In this
-             * case, we discard it and decrement decExp.
-             */
-            ndigit = 0;
-            q = Bval.quoRemIteration( Sval );
-            Mval = Mval.mult( 10 );
-            low  = (Bval.cmp( Mval ) < 0);
-            high = (Bval.add( Mval ).cmp( tenSval ) > 0 );
-            assert q < 10 : q; // excessively large digit
-            if ( (q == 0) && ! high ){
-                // oops. Usually ignore leading zero.
-                decExp--;
-            } else {
-                digits[ndigit++] = (char)('0' + q);
-            }
-            /*
-             * HACK! Java spec sez that we always have at least
-             * one digit after the . in either F- or E-form output.
-             * Thus we will need more than one digit if we're using
-             * E-form
-             */
-            if ( decExp < -3 || decExp >= 8 ){
-                high = low = false;
-            }
-            while( ! low && ! high ){
-                q = Bval.quoRemIteration( Sval );
-                Mval = Mval.mult( 10 );
-                assert q < 10 : q;  // excessively large digit
-                low  = (Bval.cmp( Mval ) < 0);
-                high = (Bval.add( Mval ).cmp( tenSval ) > 0 );
-                digits[ndigit++] = (char)('0' + q);
-            }
-            if ( high && low ){
-                Bval.lshiftMe(1);
-                lowDigitDifference = Bval.cmp(tenSval);
-            } else {
-                lowDigitDifference = 0L; // this here only for flow analysis!
-            }
-            exactDecimalConversion  = (Bval.cmp( ZeroVal ) == 0);
-        }
-        this.decExponent = decExp+1;
-        this.digits = digits;
-        this.nDigits = ndigit;
-        /*
-         * Last digit gets rounded based on stopping condition.
-         */
-        if ( high ){
-            if ( low ){
-                if ( lowDigitDifference == 0L ){
-                    // it's a tie!
-                    // choose based on which digits we like.
-                    if ( (digits[nDigits-1]&1) != 0 ) roundup();
-                } else if ( lowDigitDifference > 0 ){
-                    roundup();
-                }
-            } else {
-                roundup();
-            }
-        }
-    }
-
-    public boolean decimalDigitsExact() {
-        return exactDecimalConversion;
-    }
-
-    public String
-    toString(){
-        // most brain-dead version
-        StringBuffer result = new StringBuffer( nDigits+8 );
-        if ( isNegative ){ result.append( '-' ); }
-        if ( isExceptional ){
-            result.append( digits, 0, nDigits );
-        } else {
-            result.append( "0.");
-            result.append( digits, 0, nDigits );
-            result.append('e');
-            result.append( decExponent );
-        }
-        return new String(result);
-    }
-
-    public String toJavaFormatString() {
-        char result[] = perThreadBuffer.get();
-        int i = getChars(result);
-        return new String(result, 0, i);
-    }
-
-    private int getChars(char[] result) {
-        assert nDigits <= 19 : nDigits; // generous bound on size of nDigits
-        int i = 0;
-        if (isNegative) { result[0] = '-'; i = 1; }
-        if (isExceptional) {
-            System.arraycopy(digits, 0, result, i, nDigits);
-            i += nDigits;
-        } else {
-            if (decExponent > 0 && decExponent < 8) {
-                // print digits.digits.
-                int charLength = Math.min(nDigits, decExponent);
-                System.arraycopy(digits, 0, result, i, charLength);
-                i += charLength;
-                if (charLength < decExponent) {
-                    charLength = decExponent-charLength;
-                    System.arraycopy(zero, 0, result, i, charLength);
-                    i += charLength;
-                    result[i++] = '.';
-                    result[i++] = '0';
-                } else {
-                    result[i++] = '.';
-                    if (charLength < nDigits) {
-                        int t = nDigits - charLength;
-                        System.arraycopy(digits, charLength, result, i, t);
-                        i += t;
-                    } else {
-                        result[i++] = '0';
-                    }
-                }
-            } else if (decExponent <=0 && decExponent > -3) {
-                result[i++] = '0';
-                result[i++] = '.';
-                if (decExponent != 0) {
-                    System.arraycopy(zero, 0, result, i, -decExponent);
-                    i -= decExponent;
-                }
-                System.arraycopy(digits, 0, result, i, nDigits);
-                i += nDigits;
-            } else {
-                result[i++] = digits[0];
-                result[i++] = '.';
-                if (nDigits > 1) {
-                    System.arraycopy(digits, 1, result, i, nDigits-1);
-                    i += nDigits-1;
-                } else {
-                    result[i++] = '0';
-                }
-                result[i++] = 'E';
-                int e;
-                if (decExponent <= 0) {
-                    result[i++] = '-';
-                    e = -decExponent+1;
-                } else {
-                    e = decExponent-1;
-                }
-                // decExponent has 1, 2, or 3, digits
-                if (e <= 9) {
-                    result[i++] = (char)(e+'0');
-                } else if (e <= 99) {
-                    result[i++] = (char)(e/10 +'0');
-                    result[i++] = (char)(e%10 + '0');
-                } else {
-                    result[i++] = (char)(e/100+'0');
-                    e %= 100;
-                    result[i++] = (char)(e/10+'0');
-                    result[i++] = (char)(e%10 + '0');
-                }
-            }
-        }
-        return i;
-    }
-
-    // Per-thread buffer for string/stringbuffer conversion
-    private static ThreadLocal<char[]> perThreadBuffer = new ThreadLocal<char[]>() {
-            protected synchronized char[] initialValue() {
-                return new char[26];
-            }
-        };
-
-    public void appendTo(Appendable buf) {
-          char result[] = perThreadBuffer.get();
-          int i = getChars(result);
-        if (buf instanceof StringBuilder)
-            ((StringBuilder) buf).append(result, 0, i);
-        else if (buf instanceof StringBuffer)
-            ((StringBuffer) buf).append(result, 0, i);
-        else
-            assert false;
-    }
-
-    @SuppressWarnings("fallthrough")
-    public static OldFloatingDecimalForTest
-    readJavaFormatString( String in ) throws NumberFormatException {
-        boolean isNegative = false;
-        boolean signSeen   = false;
-        int     decExp;
-        char    c;
-
-    parseNumber:
-        try{
-            in = in.trim(); // don't fool around with white space.
-                            // throws NullPointerException if null
-            int l = in.length();
-            if ( l == 0 ) throw new NumberFormatException("empty String");
-            int i = 0;
-            switch ( c = in.charAt( i ) ){
-            case '-':
-                isNegative = true;
-                //FALLTHROUGH
-            case '+':
-                i++;
-                signSeen = true;
-            }
-
-            // Check for NaN and Infinity strings
-            c = in.charAt(i);
-            if(c == 'N' || c == 'I') { // possible NaN or infinity
-                boolean potentialNaN = false;
-                char targetChars[] = null;  // char array of "NaN" or "Infinity"
-
-                if(c == 'N') {
-                    targetChars = notANumber;
-                    potentialNaN = true;
-                } else {
-                    targetChars = infinity;
-                }
-
-                // compare Input string to "NaN" or "Infinity"
-                int j = 0;
-                while(i < l && j < targetChars.length) {
-                    if(in.charAt(i) == targetChars[j]) {
-                        i++; j++;
-                    }
-                    else // something is amiss, throw exception
-                        break parseNumber;
-                }
-
-                // For the candidate string to be a NaN or infinity,
-                // all characters in input string and target char[]
-                // must be matched ==> j must equal targetChars.length
-                // and i must equal l
-                if( (j == targetChars.length) && (i == l) ) { // return NaN or infinity
-                    return (potentialNaN ? new OldFloatingDecimalForTest(Double.NaN) // NaN has no sign
-                            : new OldFloatingDecimalForTest(isNegative?
-                                                  Double.NEGATIVE_INFINITY:
-                                                  Double.POSITIVE_INFINITY)) ;
-                }
-                else { // something went wrong, throw exception
-                    break parseNumber;
-                }
-
-            } else if (c == '0')  { // check for hexadecimal floating-point number
-                if (l > i+1 ) {
-                    char ch = in.charAt(i+1);
-                    if (ch == 'x' || ch == 'X' ) // possible hex string
-                        return parseHexString(in);
-                }
-            }  // look for and process decimal floating-point string
-
-            char[] digits = new char[ l ];
-            int    nDigits= 0;
-            boolean decSeen = false;
-            int decPt = 0;
-            int nLeadZero = 0;
-            int nTrailZero= 0;
-        digitLoop:
-            while ( i < l ){
-                switch ( c = in.charAt( i ) ){
-                case '0':
-                    if ( nDigits > 0 ){
-                        nTrailZero += 1;
-                    } else {
-                        nLeadZero += 1;
-                    }
-                    break; // out of switch.
-                case '1':
-                case '2':
-                case '3':
-                case '4':
-                case '5':
-                case '6':
-                case '7':
-                case '8':
-                case '9':
-                    while ( nTrailZero > 0 ){
-                        digits[nDigits++] = '0';
-                        nTrailZero -= 1;
-                    }
-                    digits[nDigits++] = c;
-                    break; // out of switch.
-                case '.':
-                    if ( decSeen ){
-                        // already saw one ., this is the 2nd.
-                        throw new NumberFormatException("multiple points");
-                    }
-                    decPt = i;
-                    if ( signSeen ){
-                        decPt -= 1;
-                    }
-                    decSeen = true;
-                    break; // out of switch.
-                default:
-                    break digitLoop;
-                }
-                i++;
-            }
-            /*
-             * At this point, we've scanned all the digits and decimal
-             * point we're going to see. Trim off leading and trailing
-             * zeros, which will just confuse us later, and adjust
-             * our initial decimal exponent accordingly.
-             * To review:
-             * we have seen i total characters.
-             * nLeadZero of them were zeros before any other digits.
-             * nTrailZero of them were zeros after any other digits.
-             * if ( decSeen ), then a . was seen after decPt characters
-             * ( including leading zeros which have been discarded )
-             * nDigits characters were neither lead nor trailing
-             * zeros, nor point
-             */
-            /*
-             * special hack: if we saw no non-zero digits, then the
-             * answer is zero!
-             * Unfortunately, we feel honor-bound to keep parsing!
-             */
-            if ( nDigits == 0 ){
-                digits = zero;
-                nDigits = 1;
-                if ( nLeadZero == 0 ){
-                    // we saw NO DIGITS AT ALL,
-                    // not even a crummy 0!
-                    // this is not allowed.
-                    break parseNumber; // go throw exception
-                }
-
-            }
-
-            /* Our initial exponent is decPt, adjusted by the number of
-             * discarded zeros. Or, if there was no decPt,
-             * then its just nDigits adjusted by discarded trailing zeros.
-             */
-            if ( decSeen ){
-                decExp = decPt - nLeadZero;
-            } else {
-                decExp = nDigits+nTrailZero;
-            }
-
-            /*
-             * Look for 'e' or 'E' and an optionally signed integer.
-             */
-            if ( (i < l) &&  (((c = in.charAt(i) )=='e') || (c == 'E') ) ){
-                int expSign = 1;
-                int expVal  = 0;
-                int reallyBig = Integer.MAX_VALUE / 10;
-                boolean expOverflow = false;
-                switch( in.charAt(++i) ){
-                case '-':
-                    expSign = -1;
-                    //FALLTHROUGH
-                case '+':
-                    i++;
-                }
-                int expAt = i;
-            expLoop:
-                while ( i < l  ){
-                    if ( expVal >= reallyBig ){
-                        // the next character will cause integer
-                        // overflow.
-                        expOverflow = true;
-                    }
-                    switch ( c = in.charAt(i++) ){
-                    case '0':
-                    case '1':
-                    case '2':
-                    case '3':
-                    case '4':
-                    case '5':
-                    case '6':
-                    case '7':
-                    case '8':
-                    case '9':
-                        expVal = expVal*10 + ( (int)c - (int)'0' );
-                        continue;
-                    default:
-                        i--;           // back up.
-                        break expLoop; // stop parsing exponent.
-                    }
-                }
-                int expLimit = bigDecimalExponent+nDigits+nTrailZero;
-                if ( expOverflow || ( expVal > expLimit ) ){
-                    //
-                    // The intent here is to end up with
-                    // infinity or zero, as appropriate.
-                    // The reason for yielding such a small decExponent,
-                    // rather than something intuitive such as
-                    // expSign*Integer.MAX_VALUE, is that this value
-                    // is subject to further manipulation in
-                    // doubleValue() and floatValue(), and I don't want
-                    // it to be able to cause overflow there!
-                    // (The only way we can get into trouble here is for
-                    // really outrageous nDigits+nTrailZero, such as 2 billion. )
-                    //
-                    decExp = expSign*expLimit;
-                } else {
-                    // this should not overflow, since we tested
-                    // for expVal > (MAX+N), where N >= abs(decExp)
-                    decExp = decExp + expSign*expVal;
-                }
-
-                // if we saw something not a digit ( or end of string )
-                // after the [Ee][+-], without seeing any digits at all
-                // this is certainly an error. If we saw some digits,
-                // but then some trailing garbage, that might be ok.
-                // so we just fall through in that case.
-                // HUMBUG
-                if ( i == expAt )
-                    break parseNumber; // certainly bad
-            }
-            /*
-             * We parsed everything we could.
-             * If there are leftovers, then this is not good input!
-             */
-            if ( i < l &&
-                ((i != l - 1) ||
-                (in.charAt(i) != 'f' &&
-                 in.charAt(i) != 'F' &&
-                 in.charAt(i) != 'd' &&
-                 in.charAt(i) != 'D'))) {
-                break parseNumber; // go throw exception
-            }
-
-            return new OldFloatingDecimalForTest( isNegative, decExp, digits, nDigits,  false );
-        } catch ( StringIndexOutOfBoundsException e ){ }
-        throw new NumberFormatException("For input string: \"" + in + "\"");
-    }
-
-    /*
-     * Take a FloatingDecimal, which we presumably just scanned in,
-     * and find out what its value is, as a double.
-     *
-     * AS A SIDE EFFECT, SET roundDir TO INDICATE PREFERRED
-     * ROUNDING DIRECTION in case the result is really destined
-     * for a single-precision float.
-     */
-
-    public strictfp double doubleValue(){
-        int     kDigits = Math.min( nDigits, maxDecimalDigits+1 );
-        long    lValue;
-        double  dValue;
-        double  rValue, tValue;
-
-        // First, check for NaN and Infinity values
-        if(digits == infinity || digits == notANumber) {
-            if(digits == notANumber)
-                return Double.NaN;
-            else
-                return (isNegative?Double.NEGATIVE_INFINITY:Double.POSITIVE_INFINITY);
-        }
-        else {
-            if (mustSetRoundDir) {
-                roundDir = 0;
-            }
-            /*
-             * convert the lead kDigits to a long integer.
-             */
-            // (special performance hack: start to do it using int)
-            int iValue = (int)digits[0]-(int)'0';
-            int iDigits = Math.min( kDigits, intDecimalDigits );
-            for ( int i=1; i < iDigits; i++ ){
-                iValue = iValue*10 + (int)digits[i]-(int)'0';
-            }
-            lValue = (long)iValue;
-            for ( int i=iDigits; i < kDigits; i++ ){
-                lValue = lValue*10L + (long)((int)digits[i]-(int)'0');
-            }
-            dValue = (double)lValue;
-            int exp = decExponent-kDigits;
-            /*
-             * lValue now contains a long integer with the value of
-             * the first kDigits digits of the number.
-             * dValue contains the (double) of the same.
-             */
-
-            if ( nDigits <= maxDecimalDigits ){
-                /*
-                 * possibly an easy case.
-                 * We know that the digits can be represented
-                 * exactly. And if the exponent isn't too outrageous,
-                 * the whole thing can be done with one operation,
-                 * thus one rounding error.
-                 * Note that all our constructors trim all leading and
-                 * trailing zeros, so simple values (including zero)
-                 * will always end up here
-                 */
-                if (exp == 0 || dValue == 0.0)
-                    return (isNegative)? -dValue : dValue; // small floating integer
-                else if ( exp >= 0 ){
-                    if ( exp <= maxSmallTen ){
-                        /*
-                         * Can get the answer with one operation,
-                         * thus one roundoff.
-                         */
-                        rValue = dValue * small10pow[exp];
-                        if ( mustSetRoundDir ){
-                            tValue = rValue / small10pow[exp];
-                            roundDir = ( tValue ==  dValue ) ? 0
-                                :( tValue < dValue ) ? 1
-                                : -1;
-                        }
-                        return (isNegative)? -rValue : rValue;
-                    }
-                    int slop = maxDecimalDigits - kDigits;
-                    if ( exp <= maxSmallTen+slop ){
-                        /*
-                         * We can multiply dValue by 10^(slop)
-                         * and it is still "small" and exact.
-                         * Then we can multiply by 10^(exp-slop)
-                         * with one rounding.
-                         */
-                        dValue *= small10pow[slop];
-                        rValue = dValue * small10pow[exp-slop];
-
-                        if ( mustSetRoundDir ){
-                            tValue = rValue / small10pow[exp-slop];
-                            roundDir = ( tValue ==  dValue ) ? 0
-                                :( tValue < dValue ) ? 1
-                                : -1;
-                        }
-                        return (isNegative)? -rValue : rValue;
-                    }
-                    /*
-                     * Else we have a hard case with a positive exp.
-                     */
-                } else {
-                    if ( exp >= -maxSmallTen ){
-                        /*
-                         * Can get the answer in one division.
-                         */
-                        rValue = dValue / small10pow[-exp];
-                        tValue = rValue * small10pow[-exp];
-                        if ( mustSetRoundDir ){
-                            roundDir = ( tValue ==  dValue ) ? 0
-                                :( tValue < dValue ) ? 1
-                                : -1;
-                        }
-                        return (isNegative)? -rValue : rValue;
-                    }
-                    /*
-                     * Else we have a hard case with a negative exp.
-                     */
-                }
-            }
-
-            /*
-             * Harder cases:
-             * The sum of digits plus exponent is greater than
-             * what we think we can do with one error.
-             *
-             * Start by approximating the right answer by,
-             * naively, scaling by powers of 10.
-             */
-            if ( exp > 0 ){
-                if ( decExponent > maxDecimalExponent+1 ){
-                    /*
-                     * Lets face it. This is going to be
-                     * Infinity. Cut to the chase.
-                     */
-                    return (isNegative)? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
-                }
-                if ( (exp&15) != 0 ){
-                    dValue *= small10pow[exp&15];
-                }
-                if ( (exp>>=4) != 0 ){
-                    int j;
-                    for( j = 0; exp > 1; j++, exp>>=1 ){
-                        if ( (exp&1)!=0)
-                            dValue *= big10pow[j];
-                    }
-                    /*
-                     * The reason for the weird exp > 1 condition
-                     * in the above loop was so that the last multiply
-                     * would get unrolled. We handle it here.
-                     * It could overflow.
-                     */
-                    double t = dValue * big10pow[j];
-                    if ( Double.isInfinite( t ) ){
-                        /*
-                         * It did overflow.
-                         * Look more closely at the result.
-                         * If the exponent is just one too large,
-                         * then use the maximum finite as our estimate
-                         * value. Else call the result infinity
-                         * and punt it.
-                         * ( I presume this could happen because
-                         * rounding forces the result here to be
-                         * an ULP or two larger than
-                         * Double.MAX_VALUE ).
-                         */
-                        t = dValue / 2.0;
-                        t *= big10pow[j];
-                        if ( Double.isInfinite( t ) ){
-                            return (isNegative)? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
-                        }
-                        t = Double.MAX_VALUE;
-                    }
-                    dValue = t;
-                }
-            } else if ( exp < 0 ){
-                exp = -exp;
-                if ( decExponent < minDecimalExponent-1 ){
-                    /*
-                     * Lets face it. This is going to be
-                     * zero. Cut to the chase.
-                     */
-                    return (isNegative)? -0.0 : 0.0;
-                }
-                if ( (exp&15) != 0 ){
-                    dValue /= small10pow[exp&15];
-                }
-                if ( (exp>>=4) != 0 ){
-                    int j;
-                    for( j = 0; exp > 1; j++, exp>>=1 ){
-                        if ( (exp&1)!=0)
-                            dValue *= tiny10pow[j];
-                    }
-                    /*
-                     * The reason for the weird exp > 1 condition
-                     * in the above loop was so that the last multiply
-                     * would get unrolled. We handle it here.
-                     * It could underflow.
-                     */
-                    double t = dValue * tiny10pow[j];
-                    if ( t == 0.0 ){
-                        /*
-                         * It did underflow.
-                         * Look more closely at the result.
-                         * If the exponent is just one too small,
-                         * then use the minimum finite as our estimate
-                         * value. Else call the result 0.0
-                         * and punt it.
-                         * ( I presume this could happen because
-                         * rounding forces the result here to be
-                         * an ULP or two less than
-                         * Double.MIN_VALUE ).
-                         */
-                        t = dValue * 2.0;
-                        t *= tiny10pow[j];
-                        if ( t == 0.0 ){
-                            return (isNegative)? -0.0 : 0.0;
-                        }
-                        t = Double.MIN_VALUE;
-                    }
-                    dValue = t;
-                }
-            }
-
-            /*
-             * dValue is now approximately the result.
-             * The hard part is adjusting it, by comparison
-             * with OldFDBigIntForTest arithmetic.
-             * Formulate the EXACT big-number result as
-             * bigD0 * 10^exp
-             */
-            OldFDBigIntForTest bigD0 = new OldFDBigIntForTest( lValue, digits, kDigits, nDigits );
-            exp   = decExponent - nDigits;
-
-            correctionLoop:
-            while(true){
-                /* AS A SIDE EFFECT, THIS METHOD WILL SET THE INSTANCE VARIABLES
-                 * bigIntExp and bigIntNBits
-                 */
-                OldFDBigIntForTest bigB = doubleToBigInt( dValue );
-
-                /*
-                 * Scale bigD, bigB appropriately for
-                 * big-integer operations.
-                 * Naively, we multiply by powers of ten
-                 * and powers of two. What we actually do
-                 * is keep track of the powers of 5 and
-                 * powers of 2 we would use, then factor out
-                 * common divisors before doing the work.
-                 */
-                int B2, B5; // powers of 2, 5 in bigB
-                int     D2, D5; // powers of 2, 5 in bigD
-                int Ulp2;   // powers of 2 in halfUlp.
-                if ( exp >= 0 ){
-                    B2 = B5 = 0;
-                    D2 = D5 = exp;
-                } else {
-                    B2 = B5 = -exp;
-                    D2 = D5 = 0;
-                }
-                if ( bigIntExp >= 0 ){
-                    B2 += bigIntExp;
-                } else {
-                    D2 -= bigIntExp;
-                }
-                Ulp2 = B2;
-                // shift bigB and bigD left by a number s. t.
-                // halfUlp is still an integer.
-                int hulpbias;
-                if ( bigIntExp+bigIntNBits <= -expBias+1 ){
-                    // This is going to be a denormalized number
-                    // (if not actually zero).
-                    // half an ULP is at 2^-(expBias+expShift+1)
-                    hulpbias = bigIntExp+ expBias + expShift;
-                } else {
-                    hulpbias = expShift + 2 - bigIntNBits;
-                }
-                B2 += hulpbias;
-                D2 += hulpbias;
-                // if there are common factors of 2, we might just as well
-                // factor them out, as they add nothing useful.
-                int common2 = Math.min( B2, Math.min( D2, Ulp2 ) );
-                B2 -= common2;
-                D2 -= common2;
-                Ulp2 -= common2;
-                // do multiplications by powers of 5 and 2
-                bigB = multPow52( bigB, B5, B2 );
-                OldFDBigIntForTest bigD = multPow52( new OldFDBigIntForTest( bigD0 ), D5, D2 );
-                //
-                // to recap:
-                // bigB is the scaled-big-int version of our floating-point
-                // candidate.
-                // bigD is the scaled-big-int version of the exact value
-                // as we understand it.
-                // halfUlp is 1/2 an ulp of bigB, except for special cases
-                // of exact powers of 2
-                //
-                // the plan is to compare bigB with bigD, and if the difference
-                // is less than halfUlp, then we're satisfied. Otherwise,
-                // use the ratio of difference to halfUlp to calculate a fudge
-                // factor to add to the floating value, then go 'round again.
-                //
-                OldFDBigIntForTest diff;
-                int cmpResult;
-                boolean overvalue;
-                if ( (cmpResult = bigB.cmp( bigD ) ) > 0 ){
-                    overvalue = true; // our candidate is too big.
-                    diff = bigB.sub( bigD );
-                    if ( (bigIntNBits == 1) && (bigIntExp > -expBias+1) ){
-                        // candidate is a normalized exact power of 2 and
-                        // is too big. We will be subtracting.
-                        // For our purposes, ulp is the ulp of the
-                        // next smaller range.
-                        Ulp2 -= 1;
-                        if ( Ulp2 < 0 ){
-                            // rats. Cannot de-scale ulp this far.
-                            // must scale diff in other direction.
-                            Ulp2 = 0;
-                            diff.lshiftMe( 1 );
-                        }
-                    }
-                } else if ( cmpResult < 0 ){
-                    overvalue = false; // our candidate is too small.
-                    diff = bigD.sub( bigB );
-                } else {
-                    // the candidate is exactly right!
-                    // this happens with surprising frequency
-                    break correctionLoop;
-                }
-                OldFDBigIntForTest halfUlp = constructPow52( B5, Ulp2 );
-                if ( (cmpResult = diff.cmp( halfUlp ) ) < 0 ){
-                    // difference is small.
-                    // this is close enough
-                    if (mustSetRoundDir) {
-                        roundDir = overvalue ? -1 : 1;
-                    }
-                    break correctionLoop;
-                } else if ( cmpResult == 0 ){
-                    // difference is exactly half an ULP
-                    // round to some other value maybe, then finish
-                    dValue += 0.5*ulp( dValue, overvalue );
-                    // should check for bigIntNBits == 1 here??
-                    if (mustSetRoundDir) {
-                        roundDir = overvalue ? -1 : 1;
-                    }
-                    break correctionLoop;
-                } else {
-                    // difference is non-trivial.
-                    // could scale addend by ratio of difference to
-                    // halfUlp here, if we bothered to compute that difference.
-                    // Most of the time ( I hope ) it is about 1 anyway.
-                    dValue += ulp( dValue, overvalue );
-                    if ( dValue == 0.0 || dValue == Double.POSITIVE_INFINITY )
-                        break correctionLoop; // oops. Fell off end of range.
-                    continue; // try again.
-                }
-
-            }
-            return (isNegative)? -dValue : dValue;
-        }
-    }
-
-    /*
-     * Take a FloatingDecimal, which we presumably just scanned in,
-     * and find out what its value is, as a float.
-     * This is distinct from doubleValue() to avoid the extremely
-     * unlikely case of a double rounding error, wherein the conversion
-     * to double has one rounding error, and the conversion of that double
-     * to a float has another rounding error, IN THE WRONG DIRECTION,
-     * ( because of the preference to a zero low-order bit ).
-     */
-
-    public strictfp float floatValue(){
-        int     kDigits = Math.min( nDigits, singleMaxDecimalDigits+1 );
-        int     iValue;
-        float   fValue;
-
-        // First, check for NaN and Infinity values
-        if(digits == infinity || digits == notANumber) {
-            if(digits == notANumber)
-                return Float.NaN;
-            else
-                return (isNegative?Float.NEGATIVE_INFINITY:Float.POSITIVE_INFINITY);
-        }
-        else {
-            /*
-             * convert the lead kDigits to an integer.
-             */
-            iValue = (int)digits[0]-(int)'0';
-            for ( int i=1; i < kDigits; i++ ){
-                iValue = iValue*10 + (int)digits[i]-(int)'0';
-            }
-            fValue = (float)iValue;
-            int exp = decExponent-kDigits;
-            /*
-             * iValue now contains an integer with the value of
-             * the first kDigits digits of the number.
-             * fValue contains the (float) of the same.
-             */
-
-            if ( nDigits <= singleMaxDecimalDigits ){
-                /*
-                 * possibly an easy case.
-                 * We know that the digits can be represented
-                 * exactly. And if the exponent isn't too outrageous,
-                 * the whole thing can be done with one operation,
-                 * thus one rounding error.
-                 * Note that all our constructors trim all leading and
-                 * trailing zeros, so simple values (including zero)
-                 * will always end up here.
-                 */
-                if (exp == 0 || fValue == 0.0f)
-                    return (isNegative)? -fValue : fValue; // small floating integer
-                else if ( exp >= 0 ){
-                    if ( exp <= singleMaxSmallTen ){
-                        /*
-                         * Can get the answer with one operation,
-                         * thus one roundoff.
-                         */
-                        fValue *= singleSmall10pow[exp];
-                        return (isNegative)? -fValue : fValue;
-                    }
-                    int slop = singleMaxDecimalDigits - kDigits;
-                    if ( exp <= singleMaxSmallTen+slop ){
-                        /*
-                         * We can multiply dValue by 10^(slop)
-                         * and it is still "small" and exact.
-                         * Then we can multiply by 10^(exp-slop)
-                         * with one rounding.
-                         */
-                        fValue *= singleSmall10pow[slop];
-                        fValue *= singleSmall10pow[exp-slop];
-                        return (isNegative)? -fValue : fValue;
-                    }
-                    /*
-                     * Else we have a hard case with a positive exp.
-                     */
-                } else {
-                    if ( exp >= -singleMaxSmallTen ){
-                        /*
-                         * Can get the answer in one division.
-                         */
-                        fValue /= singleSmall10pow[-exp];
-                        return (isNegative)? -fValue : fValue;
-                    }
-                    /*
-                     * Else we have a hard case with a negative exp.
-                     */
-                }
-            } else if ( (decExponent >= nDigits) && (nDigits+decExponent <= maxDecimalDigits) ){
-                /*
-                 * In double-precision, this is an exact floating integer.
-                 * So we can compute to double, then shorten to float
-                 * with one round, and get the right answer.
-                 *
-                 * First, finish accumulating digits.
-                 * Then convert that integer to a double, multiply
-                 * by the appropriate power of ten, and convert to float.
-                 */
-                long lValue = (long)iValue;
-                for ( int i=kDigits; i < nDigits; i++ ){
-                    lValue = lValue*10L + (long)((int)digits[i]-(int)'0');
-                }
-                double dValue = (double)lValue;
-                exp = decExponent-nDigits;
-                dValue *= small10pow[exp];
-                fValue = (float)dValue;
-                return (isNegative)? -fValue : fValue;
-
-            }
-            /*
-             * Harder cases:
-             * The sum of digits plus exponent is greater than
-             * what we think we can do with one error.
-             *
-             * Start by weeding out obviously out-of-range
-             * results, then convert to double and go to
-             * common hard-case code.
-             */
-            if ( decExponent > singleMaxDecimalExponent+1 ){
-                /*
-                 * Lets face it. This is going to be
-                 * Infinity. Cut to the chase.
-                 */
-                return (isNegative)? Float.NEGATIVE_INFINITY : Float.POSITIVE_INFINITY;
-            } else if ( decExponent < singleMinDecimalExponent-1 ){
-                /*
-                 * Lets face it. This is going to be
-                 * zero. Cut to the chase.
-                 */
-                return (isNegative)? -0.0f : 0.0f;
-            }
-
-            /*
-             * Here, we do 'way too much work, but throwing away
-             * our partial results, and going and doing the whole
-             * thing as double, then throwing away half the bits that computes
-             * when we convert back to float.
-             *
-             * The alternative is to reproduce the whole multiple-precision
-             * algorithm for float precision, or to try to parameterize it
-             * for common usage. The former will take about 400 lines of code,
-             * and the latter I tried without success. Thus the semi-hack
-             * answer here.
-             */
-            mustSetRoundDir = !fromHex;
-            double dValue = doubleValue();
-            return stickyRound( dValue );
-        }
-    }
-
-
-    /*
-     * All the positive powers of 10 that can be
-     * represented exactly in double/float.
-     */
-    private static final double small10pow[] = {
-        1.0e0,
-        1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5,
-        1.0e6, 1.0e7, 1.0e8, 1.0e9, 1.0e10,
-        1.0e11, 1.0e12, 1.0e13, 1.0e14, 1.0e15,
-        1.0e16, 1.0e17, 1.0e18, 1.0e19, 1.0e20,
-        1.0e21, 1.0e22
-    };
-
-    private static final float singleSmall10pow[] = {
-        1.0e0f,
-        1.0e1f, 1.0e2f, 1.0e3f, 1.0e4f, 1.0e5f,
-        1.0e6f, 1.0e7f, 1.0e8f, 1.0e9f, 1.0e10f
-    };
-
-    private static final double big10pow[] = {
-        1e16, 1e32, 1e64, 1e128, 1e256 };
-    private static final double tiny10pow[] = {
-        1e-16, 1e-32, 1e-64, 1e-128, 1e-256 };
-
-    private static final int maxSmallTen = small10pow.length-1;
-    private static final int singleMaxSmallTen = singleSmall10pow.length-1;
-
-    private static final int small5pow[] = {
-        1,
-        5,
-        5*5,
-        5*5*5,
-        5*5*5*5,
-        5*5*5*5*5,
-        5*5*5*5*5*5,
-        5*5*5*5*5*5*5,
-        5*5*5*5*5*5*5*5,
-        5*5*5*5*5*5*5*5*5,
-        5*5*5*5*5*5*5*5*5*5,
-        5*5*5*5*5*5*5*5*5*5*5,
-        5*5*5*5*5*5*5*5*5*5*5*5,
-        5*5*5*5*5*5*5*5*5*5*5*5*5
-    };
-
-
-    private static final long long5pow[] = {
-        1L,
-        5L,
-        5L*5,
-        5L*5*5,
-        5L*5*5*5,
-        5L*5*5*5*5,
-        5L*5*5*5*5*5,
-        5L*5*5*5*5*5*5,
-        5L*5*5*5*5*5*5*5,
-        5L*5*5*5*5*5*5*5*5,
-        5L*5*5*5*5*5*5*5*5*5,
-        5L*5*5*5*5*5*5*5*5*5*5,
-        5L*5*5*5*5*5*5*5*5*5*5*5,
-        5L*5*5*5*5*5*5*5*5*5*5*5*5,
-        5L*5*5*5*5*5*5*5*5*5*5*5*5*5,
-        5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
-        5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
-        5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
-        5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
-        5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
-        5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
-        5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
-        5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
-        5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
-        5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
-        5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
-        5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
-    };
-
-    // approximately ceil( log2( long5pow[i] ) )
-    private static final int n5bits[] = {
-        0,
-        3,
-        5,
-        7,
-        10,
-        12,
-        14,
-        17,
-        19,
-        21,
-        24,
-        26,
-        28,
-        31,
-        33,
-        35,
-        38,
-        40,
-        42,
-        45,
-        47,
-        49,
-        52,
-        54,
-        56,
-        59,
-        61,
-    };
-
-    private static final char infinity[] = { 'I', 'n', 'f', 'i', 'n', 'i', 't', 'y' };
-    private static final char notANumber[] = { 'N', 'a', 'N' };
-    private static final char zero[] = { '0', '0', '0', '0', '0', '0', '0', '0' };
-
-
-    /*
-     * Grammar is compatible with hexadecimal floating-point constants
-     * described in section 6.4.4.2 of the C99 specification.
-     */
-    private static Pattern hexFloatPattern = null;
-    private static synchronized Pattern getHexFloatPattern() {
-        if (hexFloatPattern == null) {
-           hexFloatPattern = Pattern.compile(
-                   //1           234                   56                7                   8      9
-                    "([-+])?0[xX](((\\p{XDigit}+)\\.?)|((\\p{XDigit}*)\\.(\\p{XDigit}+)))[pP]([-+])?(\\p{Digit}+)[fFdD]?"
-                    );
-        }
-        return hexFloatPattern;
-    }
-
-    /*
-     * Convert string s to a suitable floating decimal; uses the
-     * double constructor and set the roundDir variable appropriately
-     * in case the value is later converted to a float.
-     */
-   static OldFloatingDecimalForTest parseHexString(String s) {
-        // Verify string is a member of the hexadecimal floating-point
-        // string language.
-        Matcher m = getHexFloatPattern().matcher(s);
-        boolean validInput = m.matches();
-
-        if (!validInput) {
-            // Input does not match pattern
-            throw new NumberFormatException("For input string: \"" + s + "\"");
-        } else { // validInput
-            /*
-             * We must isolate the sign, significand, and exponent
-             * fields.  The sign value is straightforward.  Since
-             * floating-point numbers are stored with a normalized
-             * representation, the significand and exponent are
-             * interrelated.
-             *
-             * After extracting the sign, we normalized the
-             * significand as a hexadecimal value, calculating an
-             * exponent adjust for any shifts made during
-             * normalization.  If the significand is zero, the
-             * exponent doesn't need to be examined since the output
-             * will be zero.
-             *
-             * Next the exponent in the input string is extracted.
-             * Afterwards, the significand is normalized as a *binary*
-             * value and the input value's normalized exponent can be
-             * computed.  The significand bits are copied into a
-             * double significand; if the string has more logical bits
-             * than can fit in a double, the extra bits affect the
-             * round and sticky bits which are used to round the final
-             * value.
-             */
-
-            //  Extract significand sign
-            String group1 = m.group(1);
-            double sign = (( group1 == null ) || group1.equals("+"))? 1.0 : -1.0;
-
-
-            //  Extract Significand magnitude
-            /*
-             * Based on the form of the significand, calculate how the
-             * binary exponent needs to be adjusted to create a
-             * normalized *hexadecimal* floating-point number; that
-             * is, a number where there is one nonzero hex digit to
-             * the left of the (hexa)decimal point.  Since we are
-             * adjusting a binary, not hexadecimal exponent, the
-             * exponent is adjusted by a multiple of 4.
-             *
-             * There are a number of significand scenarios to consider;
-             * letters are used in indicate nonzero digits:
-             *
-             * 1. 000xxxx       =>      x.xxx   normalized
-             *    increase exponent by (number of x's - 1)*4
-             *
-             * 2. 000xxx.yyyy =>        x.xxyyyy        normalized
-             *    increase exponent by (number of x's - 1)*4
-             *
-             * 3. .000yyy  =>   y.yy    normalized
-             *    decrease exponent by (number of zeros + 1)*4
-             *
-             * 4. 000.00000yyy => y.yy normalized
-             *    decrease exponent by (number of zeros to right of point + 1)*4
-             *
-             * If the significand is exactly zero, return a properly
-             * signed zero.
-             */
-
-            String significandString =null;
-            int signifLength = 0;
-            int exponentAdjust = 0;
-            {
-                int leftDigits  = 0; // number of meaningful digits to
-                                     // left of "decimal" point
-                                     // (leading zeros stripped)
-                int rightDigits = 0; // number of digits to right of
-                                     // "decimal" point; leading zeros
-                                     // must always be accounted for
-                /*
-                 * The significand is made up of either
-                 *
-                 * 1. group 4 entirely (integer portion only)
-                 *
-                 * OR
-                 *
-                 * 2. the fractional portion from group 7 plus any
-                 * (optional) integer portions from group 6.
-                 */
-                String group4;
-                if( (group4 = m.group(4)) != null) {  // Integer-only significand
-                    // Leading zeros never matter on the integer portion
-                    significandString = stripLeadingZeros(group4);
-                    leftDigits = significandString.length();
-                }
-                else {
-                    // Group 6 is the optional integer; leading zeros
-                    // never matter on the integer portion
-                    String group6 = stripLeadingZeros(m.group(6));
-                    leftDigits = group6.length();
-
-                    // fraction
-                    String group7 = m.group(7);
-                    rightDigits = group7.length();
-
-                    // Turn "integer.fraction" into "integer"+"fraction"
-                    significandString =
-                        ((group6 == null)?"":group6) + // is the null
-                        // check necessary?
-                        group7;
-                }
-
-                significandString = stripLeadingZeros(significandString);
-                signifLength  = significandString.length();
-
-                /*
-                 * Adjust exponent as described above
-                 */
-                if (leftDigits >= 1) {  // Cases 1 and 2
-                    exponentAdjust = 4*(leftDigits - 1);
-                } else {                // Cases 3 and 4
-                    exponentAdjust = -4*( rightDigits - signifLength + 1);
-                }
-
-                // If the significand is zero, the exponent doesn't
-                // matter; return a properly signed zero.
-
-                if (signifLength == 0) { // Only zeros in input
-                    return new OldFloatingDecimalForTest(sign * 0.0);
-                }
-            }
-
-            //  Extract Exponent
-            /*
-             * Use an int to read in the exponent value; this should
-             * provide more than sufficient range for non-contrived
-             * inputs.  If reading the exponent in as an int does
-             * overflow, examine the sign of the exponent and
-             * significand to determine what to do.
-             */
-            String group8 = m.group(8);
-            boolean positiveExponent = ( group8 == null ) || group8.equals("+");
-            long unsignedRawExponent;
-            try {
-                unsignedRawExponent = Integer.parseInt(m.group(9));
-            }
-            catch (NumberFormatException e) {
-                // At this point, we know the exponent is
-                // syntactically well-formed as a sequence of
-                // digits.  Therefore, if an NumberFormatException
-                // is thrown, it must be due to overflowing int's
-                // range.  Also, at this point, we have already
-                // checked for a zero significand.  Thus the signs
-                // of the exponent and significand determine the
-                // final result:
-                //
-                //                      significand
-                //                      +               -
-                // exponent     +       +infinity       -infinity
-                //              -       +0.0            -0.0
-                return new OldFloatingDecimalForTest(sign * (positiveExponent ?
-                                                   Double.POSITIVE_INFINITY : 0.0));
-            }
-
-            long rawExponent =
-                (positiveExponent ? 1L : -1L) * // exponent sign
-                unsignedRawExponent;            // exponent magnitude
-
-            // Calculate partially adjusted exponent
-            long exponent = rawExponent + exponentAdjust ;
-
-            // Starting copying non-zero bits into proper position in
-            // a long; copy explicit bit too; this will be masked
-            // later for normal values.
-
-            boolean round = false;
-            boolean sticky = false;
-            int bitsCopied=0;
-            int nextShift=0;
-            long significand=0L;
-            // First iteration is different, since we only copy
-            // from the leading significand bit; one more exponent
-            // adjust will be needed...
-
-            // IMPORTANT: make leadingDigit a long to avoid
-            // surprising shift semantics!
-            long leadingDigit = getHexDigit(significandString, 0);
-
-            /*
-             * Left shift the leading digit (53 - (bit position of
-             * leading 1 in digit)); this sets the top bit of the
-             * significand to 1.  The nextShift value is adjusted
-             * to take into account the number of bit positions of
-             * the leadingDigit actually used.  Finally, the
-             * exponent is adjusted to normalize the significand
-             * as a binary value, not just a hex value.
-             */
-            if (leadingDigit == 1) {
-                significand |= leadingDigit << 52;
-                nextShift = 52 - 4;
-                /* exponent += 0 */     }
-            else if (leadingDigit <= 3) { // [2, 3]
-                significand |= leadingDigit << 51;
-                nextShift = 52 - 5;
-                exponent += 1;
-            }
-            else if (leadingDigit <= 7) { // [4, 7]
-                significand |= leadingDigit << 50;
-                nextShift = 52 - 6;
-                exponent += 2;
-            }
-            else if (leadingDigit <= 15) { // [8, f]
-                significand |= leadingDigit << 49;
-                nextShift = 52 - 7;
-                exponent += 3;
-            } else {
-                throw new AssertionError("Result from digit conversion too large!");
-            }
-            // The preceding if-else could be replaced by a single
-            // code block based on the high-order bit set in
-            // leadingDigit.  Given leadingOnePosition,
-
-            // significand |= leadingDigit << (SIGNIFICAND_WIDTH - leadingOnePosition);
-            // nextShift = 52 - (3 + leadingOnePosition);
-            // exponent += (leadingOnePosition-1);
-
-
-            /*
-             * Now the exponent variable is equal to the normalized
-             * binary exponent.  Code below will make representation
-             * adjustments if the exponent is incremented after
-             * rounding (includes overflows to infinity) or if the
-             * result is subnormal.
-             */
-
-            // Copy digit into significand until the significand can't
-            // hold another full hex digit or there are no more input
-            // hex digits.
-            int i = 0;
-            for(i = 1;
-                i < signifLength && nextShift >= 0;
-                i++) {
-                long currentDigit = getHexDigit(significandString, i);
-                significand |= (currentDigit << nextShift);
-                nextShift-=4;
-            }
-
-            // After the above loop, the bulk of the string is copied.
-            // Now, we must copy any partial hex digits into the
-            // significand AND compute the round bit and start computing
-            // sticky bit.
-
-            if ( i < signifLength ) { // at least one hex input digit exists
-                long currentDigit = getHexDigit(significandString, i);
-
-                // from nextShift, figure out how many bits need
-                // to be copied, if any
-                switch(nextShift) { // must be negative
-                case -1:
-                    // three bits need to be copied in; can
-                    // set round bit
-                    significand |= ((currentDigit & 0xEL) >> 1);
-                    round = (currentDigit & 0x1L)  != 0L;
-                    break;
-
-                case -2:
-                    // two bits need to be copied in; can
-                    // set round and start sticky
-                    significand |= ((currentDigit & 0xCL) >> 2);
-                    round = (currentDigit &0x2L)  != 0L;
-                    sticky = (currentDigit & 0x1L) != 0;
-                    break;
-
-                case -3:
-                    // one bit needs to be copied in
-                    significand |= ((currentDigit & 0x8L)>>3);
-                    // Now set round and start sticky, if possible
-                    round = (currentDigit &0x4L)  != 0L;
-                    sticky = (currentDigit & 0x3L) != 0;
-                    break;
-
-                case -4:
-                    // all bits copied into significand; set
-                    // round and start sticky
-                    round = ((currentDigit & 0x8L) != 0);  // is top bit set?
-                    // nonzeros in three low order bits?
-                    sticky = (currentDigit & 0x7L) != 0;
-                    break;
-
-                default:
-                    throw new AssertionError("Unexpected shift distance remainder.");
-                    // break;
-                }
-
-                // Round is set; sticky might be set.
-
-                // For the sticky bit, it suffices to check the
-                // current digit and test for any nonzero digits in
-                // the remaining unprocessed input.
-                i++;
-                while(i < signifLength && !sticky) {
-                    currentDigit =  getHexDigit(significandString,i);
-                    sticky = sticky || (currentDigit != 0);
-                    i++;
-                }
-
-            }
-            // else all of string was seen, round and sticky are
-            // correct as false.
-
-
-            // Check for overflow and update exponent accordingly.
-
-            if (exponent > Double.MAX_EXPONENT) {         // Infinite result
-                // overflow to properly signed infinity
-                return new OldFloatingDecimalForTest(sign * Double.POSITIVE_INFINITY);
-            } else {  // Finite return value
-                if (exponent <= Double.MAX_EXPONENT && // (Usually) normal result
-                    exponent >= Double.MIN_EXPONENT) {
-
-                    // The result returned in this block cannot be a
-                    // zero or subnormal; however after the
-                    // significand is adjusted from rounding, we could
-                    // still overflow in infinity.
-
-                    // AND exponent bits into significand; if the
-                    // significand is incremented and overflows from
-                    // rounding, this combination will update the
-                    // exponent correctly, even in the case of
-                    // Double.MAX_VALUE overflowing to infinity.
-
-                    significand = (( (exponent +
-                                     (long)DoubleConsts.EXP_BIAS) <<
-                                     (DoubleConsts.SIGNIFICAND_WIDTH-1))
-                                   & DoubleConsts.EXP_BIT_MASK) |
-                        (DoubleConsts.SIGNIF_BIT_MASK & significand);
-
-                }  else  {  // Subnormal or zero
-                    // (exponent < Double.MIN_EXPONENT)
-
-                    if (exponent < (DoubleConsts.MIN_SUB_EXPONENT -1 )) {
-                        // No way to round back to nonzero value
-                        // regardless of significand if the exponent is
-                        // less than -1075.
-                        return new OldFloatingDecimalForTest(sign * 0.0);
-                    } else { //  -1075 <= exponent <= MIN_EXPONENT -1 = -1023
-                        /*
-                         * Find bit position to round to; recompute
-                         * round and sticky bits, and shift
-                         * significand right appropriately.
-                         */
-
-                        sticky = sticky || round;
-                        round = false;
-
-                        // Number of bits of significand to preserve is
-                        // exponent - abs_min_exp +1
-                        // check:
-                        // -1075 +1074 + 1 = 0
-                        // -1023 +1074 + 1 = 52
-
-                        int bitsDiscarded = 53 -
-                            ((int)exponent - DoubleConsts.MIN_SUB_EXPONENT + 1);
-                        assert bitsDiscarded >= 1 && bitsDiscarded <= 53;
-
-                        // What to do here:
-                        // First, isolate the new round bit
-                        round = (significand & (1L << (bitsDiscarded -1))) != 0L;
-                        if (bitsDiscarded > 1) {
-                            // create mask to update sticky bits; low
-                            // order bitsDiscarded bits should be 1
-                            long mask = ~((~0L) << (bitsDiscarded -1));
-                            sticky = sticky || ((significand & mask) != 0L ) ;
-                        }
-
-                        // Now, discard the bits
-                        significand = significand >> bitsDiscarded;
-
-                        significand = (( ((long)(Double.MIN_EXPONENT -1) + // subnorm exp.
-                                          (long)DoubleConsts.EXP_BIAS) <<
-                                         (DoubleConsts.SIGNIFICAND_WIDTH-1))
-                                       & DoubleConsts.EXP_BIT_MASK) |
-                            (DoubleConsts.SIGNIF_BIT_MASK & significand);
-                    }
-                }
-
-                // The significand variable now contains the currently
-                // appropriate exponent bits too.
-
-                /*
-                 * Determine if significand should be incremented;
-                 * making this determination depends on the least
-                 * significant bit and the round and sticky bits.
-                 *
-                 * Round to nearest even rounding table, adapted from
-                 * table 4.7 in "Computer Arithmetic" by IsraelKoren.
-                 * The digit to the left of the "decimal" point is the
-                 * least significant bit, the digits to the right of
-                 * the point are the round and sticky bits
-                 *
-                 * Number       Round(x)
-                 * x0.00        x0.
-                 * x0.01        x0.
-                 * x0.10        x0.
-                 * x0.11        x1. = x0. +1
-                 * x1.00        x1.
-                 * x1.01        x1.
-                 * x1.10        x1. + 1
-                 * x1.11        x1. + 1
-                 */
-                boolean incremented = false;
-                boolean leastZero  = ((significand & 1L) == 0L);
-                if( (  leastZero  && round && sticky ) ||
-                    ((!leastZero) && round )) {
-                    incremented = true;
-                    significand++;
-                }
-
-                OldFloatingDecimalForTest fd = new OldFloatingDecimalForTest(Math.copySign(
-                                                              Double.longBitsToDouble(significand),
-                                                              sign));
-
-                /*
-                 * Set roundingDir variable field of fd properly so
-                 * that the input string can be properly rounded to a
-                 * float value.  There are two cases to consider:
-                 *
-                 * 1. rounding to double discards sticky bit
-                 * information that would change the result of a float
-                 * rounding (near halfway case between two floats)
-                 *
-                 * 2. rounding to double rounds up when rounding up
-                 * would not occur when rounding to float.
-                 *
-                 * For former case only needs to be considered when
-                 * the bits rounded away when casting to float are all
-                 * zero; otherwise, float round bit is properly set
-                 * and sticky will already be true.
-                 *
-                 * The lower exponent bound for the code below is the
-                 * minimum (normalized) subnormal exponent - 1 since a
-                 * value with that exponent can round up to the
-                 * minimum subnormal value and the sticky bit
-                 * information must be preserved (i.e. case 1).
-                 */
-                if ((exponent >= FloatConsts.MIN_SUB_EXPONENT-1) &&
-                    (exponent <= Float.MAX_EXPONENT ) ){
-                    // Outside above exponent range, the float value
-                    // will be zero or infinity.
-
-                    /*
-                     * If the low-order 28 bits of a rounded double
-                     * significand are 0, the double could be a
-                     * half-way case for a rounding to float.  If the
-                     * double value is a half-way case, the double
-                     * significand may have to be modified to round
-                     * the the right float value (see the stickyRound
-                     * method).  If the rounding to double has lost
-                     * what would be float sticky bit information, the
-                     * double significand must be incremented.  If the
-                     * double value's significand was itself
-                     * incremented, the float value may end up too
-                     * large so the increment should be undone.
-                     */
-                    if ((significand & 0xfffffffL) ==  0x0L) {
-                        // For negative values, the sign of the
-                        // roundDir is the same as for positive values
-                        // since adding 1 increasing the significand's
-                        // magnitude and subtracting 1 decreases the
-                        // significand's magnitude.  If neither round
-                        // nor sticky is true, the double value is
-                        // exact and no adjustment is required for a
-                        // proper float rounding.
-                        if( round || sticky) {
-                            if (leastZero) { // prerounding lsb is 0
-                                // If round and sticky were both true,
-                                // and the least significant
-                                // significand bit were 0, the rounded
-                                // significand would not have its
-                                // low-order bits be zero.  Therefore,
-                                // we only need to adjust the
-                                // significand if round XOR sticky is
-                                // true.
-                                if (round ^ sticky) {
-                                    fd.roundDir =  1;
-                                }
-                            }
-                            else { // prerounding lsb is 1
-                                // If the prerounding lsb is 1 and the
-                                // resulting significand has its
-                                // low-order bits zero, the significand
-                                // was incremented.  Here, we undo the
-                                // increment, which will ensure the
-                                // right guard and sticky bits for the
-                                // float rounding.
-                                if (round)
-                                    fd.roundDir =  -1;
-                            }
-                        }
-                    }
-                }
-
-                fd.fromHex = true;
-                return fd;
-            }
-        }
-    }
-
-    /**
-     * Return <code>s</code> with any leading zeros removed.
-     */
-    static String stripLeadingZeros(String s) {
-        return  s.replaceFirst("^0+", "");
-    }
-
-    /**
-     * Extract a hexadecimal digit from position <code>position</code>
-     * of string <code>s</code>.
-     */
-    static int getHexDigit(String s, int position) {
-        int value = Character.digit(s.charAt(position), 16);
-        if (value <= -1 || value >= 16) {
-            throw new AssertionError("Unexpected failure of digit conversion of " +
-                                     s.charAt(position));
-        }
-        return value;
-    }
-
-
-}
--- a/jdk/test/sun/misc/FloatingDecimal/TestFDBigInteger.java	Thu Dec 24 10:33:21 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,435 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-import java.math.BigInteger;
-import java.util.Random;
-import sun.misc.FDBigInteger;
-
-/**
- * @test
- * @bug 7032154
- * @summary unit testys of sun.misc.FDBigInteger
- * @modules java.base/sun.misc
- * @author Dmitry Nadezhin
- */
-public class TestFDBigInteger {
-
-    private static final int MAX_P5 = 413;
-    private static final int MAX_P2 = 65;
-    private static final long LONG_SIGN_MASK = (1L << 63);
-    private static final BigInteger FIVE = BigInteger.valueOf(5);
-    private static final FDBigInteger MUTABLE_ZERO = FDBigInteger.valueOfPow52(0, 0).leftInplaceSub(FDBigInteger.valueOfPow52(0, 0));
-    private static final FDBigInteger IMMUTABLE_ZERO = FDBigInteger.valueOfPow52(0, 0).leftInplaceSub(FDBigInteger.valueOfPow52(0, 0));
-    private static final FDBigInteger IMMUTABLE_MILLION = genMillion1();
-    private static final FDBigInteger IMMUTABLE_BILLION = genBillion1();
-    private static final FDBigInteger IMMUTABLE_TEN18 = genTen18();
-
-    static {
-        IMMUTABLE_ZERO.makeImmutable();
-        IMMUTABLE_MILLION.makeImmutable();
-        IMMUTABLE_BILLION.makeImmutable();
-        IMMUTABLE_TEN18.makeImmutable();
-    }
-
-    private static FDBigInteger mutable(String hex, int offset) {
-        char[] chars = new BigInteger(hex, 16).toString().toCharArray();
-        return new FDBigInteger(0, chars, 0, chars.length).multByPow52(0, offset * 32);
-    }
-
-    private static FDBigInteger immutable(String hex, int offset) {
-        FDBigInteger fd = mutable(hex, offset);
-        fd.makeImmutable();
-        return fd;
-    }
-
-    private static BigInteger biPow52(int p5, int p2) {
-        return FIVE.pow(p5).shiftLeft(p2);
-    }
-
-    // data.length == 1, nWords == 1, offset == 0
-    private static FDBigInteger genMillion1() {
-        return FDBigInteger.valueOfPow52(6, 0).leftShift(6);
-    }
-
-    // data.length == 2, nWords == 1, offset == 0
-    private static FDBigInteger genMillion2() {
-        return FDBigInteger.valueOfMulPow52(1000000L, 0, 0);
-    }
-
-    // data.length == 1, nWords == 1, offset == 0
-    private static FDBigInteger genBillion1() {
-        return FDBigInteger.valueOfPow52(9, 0).leftShift(9);
-    }
-
-    // data.length == 2, nWords == 2, offset == 0
-    private static FDBigInteger genTen18() {
-        return FDBigInteger.valueOfPow52(18, 0).leftShift(18);
-    }
-
-    private static void check(BigInteger expected, FDBigInteger actual, String message) throws Exception {
-        if (!expected.equals(actual.toBigInteger())) {
-            throw new Exception(message + " result " + actual.toHexString() + " expected " + expected.toString(16));
-        }
-    }
-
-    private static void testValueOfPow52(int p5, int p2) throws Exception {
-        check(biPow52(p5, p2), FDBigInteger.valueOfPow52(p5, p2),
-                "valueOfPow52(" + p5 + "," + p2 + ")");
-    }
-
-    private static void testValueOfPow52() throws Exception {
-        for (int p5 = 0; p5 <= MAX_P5; p5++) {
-            for (int p2 = 0; p2 <= MAX_P2; p2++) {
-                testValueOfPow52(p5, p2);
-            }
-        }
-    }
-
-    private static void testValueOfMulPow52(long value, int p5, int p2) throws Exception {
-        BigInteger bi = BigInteger.valueOf(value & ~LONG_SIGN_MASK);
-        if (value < 0) {
-            bi = bi.setBit(63);
-        }
-        check(biPow52(p5, p2).multiply(bi), FDBigInteger.valueOfMulPow52(value, p5, p2),
-                "valueOfMulPow52(" + Long.toHexString(value) + "." + p5 + "," + p2 + ")");
-    }
-
-    private static void testValueOfMulPow52(long value, int p5) throws Exception {
-        testValueOfMulPow52(value, p5, 0);
-        testValueOfMulPow52(value, p5, 1);
-        testValueOfMulPow52(value, p5, 30);
-        testValueOfMulPow52(value, p5, 31);
-        testValueOfMulPow52(value, p5, 33);
-        testValueOfMulPow52(value, p5, 63);
-    }
-
-    private static void testValueOfMulPow52() throws Exception {
-        for (int p5 = 0; p5 <= MAX_P5; p5++) {
-            testValueOfMulPow52(0xFFFFFFFFL, p5);
-            testValueOfMulPow52(0x123456789AL, p5);
-            testValueOfMulPow52(0x7FFFFFFFFFFFFFFFL, p5);
-            testValueOfMulPow52(0xFFFFFFFFFFF54321L, p5);
-        }
-    }
-
-    private static void testLeftShift(FDBigInteger t, int shift, boolean isImmutable) throws Exception {
-        BigInteger bt = t.toBigInteger();
-        FDBigInteger r = t.leftShift(shift);
-        if ((bt.signum() == 0 || shift == 0 || !isImmutable) && r != t) {
-            throw new Exception("leftShift doesn't reuse its argument");
-        }
-        if (isImmutable) {
-            check(bt, t, "leftShift corrupts its argument");
-        }
-        check(bt.shiftLeft(shift), r, "leftShift returns wrong result");
-    }
-
-    private static void testLeftShift() throws Exception {
-        testLeftShift(IMMUTABLE_ZERO, 0, true);
-        testLeftShift(IMMUTABLE_ZERO, 10, true);
-        testLeftShift(MUTABLE_ZERO, 0, false);
-        testLeftShift(MUTABLE_ZERO, 10, false);
-
-        testLeftShift(IMMUTABLE_MILLION, 0, true);
-        testLeftShift(IMMUTABLE_MILLION, 1, true);
-        testLeftShift(IMMUTABLE_MILLION, 12, true);
-        testLeftShift(IMMUTABLE_MILLION, 13, true);
-        testLeftShift(IMMUTABLE_MILLION, 32, true);
-        testLeftShift(IMMUTABLE_MILLION, 33, true);
-        testLeftShift(IMMUTABLE_MILLION, 44, true);
-        testLeftShift(IMMUTABLE_MILLION, 45, true);
-
-        testLeftShift(genMillion1(), 0, false);
-        testLeftShift(genMillion1(), 1, false);
-        testLeftShift(genMillion1(), 12, false);
-        testLeftShift(genMillion1(), 13, false);
-        testLeftShift(genMillion1(), 25, false);
-        testLeftShift(genMillion1(), 26, false);
-        testLeftShift(genMillion1(), 32, false);
-        testLeftShift(genMillion1(), 33, false);
-        testLeftShift(genMillion1(), 44, false);
-        testLeftShift(genMillion1(), 45, false);
-
-        testLeftShift(genMillion2(), 0, false);
-        testLeftShift(genMillion2(), 1, false);
-        testLeftShift(genMillion2(), 12, false);
-        testLeftShift(genMillion2(), 13, false);
-        testLeftShift(genMillion2(), 25, false);
-        testLeftShift(genMillion2(), 26, false);
-        testLeftShift(genMillion2(), 32, false);
-        testLeftShift(genMillion2(), 33, false);
-        testLeftShift(genMillion2(), 44, false);
-        testLeftShift(genMillion2(), 45, false);
-    }
-
-    private static void testQuoRemIteration(FDBigInteger t, FDBigInteger s) throws Exception {
-        BigInteger bt = t.toBigInteger();
-        BigInteger bs = s.toBigInteger();
-        int q = t.quoRemIteration(s);
-        BigInteger[] qr = bt.divideAndRemainder(bs);
-        if (!BigInteger.valueOf(q).equals(qr[0])) {
-            throw new Exception("quoRemIteration returns incorrect quo");
-        }
-        check(qr[1].multiply(BigInteger.TEN), t, "quoRemIteration returns incorrect rem");
-    }
-
-    private static void testQuoRemIteration() throws Exception {
-        // IMMUTABLE_TEN18 == 0de0b6b3a7640000
-        // q = 0
-        testQuoRemIteration(mutable("00000001", 0), IMMUTABLE_TEN18);
-        testQuoRemIteration(mutable("00000001", 1), IMMUTABLE_TEN18);
-        testQuoRemIteration(mutable("0de0b6b2", 1), IMMUTABLE_TEN18);
-        // q = 1 -> q = 0
-        testQuoRemIteration(mutable("0de0b6b3", 1), IMMUTABLE_TEN18);
-        testQuoRemIteration(mutable("0de0b6b3a763FFFF", 0), IMMUTABLE_TEN18);
-        // q = 1
-        testQuoRemIteration(mutable("0de0b6b3a7640000", 0), IMMUTABLE_TEN18);
-        testQuoRemIteration(mutable("0de0b6b3FFFFFFFF", 0), IMMUTABLE_TEN18);
-        testQuoRemIteration(mutable("8ac72304", 1), IMMUTABLE_TEN18);
-        testQuoRemIteration(mutable("0de0b6b400000000", 0), IMMUTABLE_TEN18);
-        testQuoRemIteration(mutable("8ac72305", 1), IMMUTABLE_TEN18);
-        // q = 18
-        testQuoRemIteration(mutable("FFFFFFFF", 1), IMMUTABLE_TEN18);
-    }
-
-    private static void testCmp(FDBigInteger t, FDBigInteger o) throws Exception {
-        BigInteger bt = t.toBigInteger();
-        BigInteger bo = o.toBigInteger();
-        int cmp = t.cmp(o);
-        int bcmp = bt.compareTo(bo);
-        if (bcmp != cmp) {
-            throw new Exception("cmp returns " + cmp + " expected " + bcmp);
-        }
-        check(bt, t, "cmp corrupts this");
-        check(bo, o, "cmp corrupts other");
-        if (o.cmp(t) != -cmp) {
-            throw new Exception("asymmetrical cmp");
-        }
-        check(bt, t, "cmp corrupts this");
-        check(bo, o, "cmp corrupts other");
-    }
-
-    private static void testCmp() throws Exception {
-        testCmp(mutable("FFFFFFFF", 0), mutable("100000000", 0));
-        testCmp(mutable("FFFFFFFF", 0), mutable("1", 1));
-        testCmp(mutable("5", 0), mutable("6", 0));
-        testCmp(mutable("5", 0), mutable("5", 0));
-        testCmp(mutable("5000000001", 0), mutable("500000001", 0));
-        testCmp(mutable("5000000001", 0), mutable("6", 1));
-        testCmp(mutable("5000000001", 0), mutable("5", 1));
-        testCmp(mutable("5000000000", 0), mutable("5", 1));
-    }
-
-    private static void testCmpPow52(FDBigInteger t, int p5, int p2) throws Exception {
-        FDBigInteger o = FDBigInteger.valueOfPow52(p5, p2);
-        BigInteger bt = t.toBigInteger();
-        BigInteger bo = biPow52(p5, p2);
-        int cmp = t.cmp(o);
-        int bcmp = bt.compareTo(bo);
-        if (bcmp != cmp) {
-            throw new Exception("cmpPow52 returns " + cmp + " expected " + bcmp);
-        }
-        check(bt, t, "cmpPow52 corrupts this");
-        check(bo, o, "cmpPow5 corrupts other");
-    }
-
-    private static void testCmpPow52() throws Exception {
-        testCmpPow52(mutable("00000002", 1), 0, 31);
-        testCmpPow52(mutable("00000002", 1), 0, 32);
-        testCmpPow52(mutable("00000002", 1), 0, 33);
-        testCmpPow52(mutable("00000002", 1), 0, 34);
-        testCmpPow52(mutable("00000002", 1), 0, 64);
-        testCmpPow52(mutable("00000003", 1), 0, 32);
-        testCmpPow52(mutable("00000003", 1), 0, 33);
-        testCmpPow52(mutable("00000003", 1), 0, 34);
-    }
-
-    private static void testAddAndCmp(FDBigInteger t, FDBigInteger x, FDBigInteger y) throws Exception {
-        BigInteger bt = t.toBigInteger();
-        BigInteger bx = x.toBigInteger();
-        BigInteger by = y.toBigInteger();
-        int cmp = t.addAndCmp(x, y);
-        int bcmp = bt.compareTo(bx.add(by));
-        if (bcmp != cmp) {
-            throw new Exception("addAndCmp returns " + cmp + " expected " + bcmp);
-        }
-        check(bt, t, "addAndCmp corrupts this");
-        check(bx, x, "addAndCmp corrupts x");
-        check(by, y, "addAndCmp corrupts y");
-    }
-
-    private static void testAddAndCmp() throws Exception {
-        testAddAndCmp(MUTABLE_ZERO, MUTABLE_ZERO, MUTABLE_ZERO);
-        testAddAndCmp(mutable("00000001", 0), MUTABLE_ZERO, MUTABLE_ZERO);
-        testAddAndCmp(mutable("00000001", 0), mutable("00000001", 0), MUTABLE_ZERO);
-        testAddAndCmp(mutable("00000001", 0), MUTABLE_ZERO, mutable("00000001", 0));
-        testAddAndCmp(mutable("00000001", 0), mutable("00000002", 0), MUTABLE_ZERO);
-        testAddAndCmp(mutable("00000001", 0), MUTABLE_ZERO, mutable("00000002", 0));
-        testAddAndCmp(mutable("00000001", 2), mutable("FFFFFFFF", 0), mutable("FFFFFFFF", 0));
-        testAddAndCmp(mutable("00000001", 0), mutable("00000001", 1), mutable("00000001", 0));
-
-        testAddAndCmp(mutable("00000001", 2), mutable("0F0F0F0F80000000", 1), mutable("F0F0F0F080000000", 1));
-        testAddAndCmp(mutable("00000001", 2), mutable("0F0F0F0E80000000", 1), mutable("F0F0F0F080000000", 1));
-
-        testAddAndCmp(mutable("00000002", 1), mutable("0000000180000000", 1), mutable("0000000280000000", 1));
-        testAddAndCmp(mutable("00000003", 1), mutable("0000000180000000", 1), mutable("0000000280000000", 1));
-        testAddAndCmp(mutable("00000004", 1), mutable("0000000180000000", 1), mutable("0000000280000000", 1));
-        testAddAndCmp(mutable("00000005", 1), mutable("0000000180000000", 1), mutable("0000000280000000", 1));
-
-        testAddAndCmp(mutable("00000001", 2), mutable("8000000000000000", 0), mutable("8000000000000000", 0));
-        testAddAndCmp(mutable("00000001", 2), mutable("8000000000000000", 0), mutable("8000000000000001", 0));
-        testAddAndCmp(mutable("00000002", 2), mutable("8000000000000000", 0), mutable("8000000000000000", 0));
-        testAddAndCmp(mutable("00000003", 2), mutable("8000000000000000", 0), mutable("8000000000000000", 0));
-    }
-
-    private static void testMultBy10(FDBigInteger t, boolean isImmutable) throws Exception {
-        BigInteger bt = t.toBigInteger();
-        FDBigInteger r = t.multBy10();
-        if ((bt.signum() == 0 || !isImmutable) && r != t) {
-            throw new Exception("multBy10 of doesn't reuse its argument");
-        }
-        if (isImmutable) {
-            check(bt, t, "multBy10 corrupts its argument");
-        }
-        check(bt.multiply(BigInteger.TEN), r, "multBy10 returns wrong result");
-    }
-
-    private static void testMultBy10() throws Exception {
-        for (int p5 = 0; p5 <= MAX_P5; p5++) {
-            for (int p2 = 0; p2 <= MAX_P2; p2++) {
-                // This strange way of creating a value ensures that it is mutable.
-                FDBigInteger value = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5, p2);
-                testMultBy10(value, false);
-                value.makeImmutable();
-                testMultBy10(value, true);
-            }
-        }
-    }
-
-    private static void testMultByPow52(FDBigInteger t, int p5, int p2) throws Exception {
-        BigInteger bt = t.toBigInteger();
-        FDBigInteger r = t.multByPow52(p5, p2);
-        if (bt.signum() == 0 && r != t) {
-            throw new Exception("multByPow52 of doesn't reuse its argument");
-        }
-        check(bt.multiply(biPow52(p5, p2)), r, "multByPow52 returns wrong result");
-    }
-
-    private static void testMultByPow52() throws Exception {
-        for (int p5 = 0; p5 <= MAX_P5; p5++) {
-            for (int p2 = 0; p2 <= MAX_P2; p2++) {
-                // This strange way of creating a value ensures that it is mutable.
-                FDBigInteger value = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5, p2);
-                testMultByPow52(value, p5, p2);
-            }
-        }
-    }
-
-    private static void testLeftInplaceSub(FDBigInteger left, FDBigInteger right, boolean isImmutable) throws Exception {
-        BigInteger biLeft = left.toBigInteger();
-        BigInteger biRight = right.toBigInteger();
-        FDBigInteger diff = left.leftInplaceSub(right);
-        if (!isImmutable && diff != left) {
-            throw new Exception("leftInplaceSub of doesn't reuse its argument");
-        }
-        if (isImmutable) {
-            check(biLeft, left, "leftInplaceSub corrupts its left immutable argument");
-        }
-        check(biRight, right, "leftInplaceSub corrupts its right argument");
-        check(biLeft.subtract(biRight), diff, "leftInplaceSub returns wrong result");
-    }
-
-    private static void testLeftInplaceSub() throws Exception {
-        for (int p5 = 0; p5 <= MAX_P5; p5++) {
-            for (int p2 = 0; p2 <= MAX_P2; p2++) {
-//                for (int p5r = 0; p5r <= p5; p5r += 10) {
-//                    for (int p2r = 0; p2r <= p2; p2r += 10) {
-                for (int p5r = 0; p5r <= p5; p5r++) {
-                    for (int p2r = 0; p2r <= p2; p2r++) {
-                        // This strange way of creating a value ensures that it is mutable.
-                        FDBigInteger left = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5, p2);
-                        FDBigInteger right = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5r, p2r);
-                        testLeftInplaceSub(left, right, false);
-                        left = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5, p2);
-                        left.makeImmutable();
-                        testLeftInplaceSub(left, right, true);
-                    }
-                }
-            }
-        }
-    }
-
-    private static void testRightInplaceSub(FDBigInteger left, FDBigInteger right, boolean isImmutable) throws Exception {
-        BigInteger biLeft = left.toBigInteger();
-        BigInteger biRight = right.toBigInteger();
-        FDBigInteger diff = left.rightInplaceSub(right);
-        if (!isImmutable && diff != right) {
-            throw new Exception("rightInplaceSub of doesn't reuse its argument");
-        }
-        check(biLeft, left, "leftInplaceSub corrupts its left argument");
-        if (isImmutable) {
-            check(biRight, right, "leftInplaceSub corrupts its right immutable argument");
-        }
-        try {
-            check(biLeft.subtract(biRight), diff, "rightInplaceSub returns wrong result");
-        } catch (Exception e) {
-            System.out.println(biLeft+" - "+biRight+" = "+biLeft.subtract(biRight));
-            throw e;
-        }
-    }
-
-    private static void testRightInplaceSub() throws Exception {
-        for (int p5 = 0; p5 <= MAX_P5; p5++) {
-            for (int p2 = 0; p2 <= MAX_P2; p2++) {
-//                for (int p5r = 0; p5r <= p5; p5r += 10) {
-//                    for (int p2r = 0; p2r <= p2; p2r += 10) {
-                for (int p5r = 0; p5r <= p5; p5r++) {
-                    for (int p2r = 0; p2r <= p2; p2r++) {
-                        // This strange way of creating a value ensures that it is mutable.
-                        FDBigInteger left = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5, p2);
-                        FDBigInteger right = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5r, p2r);
-                        testRightInplaceSub(left, right, false);
-                        right = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5r, p2r);
-                        right.makeImmutable();
-                        testRightInplaceSub(left, right, true);
-                    }
-                }
-            }
-        }
-    }
-
-    public static void main(String[] args) throws Exception {
-        testValueOfPow52();
-        testValueOfMulPow52();
-        testLeftShift();
-        testQuoRemIteration();
-        testCmp();
-        testCmpPow52();
-        testAddAndCmp();
-        // Uncomment the following for more comprehensize but slow testing.
-        // testLeftInplaceSub();
-        // testMultBy10();
-        // testMultByPow52();
-        // testRightInplaceSub();
-    }
-}
--- a/jdk/test/sun/misc/FloatingDecimal/TestFloatingDecimal.java	Thu Dec 24 10:33:21 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,329 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-import java.util.Random;
-import sun.misc.FloatingDecimal;
-
-/*
-OldFloatingDecimalForTest
-
-public class OldFloatingDecimalForTest {
-  public boolean digitsRoundedUp();
-  public OldFloatingDecimalForTest(double);
-  public OldFloatingDecimalForTest(float);
-  public boolean decimalDigitsExact();
-  public java.lang.String toString();
-  public java.lang.String toJavaFormatString();
-  public void appendTo(java.lang.Appendable);
-  public static OldFloatingDecimalForTest readJavaFormatString(java.lang.String) throws java.lang.NumberFormatException;
-  public strictfp double doubleValue();
-  public strictfp float floatValue();
-}
-
-sun.misc.FloatingDecimal
-
-public class sun.misc.FloatingDecimal {
-  public sun.misc.FloatingDecimal();
-  public static java.lang.String toJavaFormatString(double);
-  public static java.lang.String toJavaFormatString(float);
-  public static void appendTo(double, java.lang.Appendable);
-  public static void appendTo(float, java.lang.Appendable);
-  public static double parseDouble(java.lang.String) throws java.lang.NumberFormatException;
-  public static float parseFloat(java.lang.String) throws java.lang.NumberFormatException;
-  public static sun.misc.FloatingDecimal$AbstractD2ABuffer getD2ABuffer(double);
-}
-*/
-
-/**
- * @test
- * @bug 7032154
- * @summary unit tests of sun.misc.FloatingDecimal
- * @modules java.base/sun.misc
- * @library ../../../java/lang/Math
- * @build DoubleConsts FloatConsts
- * @run main TestFloatingDecimal
- * @author Brian Burkhalter
- * @key randomness
- */
-public class TestFloatingDecimal {
-    private static enum ResultType {
-        RESULT_EXCEPTION,
-        RESULT_PRINT
-    }
-
-    private static final ResultType RESULT_TYPE = ResultType.RESULT_PRINT;
-    private static final int NUM_RANDOM_TESTS = 100000;
-
-    private static final Random RANDOM = new Random();
-
-    private static void result(String message) {
-        switch (RESULT_TYPE) {
-            case RESULT_EXCEPTION:
-                throw new RuntimeException(message);
-            case RESULT_PRINT:
-                System.err.println(message);
-                break;
-            default:
-                assert false;
-        }
-    }
-
-    private static int check(String test, Object expected, Object actual) {
-        int failures = 0;
-        if(!actual.equals(expected)) {
-            failures++;
-            result("Test "+test+" expected "+expected+" but obtained "+actual);
-        }
-        return failures;
-    }
-
-    private static int testAppendToDouble() {
-        System.out.println("  testAppendToDouble");
-        int failures = 0;
-
-        for(int i = 0; i < NUM_RANDOM_TESTS; i++) {
-            double[] d = new double[] {
-                RANDOM.nextLong(),
-                RANDOM.nextGaussian(),
-                RANDOM.nextDouble()*Double.MAX_VALUE
-            };
-            for(int j = 0; j < d.length; j++) {
-                OldFloatingDecimalForTest ofd = new OldFloatingDecimalForTest(d[j]);
-                StringBuilder sb = new StringBuilder();
-                ofd.appendTo(sb);
-                String oldString = sb.toString();
-                sb = new StringBuilder();
-                FloatingDecimal.appendTo(d[j], sb);
-                String newString = sb.toString();
-                failures += check("testAppendToDouble", oldString, newString);
-            }
-        }
-
-        return failures;
-    }
-
-    private static int testAppendToFloat() {
-        System.out.println("  testAppendToFloat");
-        int failures = 0;
-
-        for(int i = 0; i < NUM_RANDOM_TESTS; i++) {
-            float[] f = new float[] {
-                RANDOM.nextLong(),
-                (float)RANDOM.nextGaussian(),
-                RANDOM.nextFloat()*Float.MAX_VALUE
-            };
-            for(int j = 0; j < f.length; j++) {
-                OldFloatingDecimalForTest ofd = new OldFloatingDecimalForTest(f[j]);
-                StringBuilder sb = new StringBuilder();
-                ofd.appendTo(sb);
-                String oldString = sb.toString();
-                sb = new StringBuilder();
-                FloatingDecimal.appendTo(f[j], sb);
-                String newString = sb.toString();
-                failures += check("testAppendToFloat", oldString, newString);
-            }
-        }
-
-        return failures;
-    }
-
-    private static int testAppendTo() {
-        System.out.println("testAppendTo");
-        int failures = 0;
-
-        failures += testAppendToDouble();
-        failures += testAppendToFloat();
-
-        return failures;
-    }
-
-    private static int testParseDouble() {
-        System.out.println("  testParseDouble");
-        int failures = 0;
-
-        for(int i = 0; i < NUM_RANDOM_TESTS; i++) {
-            double[] d = new double[] {
-                RANDOM.nextLong(),
-                RANDOM.nextGaussian(),
-                RANDOM.nextDouble()*Double.MAX_VALUE
-            };
-            for(int j = 0; j < d.length; j++) {
-                OldFloatingDecimalForTest ofd = new OldFloatingDecimalForTest(d[j]);
-                String javaFormatString = ofd.toJavaFormatString();
-                ofd = OldFloatingDecimalForTest.readJavaFormatString(javaFormatString);
-                double oldDouble = ofd.doubleValue();
-                double newDouble = FloatingDecimal.parseDouble(javaFormatString);
-                failures += check("testParseDouble", oldDouble, newDouble);
-            }
-        }
-
-        return failures;
-    }
-
-    private static int testParseFloat() {
-        System.out.println("  testParseFloat");
-        int failures = 0;
-
-        for(int i = 0; i < NUM_RANDOM_TESTS; i++) {
-            float[] f = new float[] {
-                RANDOM.nextInt(),
-                (float)RANDOM.nextGaussian(),
-                RANDOM.nextFloat()*Float.MAX_VALUE
-            };
-            for(int j = 0; j < f.length; j++) {
-                OldFloatingDecimalForTest ofd = new OldFloatingDecimalForTest(f[j]);
-                String javaFormatString = ofd.toJavaFormatString();
-                ofd = OldFloatingDecimalForTest.readJavaFormatString(javaFormatString);
-                float oldFloat = ofd.floatValue();
-                float newFloat = FloatingDecimal.parseFloat(javaFormatString);
-                failures += check("testParseFloat", oldFloat, newFloat);
-            }
-        }
-
-        return failures;
-    }
-
-    private static int testParse() {
-        System.out.println("testParse");
-        int failures = 0;
-
-        failures += testParseDouble();
-        failures += testParseFloat();
-
-        return failures;
-    }
-
-    private static int testToJavaFormatStringDoubleFixed() {
-        System.out.println("    testToJavaFormatStringDoubleFixed");
-        int failures = 0;
-
-        double[] d = new double [] {
-            -5.9522650387500933e18, // dtoa() fast path
-            0.872989018674569,      // dtoa() fast iterative - long
-            1.1317400099603851e308  // dtoa() slow iterative
-        };
-
-        for(int i = 0; i < d.length; i++) {
-            OldFloatingDecimalForTest ofd = new OldFloatingDecimalForTest(d[i]);
-            failures += check("testToJavaFormatStringDoubleFixed", ofd.toJavaFormatString(), FloatingDecimal.toJavaFormatString(d[i]));
-        }
-
-        return failures;
-    }
-
-    private static int testToJavaFormatStringDoubleRandom() {
-        System.out.println("    testToJavaFormatStringDoubleRandom");
-        int failures = 0;
-
-        for(int i = 0; i < NUM_RANDOM_TESTS; i++) {
-            double[] d = new double[] {
-                RANDOM.nextLong(),
-                RANDOM.nextGaussian(),
-                RANDOM.nextDouble()*Double.MAX_VALUE
-            };
-            for(int j = 0; j < d.length; j++) {
-                OldFloatingDecimalForTest ofd = new OldFloatingDecimalForTest(d[j]);
-                failures += check("testToJavaFormatStringDoubleRandom", ofd.toJavaFormatString(), FloatingDecimal.toJavaFormatString(d[j]));
-            }
-        }
-
-        return failures;
-    }
-
-    private static int testToJavaFormatStringDouble() {
-        System.out.println("  testToJavaFormatStringDouble");
-        int failures = 0;
-        failures += testToJavaFormatStringDoubleFixed();
-        failures += testToJavaFormatStringDoubleRandom();
-        return failures;
-    }
-
-    private static int testToJavaFormatStringFloatFixed() {
-        System.out.println("    testToJavaFormatStringFloatFixed");
-        int failures = 0;
-
-        float[] f = new float[] {
-            -9.8784166e8f, // dtoa() fast path
-            0.70443946f,   // dtoa() fast iterative - int
-            1.8254228e37f  // dtoa() slow iterative
-        };
-
-        for(int i = 0; i < f.length; i++) {
-            OldFloatingDecimalForTest ofd = new OldFloatingDecimalForTest(f[i]);
-            failures += check("testToJavaFormatStringFloatFixed", ofd.toJavaFormatString(), FloatingDecimal.toJavaFormatString(f[i]));
-        }
-
-        return failures;
-    }
-
-    private static int testToJavaFormatStringFloatRandom() {
-        System.out.println("    testToJavaFormatStringFloatRandom");
-        int failures = 0;
-
-        for(int i = 0; i < NUM_RANDOM_TESTS; i++) {
-            float[] f = new float[] {
-                RANDOM.nextInt(),
-                (float)RANDOM.nextGaussian(),
-                RANDOM.nextFloat()*Float.MAX_VALUE
-            };
-            for(int j = 0; j < f.length; j++) {
-                OldFloatingDecimalForTest ofd = new OldFloatingDecimalForTest(f[j]);
-                failures += check("testToJavaFormatStringFloatRandom", ofd.toJavaFormatString(), FloatingDecimal.toJavaFormatString(f[j]));
-            }
-        }
-
-        return failures;
-    }
-
-    private static int testToJavaFormatStringFloat() {
-        System.out.println("  testToJavaFormatStringFloat");
-        int failures = 0;
-
-        failures += testToJavaFormatStringFloatFixed();
-        failures += testToJavaFormatStringFloatRandom();
-
-        return failures;
-    }
-
-    private static int testToJavaFormatString() {
-        System.out.println("testToJavaFormatString");
-        int failures = 0;
-
-        failures += testToJavaFormatStringDouble();
-        failures += testToJavaFormatStringFloat();
-
-        return failures;
-    }
-
-    public static void main(String[] args) {
-        int failures = 0;
-
-        failures += testAppendTo();
-        failures += testParse();
-        failures += testToJavaFormatString();
-
-        if (failures != 0) {
-            throw new RuntimeException("" + failures + " failures while testing FloatingDecimal");
-        }
-    }
-}
--- a/jdk/test/sun/security/tools/jarsigner/concise_jarsigner.sh	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/test/sun/security/tools/jarsigner/concise_jarsigner.sh	Wed Jul 05 21:10:50 2017 +0200
@@ -69,8 +69,8 @@
 # First part: output format
 # ==========================================================
 
-$KT -genkeypair -alias a1 -dname CN=a1 -validity 365
-$KT -genkeypair -alias a2 -dname CN=a2 -validity 365
+$KT -genkeypair -alias a1 -dname CN=a1 -validity 366
+$KT -genkeypair -alias a2 -dname CN=a2 -validity 366
 
 # a.jar includes 8 unsigned, 2 signed by a1 and a2, 2 signed by a3
 $JAR cvf a.jar A1.class A2.class
--- a/jdk/test/sun/tools/jstatd/TestJstatdServer.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/jdk/test/sun/tools/jstatd/TestJstatdServer.java	Wed Jul 05 21:10:50 2017 +0200
@@ -24,6 +24,7 @@
 /*
  * @test
  * @bug 4990825
+ * @key intermittent
  * @library /lib/testlibrary
  * @modules java.management
  * @build jdk.testlibrary.* JstatdTest JstatGCUtilParser
--- a/modules.xml	Thu Dec 24 10:33:21 2015 -0800
+++ b/modules.xml	Wed Jul 05 21:10:50 2017 +0200
@@ -223,6 +223,10 @@
       <to>jdk.dev</to>
     </export>
     <export>
+      <name>jdk.internal.math</name>
+      <to>java.desktop</to>
+    </export>
+    <export>
       <name>jdk.internal.misc</name>
       <to>java.corba</to>
       <to>java.desktop</to>
@@ -295,6 +299,7 @@
       <to>jdk.security.jgss</to>
       <to>jdk.snmp</to>
       <to>jdk.vm.ci</to>
+      <to>jdk.zipfs</to>
       <to>java.instrument</to>
     </export>
     <export>
--- a/nashorn/.hgtags	Thu Dec 24 10:33:21 2015 -0800
+++ b/nashorn/.hgtags	Wed Jul 05 21:10:50 2017 +0200
@@ -332,3 +332,4 @@
 d52c09d5d98a81ee6102a25f662ec4b9ae614163 jdk-9+96
 2beaef2b6a880c0bff8c9f57ffca33477d647f8b jdk-9+97
 68a36216f70c0de4c7e36f8978995934fc72ec03 jdk-9+98
+74ddd1339c57cf2c2a13e34e1760006c2e54d1fc jdk-9+99
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java	Wed Jul 05 21:10:50 2017 +0200
@@ -59,8 +59,8 @@
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_CREATEBUILTIN_SPECS_DESC;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY_DESC;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETDOCUMENTATION;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETDOCUMENTATION_DESC;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETDOCUMENTATIONKEY;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETDOCUMENTATIONKEY_DESC;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_TYPE;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.SETTER_PREFIX;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.TYPE_OBJECT;
@@ -274,7 +274,7 @@
         addField(cv, name, OBJECT_DESC);
     }
 
-    static void newFunction(final MethodGenerator mi, final String className, final MemberInfo memInfo, final List<MemberInfo> specs) {
+    static void newFunction(final MethodGenerator mi, final String objName, final String className, final MemberInfo memInfo, final List<MemberInfo> specs) {
         final boolean arityFound = (memInfo.getArity() != MemberInfo.DEFAULT_ARITY);
 
         mi.loadLiteral(memInfo.getName());
@@ -294,12 +294,9 @@
             mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETARITY, SCRIPTFUNCTION_SETARITY_DESC);
         }
 
-        String doc = memInfo.getDocumentation();
-        if (doc != null) {
-            mi.dup();
-            mi.loadLiteral(memInfo.getDocumentation());
-            mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETDOCUMENTATION, SCRIPTFUNCTION_SETDOCUMENTATION_DESC);
-        }
+        mi.dup();
+        mi.loadLiteral(memInfo.getDocumentationKey(objName));
+        mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETDOCUMENTATIONKEY, SCRIPTFUNCTION_SETDOCUMENTATIONKEY_DESC);
     }
 
     static void linkerAddGetterSetter(final MethodGenerator mi, final String className, final MemberInfo memInfo) {
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java	Wed Jul 05 21:10:50 2017 +0200
@@ -42,8 +42,8 @@
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_INIT_DESC4;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY_DESC;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETDOCUMENTATION;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETDOCUMENTATION_DESC;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETDOCUMENTATIONKEY;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETDOCUMENTATIONKEY_DESC;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETPROTOTYPE;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETPROTOTYPE_DESC;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_TYPE;
@@ -161,13 +161,11 @@
                 mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETARITY,
                         SCRIPTFUNCTION_SETARITY_DESC);
             }
-            final String doc = constructor.getDocumentation();
-            if (doc != null) {
-                mi.loadThis();
-                mi.loadLiteral(doc);
-                mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETDOCUMENTATION,
-                        SCRIPTFUNCTION_SETDOCUMENTATION_DESC);
-            }
+
+            mi.loadThis();
+            mi.loadLiteral(scriptClassInfo.getName());
+            mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETDOCUMENTATIONKEY,
+                        SCRIPTFUNCTION_SETDOCUMENTATIONKEY_DESC);
         }
         mi.returnVoid();
         mi.computeMaxs();
@@ -208,7 +206,7 @@
                 continue;
             }
             mi.loadThis();
-            newFunction(mi, scriptClassInfo.getJavaName(), memInfo, scriptClassInfo.findSpecializations(memInfo.getJavaName()));
+            newFunction(mi, scriptClassInfo.getName(), scriptClassInfo.getJavaName(), memInfo, scriptClassInfo.findSpecializations(memInfo.getJavaName()));
             mi.putField(className, memInfo.getJavaName(), OBJECT_DESC);
         }
     }
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java	Wed Jul 05 21:10:50 2017 +0200
@@ -85,8 +85,6 @@
     private MemberInfo.Kind kind;
     // script property name
     private String name;
-    // documentation for this member
-    private String documentation;
     // script property attributes
     private int attributes;
     // name of the java member
@@ -139,20 +137,6 @@
     }
 
     /**
-     * @return the documentation
-     */
-    public String getDocumentation() {
-        return documentation;
-    }
-
-    /**
-     * @param doc the documentation to set
-     */
-    public void setDocumentation(final String doc) {
-        this.documentation = doc;
-    }
-
-    /**
      * Tag something as specialized constructor or not
      * @param isSpecializedConstructor boolean, true if specialized constructor
      */
@@ -560,4 +544,25 @@
     void setArity(final int arity) {
         this.arity = arity;
     }
+
+    String getDocumentationKey(final String objName) {
+        if (kind == Kind.FUNCTION) {
+            StringBuilder buf = new StringBuilder(objName);
+            switch (where) {
+                case CONSTRUCTOR:
+                    break;
+                case PROTOTYPE:
+                    buf.append(".prototype");
+                    break;
+                case INSTANCE:
+                    buf.append(".this");
+                    break;
+            }
+            buf.append('.');
+            buf.append(name);
+            return buf.toString();
+        }
+
+        return null;
+    }
 }
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/PrototypeGenerator.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/PrototypeGenerator.java	Wed Jul 05 21:10:50 2017 +0200
@@ -142,7 +142,7 @@
                 continue;
             }
             mi.loadThis();
-            newFunction(mi, scriptClassInfo.getJavaName(), memInfo, scriptClassInfo.findSpecializations(memInfo.getJavaName()));
+            newFunction(mi, scriptClassInfo.getName(), scriptClassInfo.getJavaName(), memInfo, scriptClassInfo.findSpecializations(memInfo.getJavaName()));
             mi.putField(className, memInfo.getJavaName(), OBJECT_DESC);
         }
     }
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfoCollector.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfoCollector.java	Wed Jul 05 21:10:50 2017 +0200
@@ -206,7 +206,6 @@
                         // These could be "null" if values are not supplied,
                         // in which case we have to use the default values.
                         private String  name;
-                        private String  documentation;
                         private Integer attributes;
                         private Integer arity;
                         private Where   where;
@@ -223,13 +222,6 @@
                                     name = null;
                                 }
                                 break;
-                            case "documentation":
-                                this.documentation = (String)annotationValue;
-                                if (documentation.isEmpty()) {
-                                    documentation = null;
-                                }
-
-                                break;
                             case "attributes":
                                 this.attributes = (Integer)annotationValue;
                                 break;
@@ -279,7 +271,6 @@
                                 memInfo.setName(name == null ? methodName : name);
                             }
 
-                            memInfo.setDocumentation(documentation);
                             memInfo.setAttributes(attributes == null ? MemberInfo.DEFAULT_ATTRIBUTES : attributes);
 
                             memInfo.setArity((arity == null)? MemberInfo.DEFAULT_ARITY : arity);
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInstrumentor.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInstrumentor.java	Wed Jul 05 21:10:50 2017 +0200
@@ -170,7 +170,7 @@
 
                             if (memInfo.isInstanceFunction()) {
                                 super.visitVarInsn(ALOAD, 0);
-                                ClassGenerator.newFunction(delegateMV, scriptClassInfo.getJavaName(), memInfo, scriptClassInfo.findSpecializations(memInfo.getJavaName()));
+                                ClassGenerator.newFunction(delegateMV, scriptClassInfo.getName(), scriptClassInfo.getJavaName(), memInfo, scriptClassInfo.findSpecializations(memInfo.getJavaName()));
                                 super.visitFieldInsn(PUTFIELD, scriptClassInfo.getJavaName(),
                                     memInfo.getJavaName(), OBJECT_DESC);
                             }
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java	Wed Jul 05 21:10:50 2017 +0200
@@ -118,8 +118,8 @@
     static final String SCRIPTFUNCTION_TYPE = TYPE_SCRIPTFUNCTION.getInternalName();
     static final String SCRIPTFUNCTION_SETARITY = "setArity";
     static final String SCRIPTFUNCTION_SETARITY_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE);
-    static final String SCRIPTFUNCTION_SETDOCUMENTATION = "setDocumentation";
-    static final String SCRIPTFUNCTION_SETDOCUMENTATION_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_STRING);
+    static final String SCRIPTFUNCTION_SETDOCUMENTATIONKEY = "setDocumentationKey";
+    static final String SCRIPTFUNCTION_SETDOCUMENTATIONKEY_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_STRING);
     static final String SCRIPTFUNCTION_SETPROTOTYPE = "setPrototype";
     static final String SCRIPTFUNCTION_SETPROTOTYPE_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_OBJECT);
     static final String SCRIPTFUNCTION_CREATEBUILTIN = "createBuiltin";
--- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/AbstractJavaLinker.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/AbstractJavaLinker.java	Wed Jul 05 21:10:50 2017 +0200
@@ -790,7 +790,7 @@
      */
     @SuppressWarnings("unused")
     private Object getPropertyGetterHandle(final Object id) {
-        return propertyGetters.get(id);
+        return propertyGetters.get(String.valueOf(id));
     }
 
     // Type is MethodHandle(BeanLinker, MethodType, LinkerServices, Object, String, Object), of which the two "Object"
--- a/nashorn/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Main.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/nashorn/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Main.java	Wed Jul 05 21:10:50 2017 +0200
@@ -47,10 +47,10 @@
 import jdk.nashorn.internal.objects.NativeJava;
 import jdk.nashorn.internal.runtime.Context;
 import jdk.nashorn.internal.runtime.NativeJavaPackage;
-import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.Property;
 import jdk.nashorn.internal.runtime.ScriptEnvironment;
 import jdk.nashorn.internal.runtime.ScriptFunction;
+import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
 import jdk.nashorn.tools.Shell;
 
@@ -60,6 +60,8 @@
 public final class Main extends Shell {
     private Main() {}
 
+    private static final String DOC_PROPERTY_NAME = "__doc__";
+
     static final boolean DEBUG = Boolean.getBoolean("nashorn.jjs.debug");
     static final boolean HEADLESS = GraphicsEnvironment.isHeadless();
 
@@ -132,12 +134,17 @@
                                 final String pkgName = ((NativeJavaPackage)res).getName();
                                 final String url = pkgName.replace('.', '/') + "/package-summary.html";
                                 openBrowserForJavadoc(url);
-                            } else if (res instanceof ScriptFunction) {
-                                return ((ScriptFunction)res).getDocumentation();
+                            } else if (res instanceof ScriptObject) {
+                                final ScriptObject sobj = (ScriptObject)res;
+                                if (sobj.has(DOC_PROPERTY_NAME)) {
+                                    return toString(sobj.get(DOC_PROPERTY_NAME), global);
+                                } else if (sobj instanceof ScriptFunction) {
+                                    return ((ScriptFunction)sobj).getDocumentation();
+                                }
                             }
 
                             // FIXME: better than toString for other cases?
-                            return JSType.toString(res);
+                            return toString(res, global);
                         }
                      } catch (Exception ignored) {
                      }
@@ -253,7 +260,7 @@
         try {
             final Object res = context.eval(global, source, global, "<shell>");
             if (res != UNDEFINED) {
-                err.println(JSType.toString(res));
+                err.println(toString(res, global));
             }
         } catch (final Exception e) {
             err.println(e);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java	Wed Jul 05 21:10:50 2017 +0200
@@ -148,8 +148,7 @@
      * @param buf external buffer - should be a nio ByteBuffer
      * @return the 'obj' object
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
-        documentation = "sets ByteBuffer to hold indexed data (nashorn extension)")
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
     public static ScriptObject setIndexedPropertiesToExternalArrayData(final Object self, final Object obj, final Object buf) {
         Global.checkObject(obj);
         final ScriptObject sobj = (ScriptObject)obj;
@@ -169,8 +168,7 @@
      * @param  obj object to get prototype from
      * @return the prototype of an object
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
-        documentation = "returns the prototype of the specified object")
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
     public static Object getPrototypeOf(final Object self, final Object obj) {
         if (obj instanceof ScriptObject) {
             return ((ScriptObject)obj).getProto();
@@ -197,8 +195,7 @@
      * @param  proto prototype object to be used
      * @return object whose prototype is set
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
-        documentation = "sets the prototype of the given object (ES6)")
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
     public static Object setPrototypeOf(final Object self, final Object obj, final Object proto) {
         if (obj instanceof ScriptObject) {
             ((ScriptObject)obj).setPrototypeOf(proto);
@@ -219,8 +216,7 @@
      * @param prop  property descriptor
      * @return property descriptor
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
-        documentation = "returns a property descriptor for an own property (not inherited property)")
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
     public static Object getOwnPropertyDescriptor(final Object self, final Object obj, final Object prop) {
         if (obj instanceof ScriptObject) {
             final String       key  = JSType.toString(prop);
@@ -244,8 +240,7 @@
      * @param obj  object to query for property names
      * @return array of property names
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
-        documentation = "returns an array of all properties (enumerable or not) found directly on the given object")
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
     public static ScriptObject getOwnPropertyNames(final Object self, final Object obj) {
         if (obj instanceof ScriptObject) {
             return new NativeArray(((ScriptObject)obj).getOwnKeys(true));
@@ -263,8 +258,7 @@
      * @param obj  object to query for property names
      * @return array of property names
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
-        documentation = "returns an array of all symbol properties found directly on the given object (ES6)")
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
     public static ScriptObject getOwnPropertySymbols(final Object self, final Object obj) {
         if (obj instanceof ScriptObject) {
             return new NativeArray(((ScriptObject)obj).getOwnSymbols(true));
@@ -282,8 +276,7 @@
      * @param props properties to define
      * @return object created
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
-        documentation = "creates a new object with the specified prototype object and properties")
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
     public static ScriptObject create(final Object self, final Object proto, final Object props) {
         if (proto != null) {
             Global.checkObject(proto);
@@ -309,8 +302,7 @@
      * @param attr attributes for property descriptor
      * @return object
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
-        documentation = "adds an own property and/or update the attributes of an existing own property of an object")
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
     public static ScriptObject defineProperty(final Object self, final Object obj, final Object prop, final Object attr) {
         final ScriptObject sobj = Global.checkObject(obj);
         sobj.defineOwnProperty(JSType.toPropertyKey(prop), attr, true);
@@ -325,8 +317,7 @@
      * @param props properties
      * @return object
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
-        documentation = "defines new or modifies existing properties directly on the given object")
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
     public static ScriptObject defineProperties(final Object self, final Object obj, final Object props) {
         final ScriptObject sobj     = Global.checkObject(obj);
         final Object       propsObj = Global.toObject(props);
@@ -348,8 +339,7 @@
      * @param obj  object to seal
      * @return sealed object
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
-        documentation = "prevents new properties from being added to the given object and marks existing properties as non-configurable")
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
     public static Object seal(final Object self, final Object obj) {
         if (obj instanceof ScriptObject) {
             return ((ScriptObject)obj).seal();
@@ -368,8 +358,7 @@
      * @param obj object to freeze
      * @return frozen object
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
-        documentation = "prevents new properties from being added to the given object and prevents existing properties from being removed or re-configured")
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
     public static Object freeze(final Object self, final Object obj) {
         if (obj instanceof ScriptObject) {
             return ((ScriptObject)obj).freeze();
@@ -387,8 +376,7 @@
      * @param obj  object, for which to set the internal extensible property to false
      * @return object
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
-        documentation = "prevents new properties from ever being added to the given object")
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
     public static Object preventExtensions(final Object self, final Object obj) {
         if (obj instanceof ScriptObject) {
             return ((ScriptObject)obj).preventExtensions();
@@ -406,8 +394,7 @@
      * @param obj check whether an object is sealed
      * @return true if sealed, false otherwise
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
-        documentation = "tells if an object is sealed or not")
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
     public static boolean isSealed(final Object self, final Object obj) {
         if (obj instanceof ScriptObject) {
             return ((ScriptObject)obj).isSealed();
@@ -425,8 +412,7 @@
      * @param obj check whether an object
      * @return true if object is frozen, false otherwise
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
-        documentation = "tells if an object is fronzen or not")
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
     public static boolean isFrozen(final Object self, final Object obj) {
         if (obj instanceof ScriptObject) {
             return ((ScriptObject)obj).isFrozen();
@@ -444,8 +430,7 @@
      * @param obj check whether an object is extensible
      * @return true if object is extensible, false otherwise
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
-        documentation = "tells if an object is extensible or not")
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
     public static boolean isExtensible(final Object self, final Object obj) {
         if (obj instanceof ScriptObject) {
             return ((ScriptObject)obj).isExtensible();
@@ -463,8 +448,7 @@
      * @param obj  object from which to extract keys
      * @return array of keys in object
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
-        documentation = "returns an array of the given object's own enumerable properties")
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
     public static ScriptObject keys(final Object self, final Object obj) {
         if (obj instanceof ScriptObject) {
             final ScriptObject sobj = (ScriptObject)obj;
@@ -487,7 +471,7 @@
      * @param value  value of object to be instantiated
      * @return the new NativeObject
      */
-    @Constructor(documentation = "creates a new script object or converts given value as a script object")
+    @Constructor
     public static Object construct(final boolean newObj, final Object self, final Object value) {
         final JSType type = JSType.ofNoFunction(value);
 
@@ -521,8 +505,7 @@
      * @param self self reference
      * @return ToString of object
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE,
-        documentation = "returns a string representing of this object")
+    @Function(attributes = Attribute.NOT_ENUMERABLE)
     public static String toString(final Object self) {
         return ScriptRuntime.builtinObjectToString(self);
     }
@@ -575,8 +558,7 @@
      * @param v property to check for
      * @return true if property exists in object
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE,
-        documentation = "tells whether this object has the specified property or not")
+    @Function(attributes = Attribute.NOT_ENUMERABLE)
     public static boolean hasOwnProperty(final Object self, final Object v) {
         // Convert ScriptObjects to primitive with String.class hint
         // but no need to convert other primitives to string.
@@ -593,8 +575,7 @@
      * @param v v prototype object to check against
      * @return true if object is prototype of v
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE,
-        documentation = "tests for this object in another object's prototype chain")
+    @Function(attributes = Attribute.NOT_ENUMERABLE)
     public static boolean isPrototypeOf(final Object self, final Object v) {
         if (!(v instanceof ScriptObject)) {
             return false;
@@ -620,8 +601,7 @@
      * @param v property to check if enumerable
      * @return true if property is enumerable
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE,
-        documentation = "tells whether the given property is enumerable or not")
+    @Function(attributes = Attribute.NOT_ENUMERABLE)
     public static boolean propertyIsEnumerable(final Object self, final Object v) {
         final String str = JSType.toString(v);
         final Object obj = Global.toObject(self);
@@ -696,8 +676,7 @@
      * @param source the source object whose properties are bound to the target
      * @return the target object after property binding
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
-        documentation = "binds the source object's properties to the target object (nashorn extension)")
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
     public static Object bindProperties(final Object self, final Object target, final Object source) {
         // target object has to be a ScriptObject
         final ScriptObject targetObj = Global.checkObject(target);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/annotations/Constructor.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/annotations/Constructor.java	Wed Jul 05 21:10:50 2017 +0200
@@ -48,9 +48,4 @@
      *         arity.
      */
     public int arity() default -2;
-
-    /**
-     * @return the documentation string for this constructor.
-     */
-    public String documentation() default "";
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/annotations/Function.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/annotations/Function.java	Wed Jul 05 21:10:50 2017 +0200
@@ -60,9 +60,4 @@
      * @return where this function lives.
      */
     public Where where() default Where.PROTOTYPE;
-
-    /**
-     * @return return the documentation string for this function.
-     */
-    public String documentation() default "";
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java	Wed Jul 05 21:10:50 2017 +0200
@@ -36,6 +36,9 @@
  */
 final class FinalScriptFunctionData extends ScriptFunctionData {
 
+    // documentation key for this function, may be null
+    private String docKey;
+
     private static final long serialVersionUID = -930632846167768864L;
 
     /**
@@ -73,6 +76,23 @@
     }
 
     @Override
+    String getDocumentationKey() {
+        return docKey;
+    }
+
+    @Override
+    void setDocumentationKey(final String docKey) {
+        this.docKey = docKey;
+    }
+
+    @Override
+    String getDocumentation() {
+        String doc = docKey != null?
+            FunctionDocumentation.getDoc(docKey) : null;
+        return doc != null? doc : super.getDocumentation();
+    }
+
+    @Override
     protected boolean needsCallee() {
         final boolean needsCallee = code.getFirst().needsCallee();
         assert allNeedCallee(needsCallee);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/FunctionDocumentation.java	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.runtime;
+
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+/**
+ * Utility class to fetch documentation for built-in functions, constructors.
+ */
+final class FunctionDocumentation {
+    private FunctionDocumentation() {}
+
+    private static final String DOCS_RESOURCE = "jdk.nashorn.internal.runtime.resources.Functions";
+
+    private static final ResourceBundle FUNC_DOCS;
+    static {
+        FUNC_DOCS = ResourceBundle.getBundle(DOCS_RESOURCE, Locale.getDefault());
+    }
+
+    static String getDoc(final String docKey) {
+        try {
+            return FUNC_DOCS.getString(docKey);
+        } catch (final RuntimeException ignored) {
+            return null;
+        }
+    }
+}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java	Wed Jul 05 21:10:50 2017 +0200
@@ -655,12 +655,21 @@
     }
 
     /**
-     * Set the documentation for this function
+     * Get the documentation key for this function
      *
-     * @param doc documentation String for this function
+     * @return the documentation key
      */
-    public final void setDocumentation(final String doc) {
-        data.setDocumentation(doc);
+    public final String getDocumentationKey() {
+        return data.getDocumentationKey();
+    }
+
+    /**
+     * Set the documentation key for this function
+     *
+     * @param docKey documentation key String for this function
+     */
+    public final void setDocumentationKey(final String docKey) {
+        data.setDocumentationKey(docKey);
     }
 
     /**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunctionData.java	Thu Dec 24 10:33:21 2015 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunctionData.java	Wed Jul 05 21:10:50 2017 +0200
@@ -70,9 +70,6 @@
     // value, the function might still be capable of receiving variable number of arguments, see isVariableArity.
     private int arity;
 
-    // this may be null, if not available
-    private String documentation;
-
     /**
      * A pair of method handles used for generic invoker and constructor. Field is volatile as it can be initialized by
      * multiple threads concurrently, but we still tolerate a race condition in it as all values stored into it are
@@ -121,8 +118,12 @@
         return arity;
     }
 
-    final String getDocumentation() {
-        return documentation != null? documentation : toSource();
+    String getDocumentation() {
+        return toSource();
+    }
+
+    String getDocumentationKey() {
+        return null;
     }
 
     final boolean isVariableArity() {
@@ -149,10 +150,10 @@
      *
      * @param doc documentation for this function
      */
-    void setDocumentation(final String doc) {
-        this.documentation = doc;
+    void setDocumentationKey(final String docKey) {
     }
 
+
     CompiledFunction bind(final CompiledFunction originalInv, final ScriptFunction fn, final Object self, final Object[] args) {
         final MethodHandle boundInvoker = bindInvokeHandle(originalInv.createComposableInvoker(), fn, self, args);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Functions.properties	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,44 @@
+Object.setIndexedPropertiesToExternalArrayData=sets ByteBuffer to hold indexed data (nashorn extension)
+
+Object.getPrototypeOf=returns the prototype of the specified object
+
+Object.setPrototypeOf=sets the prototype of the given object (ES6)
+
+Object.getOwnPropertyDescriptor=returns a property descriptor for an own property (not inherited property)
+
+Object.getOwnPropertyNames=returns an array of all properties (enumerable or not) found directly on the given object
+
+Object.getOwnPropertySymbols=returns an array of all symbol properties found directly on the given object (ES6)
+
+Object.create=creates a new object with the specified prototype object and properties
+
+Object.defineProperty=adds an own property and/or update the attributes of an existing own property of an object
+
+Object.defineProperties=defines new or modifies existing properties directly on the given object
+
+Object.seal=prevents new properties from being added to the given object and marks existing properties as non-configurable
+
+Object.freeze=prevents new properties from being added to the given object and prevents existing properties from being removed or re-configured
+
+Object.preventExtensions=prevents new properties from ever being added to the given object
+
+Object.isSealed=tells if an object is sealed or not
+
+Object.isFrozen=tells if an object is fronzen or not
+
+Object.isExtensible=tells if an object is extensible or not
+
+Object.keys=returns an array of the given object's own enumerable properties
+
+Object=creates a new script object or converts given value as a script object
+
+Object.prototype.toString=returns a string representing of this object
+
+Object.prototype.hasOwnProperty=tells whether this object has the specified property or not
+
+Object.prototype.isPrototypeOf=tests for this object in another object's prototype chain
+
+Object.prototype.propertyIsEnumerable=tells whether the given property is enumerable or not
+
+Object.bindProperties=binds the source object's properties to the target object (nashorn extension)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8146147.js	Wed Jul 05 21:10:50 2017 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8146147: Java linker indexed property getter does not work for computed nashorn string
+ *
+ * @test
+ * @run
+ */
+
+var locale = java.util.Locale.ENGLISH;
+var prop = 'ISO3Language';
+var prop1 = 'ISO3';
+var prop2 = prop1 + 'Language';
+var prop3 = String(prop2);
+
+function checkLang(obj) {
+    if (obj != "eng") {
+        throw new Error("FAILED: expected 'eng', got " + obj);
+    }
+}
+
+checkLang(locale.ISO3Language);
+checkLang(locale['ISO3Language']);
+checkLang(locale[prop]);
+checkLang(locale[prop1 + 'Language']);
+checkLang(locale[prop2]);
+checkLang(locale[prop3]);
+checkLang(locale[String(prop1 + 'Language')]);