Merge
authorchegar
Mon, 10 Jun 2013 10:38:33 +0100
changeset 18253 4323a5fe8bc4
parent 18252 1a7454a9febb (current diff)
parent 18152 804f7c54faa6 (diff)
child 18254 e4083179f1c9
Merge
jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java
jdk/src/share/classes/java/lang/Class.java
jdk/src/share/classes/java/nio/file/Files.java
jdk/src/share/classes/java/security/AccessControlContext.java
jdk/src/share/classes/java/security/AccessController.java
jdk/src/share/classes/java/util/zip/ZipFile.java
jdk/src/share/classes/sun/misc/FDBigInt.java
jdk/src/share/classes/sun/tools/jconsole/VMPanel.java
jdk/src/share/classes/sun/tools/jconsole/resources/messages.properties
jdk/src/share/lib/security/java.security-linux
jdk/src/share/lib/security/java.security-macosx
jdk/src/share/lib/security/java.security-solaris
jdk/src/share/lib/security/java.security-windows
jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c
jdk/src/solaris/classes/sun/awt/X11/XWM.java
jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.c
jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.h
jdk/src/solaris/native/sun/java2d/x11/X11SurfaceData.c
jdk/src/solaris/native/sun/xawt/XlibWrapper.c
jdk/src/windows/native/java/net/DualStackPlainDatagramSocketImpl.c
jdk/src/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c
jdk/test/com/sun/jmx/remote/NotificationMarshalVersions/TestSerializationMismatch.sh
jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/SpliteratorLateBindingFailFastTest.java
jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/SpliteratorTraversingAndSplittingTest.java
--- a/jdk/make/java/management/Exportedfiles.gmk	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/make/java/management/Exportedfiles.gmk	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
+# 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
@@ -29,6 +29,7 @@
 
 FILES_export = \
 	sun/management/ClassLoadingImpl.java \
+	sun/management/DiagnosticCommandImpl.java \
 	sun/management/FileSystemImpl.java \
 	sun/management/Flag.java \
 	sun/management/GarbageCollectorImpl.java \
--- a/jdk/make/java/management/FILES_c.gmk	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/make/java/management/FILES_c.gmk	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
+# 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
@@ -25,6 +25,7 @@
 
 FILES_c = \
 	ClassLoadingImpl.c \
+	DiagnosticCommandImpl.c \
 	FileSystemImpl.c \
 	Flag.c \
 	GarbageCollectorImpl.c \
--- a/jdk/make/java/management/mapfile-vers	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/make/java/management/mapfile-vers	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -39,6 +39,10 @@
 	    Java_com_sun_management_UnixOperatingSystem_getTotalSwapSpaceSize;
 	    Java_com_sun_management_UnixOperatingSystem_initialize;
 	    Java_sun_management_ClassLoadingImpl_setVerboseClass;
+            Java_sun_management_DiagnosticCommandImpl_executeDiagnosticCommand;
+            Java_sun_management_DiagnosticCommandImpl_getDiagnosticCommands;
+            Java_sun_management_DiagnosticCommandImpl_getDiagnosticCommandInfo;
+	    Java_sun_management_DiagnosticCommandImpl_setNotificationEnabled;
 	    Java_sun_management_FileSystemImpl_isAccessUserOnly0;
 	    Java_sun_management_Flag_getAllFlagNames;
 	    Java_sun_management_Flag_getFlags;
--- a/jdk/make/sun/awt/FILES_c_unix.gmk	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/make/sun/awt/FILES_c_unix.gmk	Mon Jun 10 10:38:33 2013 +0100
@@ -171,3 +171,13 @@
         GLXSurfaceData.c \
         AccelGlyphCache.c \
 	CUPSfuncs.c
+
+ifeq ($(PLATFORM), macosx)
+FILES_NO_MOTIF_objc = \
+		AWTFont.m \
+		AWTStrike.m \
+		CCharToGlyphMapper.m \
+		CGGlyphImages.m \
+		CGGlyphOutlines.m \
+		CoreTextSupport.m
+endif # PLATFORM
--- a/jdk/make/sun/awt/FILES_export_unix.gmk	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/make/sun/awt/FILES_export_unix.gmk	Mon Jun 10 10:38:33 2013 +0100
@@ -187,3 +187,14 @@
 	java/awt/dnd/DnDConstants.java \
 	sun/awt/CausedFocusEvent.java
 
+ifeq ($(PLATFORM), macosx)
+ifeq ($(HEADLESS), true)
+FILES_export += \
+	sun/awt/SunHints.java \
+	sun/font/CCharToGlyphMapper.java \
+	sun/font/CFont.java \
+	sun/font/CFontManager.java \
+	sun/font/CStrike.java \
+	sun/font/CStrikeDisposer.java
+endif # HEADLESS
+endif # PLATFORM
--- a/jdk/make/sun/awt/mawt.gmk	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/make/sun/awt/mawt.gmk	Mon Jun 10 10:38:33 2013 +0100
@@ -43,6 +43,10 @@
 # compiled based on the motif version.
 FILES_c = $(FILES_NO_MOTIF_c)
 
+ifeq ($(PLATFORM), macosx)
+FILES_objc = $(FILES_NO_MOTIF_objc)
+endif # PLATFORM
+
 ifeq ($(PLATFORM), solaris)
   ifneq ($(ARCH), amd64)
     FILES_reorder += reorder-$(ARCH)
@@ -97,6 +101,10 @@
 vpath %.cpp $(SHARE_SRC)/native/$(PKGDIR)/image
 vpath %.c   $(PLATFORM_SRC)/native/$(PKGDIR)/robot_child
 
+ifeq ($(PLATFORM), macosx)
+vpath %.m   $(call NativeSrcDirList,,native/sun/font)
+endif # PLATFORM
+
 #
 # Libraries to link in.
 #
@@ -192,13 +200,21 @@
         $(EVENT_MODEL)
 
 ifeq ($(PLATFORM), macosx)
-CPPFLAGS += -I$(CUPS_HEADERS_PATH)
+CPPFLAGS += -I$(CUPS_HEADERS_PATH) \
+			$(call NativeSrcDirList,-I,native/sun/awt) \
+			$(call NativeSrcDirList,-I,native/sun/font)
 
 ifndef HEADLESS
 CPPFLAGS += -I$(MOTIF_DIR)/include \
             -I$(OPENWIN_HOME)/include 
 LDFLAGS  += -L$(MOTIF_LIB) -L$(OPENWIN_LIB)
-
+else
+LDFLAGS  += -framework Accelerate \
+			-framework ApplicationServices \
+			-framework Cocoa \
+			-F/System/Library/Frameworks/JavaVM.framework/Frameworks \
+			-framework JavaNativeFoundation \
+			-framework JavaRuntimeSupport
 endif # !HEADLESS
 endif # PLATFORM
 
--- a/jdk/make/tools/CharsetMapping/EUC_KR.map	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/make/tools/CharsetMapping/EUC_KR.map	Mon Jun 10 10:38:33 2013 +0100
@@ -5,6 +5,8 @@
 # (2)Added 2 new codepoints (KS X 1001:1998)
 #     0xA2E6	0x20AC	# EURO Sign
 #     0xA2E7	0x00AE	# Registered Sign
+# (3) KS X 1001:2002
+#     0xA2E8	0x327E  # CIRCLED KOREAN CHARACTER JUEUI (Postal Code Mark)
 #
 0x00	0x0000
 0x01	0x0001
@@ -295,6 +297,7 @@
 #
 0xA2E6	0x20AC	# EURO Sign
 0xA2E7	0x00AE	# Registered Sign
+0xA2E8	0x327E  # CIRCLED KOREAN CHARACTER JUEUI
 #
 0xA2E0	0x2116	# NUMERO SIGN
 0xA2E1	0x33C7	# SQUARE CO
--- a/jdk/make/tools/src/build/tools/generatebreakiteratordata/CharSet.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/make/tools/src/build/tools/generatebreakiteratordata/CharSet.java	Mon Jun 10 10:38:33 2013 +0100
@@ -39,6 +39,7 @@
 
 package build.tools.generatebreakiteratordata;
 
+import java.util.Arrays;
 import java.util.Hashtable;
 
 /**
@@ -701,7 +702,14 @@
      * the exact same characters as this one
      */
     public boolean equals(Object that) {
-        return (that instanceof CharSet) && chars.equals(((CharSet)that).chars);
+        return (that instanceof CharSet) && Arrays.equals(chars, ((CharSet)that).chars);
+    }
+
+    /**
+     * Returns the hash code for this set of characters
+     */
+    public int hashCode() {
+       return Arrays.hashCode(chars);
     }
 
     /**
--- a/jdk/makefiles/CompileJavaClasses.gmk	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/makefiles/CompileJavaClasses.gmk	Mon Jun 10 10:38:33 2013 +0100
@@ -342,7 +342,7 @@
 		DISABLE_SJAVAC:=true,\
 		SRC:=$(JDK_TOPDIR)/src/macosx/native/jobjc/src/core/java \
 		     $(JDK_TOPDIR)/src/macosx/native/jobjc/src/runtime-additions/java \
-		     $(JDK_OUTPUTDIR)/gensrc, \
+		     $(JDK_OUTPUTDIR)/gensrc_jobjc/src, \
 		INCLUDES := com/apple/jobjc,\
                 EXCLUDES := tests/java/com/apple/jobjc,\
 		BIN:=$(JDK_OUTPUTDIR)/jobjc_classes,\
@@ -355,7 +355,7 @@
 		SETUP:=GENERATE_JDKBYTECODE,\
 		SRC:=$(JDK_TOPDIR)/src/macosx/native/jobjc/src/core/java \
 		     $(JDK_TOPDIR)/src/macosx/native/jobjc/src/runtime-additions/java \
-		     $(JDK_OUTPUTDIR)/gensrc, \
+		     $(JDK_OUTPUTDIR)/gensrc_jobjc/src, \
 		INCLUDES := com/apple/jobjc,\
                 EXCLUDES := tests/java/com/apple/jobjc,\
 		BIN:=$(JDK_OUTPUTDIR)/jobjc_classes_headers,\
--- a/jdk/makefiles/CompileNativeLibraries.gmk	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/makefiles/CompileNativeLibraries.gmk	Mon Jun 10 10:38:33 2013 +0100
@@ -2314,6 +2314,10 @@
 			$(JDK_TOPDIR)/src/solaris/native/sun/java2d/opengl \
 			$(JDK_TOPDIR)/src/solaris/native/sun/java2d/x11
 
+ifeq ($(OPENJDK_TARGET_OS),macosx)
+	LIBAWT_HEADLESS_DIRS+=$(JDK_TOPDIR)/src/macosx/native/sun/font
+endif
+
 LIBAWT_HEADLESS_CFLAGS:=-DHEADLESS=true \
                           -DX11_PATH=\"$(X11_PATH)\" -DPACKAGE_PATH=\"$(PACKAGE_PATH)\" \
 			  $(CUPS_CFLAGS) \
@@ -2328,6 +2332,12 @@
 			  -I$(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/sun/jdga \
                           $(foreach dir,$(LIBAWT_HEADLESS_DIRS),-I$(dir))
 
+ifeq ($(OPENJDK_TARGET_OS),macosx)
+	LIBAWT_HEADLESS_CFLAGS+=\
+		-F/System/Library/Frameworks/JavaVM.framework/Frameworks \
+		-F/System/Library/Frameworks/ApplicationServices.framework/Frameworks
+endif
+
 LIBAWT_HEADLESS_FILES:=\
 	awt_Font.c \
 	HeadlessToolkit.c \
@@ -2356,6 +2366,16 @@
         AccelGlyphCache.c \
 	CUPSfuncs.c
 
+ifeq ($(OPENJDK_TARGET_OS),macosx)
+	LIBAWT_HEADLESS_FILES+=\
+		AWTFont.m \
+		AWTStrike.m \
+		CCharToGlyphMapper.m \
+		CGGlyphImages.m \
+		CGGlyphOutlines.m \
+		CoreTextSupport.m
+endif
+
 LIBAWT_HEADLESS_REORDER:=
 ifeq ($(OPENJDK_TARGET_OS), solaris)
 	ifneq ($(OPENJDK_TARGET_CPU), x86_64)
@@ -2382,7 +2402,13 @@
 		REORDER:=$(LIBAWT_HEADLESS_REORDER), \
 		LDFLAGS_SUFFIX_linux:=-ljvm -lawt -lm $(LIBDL) -ljava,\
 		LDFLAGS_SUFFIX_solaris:=$(LIBDL) -ljvm -lawt -lm -ljava $(LIBCXX) -lc,\
-		LDFLAGS_SUFFIX_macosx:=-ljvm $(LIBCXX) -lawt $(LIBDL) -ljava,\
+		LDFLAGS_SUFFIX_macosx:=-ljvm $(LIBCXX) -lawt $(LIBDL) -ljava \
+				 -framework Accelerate \
+				 -framework ApplicationServices \
+				 -framework Cocoa \
+				 -F/System/Library/Frameworks/JavaVM.framework/Frameworks \
+				 -framework JavaNativeFoundation \
+				 -framework JavaRuntimeSupport,\
 		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libawt_headless,\
 		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
--- a/jdk/makefiles/GensrcBuffer.gmk	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/makefiles/GensrcBuffer.gmk	Mon Jun 10 10:38:33 2013 +0100
@@ -69,6 +69,9 @@
 		$1_fulltype := character
 		$1_Fulltype := Character
 		$1_category := integralType
+                $1_streams  := streamableType
+                $1_streamtype := int
+                $1_Streamtype := Int
 		$1_LBPV     := 1
 	endif
 
@@ -97,7 +100,7 @@
 		$1_Type     := Long
 		$1_fulltype := long
 		$1_Fulltype := Long
-		$1_category := integralType
+		$1_category := integralType	
 		$1_LBPV     := 3
 	endif
 
@@ -231,10 +234,13 @@
 	$(TOOL_SPP) < $$($1_SRC) > $$($1_OUT).tmp \
 		-K$$($1_type) \
 		-K$$($1_category) \
+		-K$$($1_streams) \
 		-Dtype=$$($1_type) \
 		-DType=$$($1_Type) \
 		-Dfulltype=$$($1_fulltype) \
 		-DFulltype=$$($1_Fulltype) \
+                -Dstreamtype=$$($1_streamtype) \
+                -DStreamtype=$$($1_Streamtype) \
 		-Dx=$$($1_x) \
 		-Dmemtype=$$($1_memtype) \
 		-DMemtype=$$($1_Memtype) \
--- a/jdk/makefiles/mapfiles/libmanagement/mapfile-vers	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/makefiles/mapfiles/libmanagement/mapfile-vers	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -39,6 +39,10 @@
 	    Java_com_sun_management_UnixOperatingSystem_getTotalSwapSpaceSize;
 	    Java_com_sun_management_UnixOperatingSystem_initialize;
 	    Java_sun_management_ClassLoadingImpl_setVerboseClass;
+            Java_sun_management_DiagnosticCommandImpl_executeDiagnosticCommand;
+            Java_sun_management_DiagnosticCommandImpl_getDiagnosticCommands;
+            Java_sun_management_DiagnosticCommandImpl_getDiagnosticCommandInfo;
+            Java_sun_management_DiagnosticCommandImpl_setNotificationEnabled;
 	    Java_sun_management_FileSystemImpl_isAccessUserOnly0;
 	    Java_sun_management_Flag_getAllFlagNames;
 	    Java_sun_management_Flag_getFlags;
--- a/jdk/src/macosx/bin/java_md_macosx.c	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/macosx/bin/java_md_macosx.c	Mon Jun 10 10:38:33 2013 +0100
@@ -44,7 +44,6 @@
 #include <Cocoa/Cocoa.h>
 #include <objc/objc-runtime.h>
 #include <objc/objc-auto.h>
-#include <dispatch/dispatch.h>
 
 #include <errno.h>
 #include <spawn.h>
@@ -1001,6 +1000,32 @@
     setenv(envVar, "1", 1);
 }
 
+/* This class is made for performSelectorOnMainThread when java main
+ * should be launched on main thread.
+ * We cannot use dispatch_sync here, because it blocks the main dispatch queue
+ * which is used inside Cocoa
+ */
+@interface JavaLaunchHelper : NSObject {
+    int _returnValue;
+}
+- (void) launchJava:(NSValue*)argsValue;
+- (int) getReturnValue;
+@end
+
+@implementation JavaLaunchHelper
+
+- (void) launchJava:(NSValue*)argsValue
+{
+    _returnValue = JavaMain([argsValue pointerValue]);
+}
+
+- (int) getReturnValue
+{
+    return _returnValue;
+}
+
+@end
+
 // MacOSX we may continue in the same thread
 int
 JVMInit(InvocationFunctions* ifn, jlong threadStackSize,
@@ -1010,16 +1035,22 @@
         JLI_TraceLauncher("In same thread\n");
         // need to block this thread against the main thread
         // so signals get caught correctly
-        __block int rslt;
-        dispatch_sync(dispatch_get_main_queue(), ^(void) {
-            JavaMainArgs args;
-            args.argc = argc;
-            args.argv = argv;
-            args.mode = mode;
-            args.what = what;
-            args.ifn  = *ifn;
-            rslt = JavaMain((void*)&args);
-        });
+        JavaMainArgs args;
+        args.argc = argc;
+        args.argv = argv;
+        args.mode = mode;
+        args.what = what;
+        args.ifn  = *ifn;
+        int rslt;
+        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+        {
+            JavaLaunchHelper* launcher = [[[JavaLaunchHelper alloc] init] autorelease];
+            [launcher performSelectorOnMainThread:@selector(launchJava:)
+                                       withObject:[NSValue valueWithPointer:(void*)&args]
+                                    waitUntilDone:YES];
+            rslt = [launcher getReturnValue];
+        }
+        [pool drain];
         return rslt;
     } else {
         return ContinueInNewThread(ifn, threadStackSize, argc, argv, mode, what, ret);
--- a/jdk/src/macosx/classes/sun/lwawt/macosx/CDropTargetContextPeer.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CDropTargetContextPeer.java	Mon Jun 10 10:38:33 2013 +0100
@@ -38,7 +38,7 @@
     private long    fNativeDropTransfer = 0;
     private long    fNativeDataAvailable = 0;
     private Object  fNativeData    = null;
-    private boolean insideTarget = false;
+    private boolean insideTarget = true;
 
     Object awtLockAccess = new Object();
 
--- a/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java	Mon Jun 10 10:38:33 2013 +0100
@@ -115,6 +115,8 @@
 
     static final int RESIZABLE = 1 << 9; // both a style bit and prop bit
     static final int NONACTIVATING = 1 << 24;
+    static final int IS_DIALOG = 1 << 25;
+    static final int IS_MODAL = 1 << 26;
 
     static final int _STYLE_PROP_BITMASK = DECORATED | TEXTURED | UNIFIED | UTILITY | HUD | SHEET | CLOSEABLE | MINIMIZABLE | RESIZABLE;
 
@@ -376,6 +378,13 @@
             }
         }
 
+        if (isDialog) {
+            styleBits = SET(styleBits, IS_DIALOG, true);
+            if (((Dialog) target).isModal()) {
+                styleBits = SET(styleBits, IS_MODAL, true);
+            }
+        }
+
         peer.setTextured(IS(TEXTURED, styleBits));
 
         return styleBits;
--- a/jdk/src/macosx/classes/sun/lwawt/macosx/CPrinterJob.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CPrinterJob.java	Mon Jun 10 10:38:33 2013 +0100
@@ -36,6 +36,7 @@
 import javax.print.*;
 import javax.print.attribute.PrintRequestAttributeSet;
 import javax.print.attribute.HashPrintRequestAttributeSet;
+import javax.print.attribute.standard.PageRanges;
 
 import sun.java2d.*;
 import sun.print.*;
@@ -173,6 +174,19 @@
         if (nsPrintInfo != null) {
             fNSPrintInfo = nsPrintInfo.getValue();
         }
+
+        PageRanges pageRangesAttr =  (PageRanges)attributes.get(PageRanges.class);
+        if (isSupportedValue(pageRangesAttr, attributes)) {
+            SunPageSelection rangeSelect = (SunPageSelection)attributes.get(SunPageSelection.class);
+            // If rangeSelect is not null, we are using AWT's print dialog that has
+            // All, Selection, and Range radio buttons
+            if (rangeSelect == null || rangeSelect == SunPageSelection.RANGE) {
+                int[][] range = pageRangesAttr.getMembers();
+                // setPageRange will set firstPage and lastPage as called in getFirstPage
+                // and getLastPage
+                setPageRange(range[0][0] - 1, range[0][1] - 1);
+            }
+        }
     }
 
     volatile boolean onEventThread;
@@ -225,7 +239,6 @@
          * the end of the document. Note that firstPage
          * and lastPage are 0 based page indices.
          */
-        int numPages = mDocument.getNumberOfPages();
 
         int firstPage = getFirstPage();
         int lastPage = getLastPage();
@@ -242,42 +255,53 @@
                 userCancelled = false;
             }
 
-            if (EventQueue.isDispatchThread()) {
-                // This is an AWT EventQueue, and this print rendering loop needs to block it.
-
-                onEventThread = true;
+            //Add support for PageRange
+            PageRanges pr = (attributes == null) ?  null
+                                                 : (PageRanges)attributes.get(PageRanges.class);
+            int[][] prMembers = (pr == null) ? new int[0][0] : pr.getMembers();
+            int loopi = 0;
+            do {
+                if (EventQueue.isDispatchThread()) {
+                    // This is an AWT EventQueue, and this print rendering loop needs to block it.
 
-                printingLoop = AccessController.doPrivileged(new PrivilegedAction<SecondaryLoop>() {
-                    @Override
-                    public SecondaryLoop run() {
-                        return Toolkit.getDefaultToolkit()
-                                .getSystemEventQueue()
-                                .createSecondaryLoop();
-                    }
-                });
+                    onEventThread = true;
+
+                    printingLoop = AccessController.doPrivileged(new PrivilegedAction<SecondaryLoop>() {
+                        @Override
+                        public SecondaryLoop run() {
+                            return Toolkit.getDefaultToolkit()
+                                    .getSystemEventQueue()
+                                    .createSecondaryLoop();
+                        }
+                    });
 
-                try {
-                    // Fire off the print rendering loop on the AppKit thread, and don't have
-                    //  it wait and block this thread.
-                    if (printLoop(false, firstPage, lastPage)) {
-                        // Start a secondary loop on EDT until printing operation is finished or cancelled
-                        printingLoop.enter();
+                    try {
+                        // Fire off the print rendering loop on the AppKit thread, and don't have
+                        //  it wait and block this thread.
+                        if (printLoop(false, firstPage, lastPage)) {
+                            // Start a secondary loop on EDT until printing operation is finished or cancelled
+                            printingLoop.enter();
+                        }
+                    } catch (Exception e) {
+                        e.printStackTrace();
                     }
-                } catch (Exception e) {
-                    e.printStackTrace();
+              } else {
+                    // Fire off the print rendering loop on the AppKit, and block this thread
+                    //  until it is done.
+                    // But don't actually block... we need to come back here!
+                    onEventThread = false;
+
+                    try {
+                        printLoop(true, firstPage, lastPage);
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                    }
                 }
-            } else {
-                // Fire off the print rendering loop on the AppKit, and block this thread
-                //  until it is done.
-                // But don't actually block... we need to come back here!
-                onEventThread = false;
-
-                try {
-                    printLoop(true, firstPage, lastPage);
-                } catch (Exception e) {
-                    e.printStackTrace();
+                if (++loopi < prMembers.length) {
+                     firstPage = prMembers[loopi][0]-1;
+                     lastPage = prMembers[loopi][1] -1;
                 }
-            }
+            }  while (loopi < prMembers.length);
         } finally {
             synchronized (this) {
                 // NOTE: Native code shouldn't allow exceptions out while
--- a/jdk/src/macosx/native/sun/awt/AWTWindow.m	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/macosx/native/sun/awt/AWTWindow.m	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -536,8 +536,12 @@
 - (void) windowDidBecomeKey: (NSNotification *) notification {
 AWT_ASSERT_APPKIT_THREAD;
     [AWTToolkit eventCountPlusPlus];
-    [CMenuBar activate:self.javaMenuBar modallyDisabled:NO];
     AWTWindow *opposite = [AWTWindow lastKeyWindow];
+    if (!IS(self.styleBits, IS_DIALOG)) {
+        [CMenuBar activate:self.javaMenuBar modallyDisabled:NO];
+    } else if (IS(self.styleBits, IS_MODAL)) {
+        [CMenuBar activate:opposite->javaMenuBar modallyDisabled:YES];        
+    }
     [AWTWindow setLastKeyWindow:nil];
 
     [self _deliverWindowFocusEvent:YES oppositeWindow: opposite];
--- a/jdk/src/macosx/native/sun/font/AWTFont.m	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/macosx/native/sun/font/AWTFont.m	Mon Jun 10 10:38:33 2013 +0100
@@ -395,6 +395,7 @@
 
 #pragma mark --- Miscellaneous JNI ---
 
+#ifndef HEADLESS
 /*
  * Class:     sun_awt_PlatformFont
  * Method:    initIDs
@@ -416,3 +417,4 @@
     (JNIEnv *env, jclass cls)
 {
 }
+#endif
--- a/jdk/src/share/classes/com/sun/beans/finder/AbstractFinder.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/com/sun/beans/finder/AbstractFinder.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,6 +24,9 @@
  */
 package com.sun.beans.finder;
 
+import java.lang.reflect.Executable;
+import java.lang.reflect.Modifier;
+
 import java.util.HashMap;
 import java.util.Map;
 
@@ -37,7 +40,7 @@
  *
  * @author Sergey A. Malenkov
  */
-abstract class AbstractFinder<T> {
+abstract class AbstractFinder<T extends Executable> {
     private final Class<?>[] args;
 
     /**
@@ -53,27 +56,6 @@
     }
 
     /**
-     * Returns an array of {@code Class} objects
-     * that represent the formal parameter types of the method.
-     * Returns an empty array if the method takes no parameters.
-     *
-     * @param method  the object that represents method
-     * @return the parameter types of the method
-     */
-    protected abstract Class<?>[] getParameters(T method);
-
-    /**
-     * Returns {@code true} if and only if the method
-     * was declared to take a variable number of arguments.
-     *
-     * @param method  the object that represents method
-     * @return {@code true} if the method was declared
-     *         to take a variable number of arguments;
-     *         {@code false} otherwise
-     */
-    protected abstract boolean isVarArgs(T method);
-
-    /**
      * Checks validness of the method.
      * At least the valid method should be public.
      *
@@ -81,7 +63,9 @@
      * @return {@code true} if the method is valid,
      *         {@code false} otherwise
      */
-    protected abstract boolean isValid(T method);
+    protected boolean isValid(T method) {
+        return Modifier.isPublic(method.getModifiers());
+    }
 
     /**
      * Performs a search in the {@code methods} array.
@@ -109,7 +93,7 @@
 
         for (T newMethod : methods) {
             if (isValid(newMethod)) {
-                Class<?>[] newParams = getParameters(newMethod);
+                Class<?>[] newParams = newMethod.getParameterTypes();
                 if (newParams.length == this.args.length) {
                     PrimitiveWrapperMap.replacePrimitivesWithWrappers(newParams);
                     if (isAssignable(newParams, this.args)) {
@@ -120,6 +104,11 @@
                             boolean useNew = isAssignable(oldParams, newParams);
                             boolean useOld = isAssignable(newParams, oldParams);
 
+                            if (useOld && useNew) {
+                                // only if parameters are equal
+                                useNew = !newMethod.isSynthetic();
+                                useOld = !oldMethod.isSynthetic();
+                            }
                             if (useOld == useNew) {
                                 ambiguous = true;
                             } else if (useNew) {
@@ -130,7 +119,7 @@
                         }
                     }
                 }
-                if (isVarArgs(newMethod)) {
+                if (newMethod.isVarArgs()) {
                     int length = newParams.length - 1;
                     if (length <= this.args.length) {
                         Class<?>[] array = new Class<?>[this.args.length];
@@ -160,6 +149,11 @@
                         boolean useNew = isAssignable(oldParams, newParams);
                         boolean useOld = isAssignable(newParams, oldParams);
 
+                        if (useOld && useNew) {
+                            // only if parameters are equal
+                            useNew = !newMethod.isSynthetic();
+                            useOld = !oldMethod.isSynthetic();
+                        }
                         if (useOld == useNew) {
                             if (oldParams == map.get(oldMethod)) {
                                 ambiguous = true;
--- a/jdk/src/share/classes/com/sun/beans/finder/ConstructorFinder.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/com/sun/beans/finder/ConstructorFinder.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 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
@@ -86,44 +86,4 @@
     private ConstructorFinder(Class<?>[] args) {
         super(args);
     }
-
-    /**
-     * Returns an array of {@code Class} objects
-     * that represent the formal parameter types of the constructor.
-     * Returns an empty array if the constructor takes no parameters.
-     *
-     * @param constructor  the object that represents constructor
-     * @return the parameter types of the constructor
-     */
-    @Override
-    protected Class<?>[] getParameters(Constructor<?> constructor) {
-        return constructor.getParameterTypes();
-    }
-
-    /**
-     * Returns {@code true} if and only if the constructor
-     * was declared to take a variable number of arguments.
-     *
-     * @param constructor  the object that represents constructor
-     * @return {@code true} if the constructor was declared
-     *         to take a variable number of arguments;
-     *         {@code false} otherwise
-     */
-    @Override
-    protected boolean isVarArgs(Constructor<?> constructor) {
-        return constructor.isVarArgs();
-    }
-
-    /**
-     * Checks validness of the constructor.
-     * The valid constructor should be public.
-     *
-     * @param constructor  the object that represents constructor
-     * @return {@code true} if the constructor is valid,
-     *         {@code false} otherwise
-     */
-    @Override
-    protected boolean isValid(Constructor<?> constructor) {
-        return Modifier.isPublic(constructor.getModifiers());
-    }
 }
--- a/jdk/src/share/classes/com/sun/beans/finder/MethodFinder.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/com/sun/beans/finder/MethodFinder.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 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
@@ -196,33 +196,6 @@
     }
 
     /**
-     * Returns an array of {@code Class} objects
-     * that represent the formal parameter types of the method.
-     * Returns an empty array if the method takes no parameters.
-     *
-     * @param method  the object that represents method
-     * @return the parameter types of the method
-     */
-    @Override
-    protected Class<?>[] getParameters(Method method) {
-        return method.getParameterTypes();
-    }
-
-    /**
-     * Returns {@code true} if and only if the method
-     * was declared to take a variable number of arguments.
-     *
-     * @param method  the object that represents method
-     * @return {@code true} if the method was declared
-     *         to take a variable number of arguments;
-     *         {@code false} otherwise
-     */
-    @Override
-    protected boolean isVarArgs(Method method) {
-        return method.isVarArgs();
-    }
-
-    /**
      * Checks validness of the method.
      * The valid method should be public and
      * should have the specified name.
@@ -233,6 +206,6 @@
      */
     @Override
     protected boolean isValid(Method method) {
-        return !method.isBridge() && Modifier.isPublic(method.getModifiers()) && method.getName().equals(this.name);
+        return super.isValid(method) && method.getName().equals(this.name);
     }
 }
--- a/jdk/src/share/classes/com/sun/crypto/provider/DHKeyAgreement.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/com/sun/crypto/provider/DHKeyAgreement.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -403,8 +403,9 @@
             }
             return skey;
         } else if (algorithm.equals("TlsPremasterSecret")) {
-            // return entire secret
-            return new SecretKeySpec(secret, "TlsPremasterSecret");
+            // remove leading zero bytes per RFC 5246 Section 8.1.2
+            return new SecretKeySpec(
+                        KeyUtil.trimZeroes(secret), "TlsPremasterSecret");
         } else {
             throw new NoSuchAlgorithmException("Unsupported secret key "
                                                + "algorithm: "+ algorithm);
--- a/jdk/src/share/classes/com/sun/crypto/provider/HmacPKCS12PBESHA1.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/com/sun/crypto/provider/HmacPKCS12PBESHA1.java	Mon Jun 10 10:38:33 2013 +0100
@@ -86,12 +86,13 @@
             throw new InvalidKeyException("SecretKey of PBE type required");
         }
         if (params == null) {
-            // generate default for salt and iteration count if necessary
-            if (salt == null) {
-                salt = new byte[20];
-                SunJCE.getRandom().nextBytes(salt);
+            // should not auto-generate default values since current
+            // javax.crypto.Mac api does not have any method for caller to
+            // retrieve the generated defaults.
+            if ((salt == null) || (iCount == 0)) {
+                throw new InvalidAlgorithmParameterException
+                    ("PBEParameterSpec required for salt and iteration count");
             }
-            if (iCount == 0) iCount = 100;
         } else if (!(params instanceof PBEParameterSpec)) {
             throw new InvalidAlgorithmParameterException
                 ("PBEParameterSpec type required");
--- a/jdk/src/share/classes/com/sun/crypto/provider/PBMAC1Core.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/com/sun/crypto/provider/PBMAC1Core.java	Mon Jun 10 10:38:33 2013 +0100
@@ -42,12 +42,10 @@
  */
 abstract class PBMAC1Core extends HmacCore {
 
-    private static final int DEFAULT_SALT_LENGTH = 20;
-    private static final int DEFAULT_COUNT = 4096;
-
+    // NOTE: this class inherits the Cloneable interface from HmacCore
+    // Need to override clone() if mutable fields are added.
     private final String kdfAlgo;
     private final String hashAlgo;
-    private final PBKDF2Core kdf;
     private final int blockLength; // in octets
 
     /**
@@ -56,13 +54,15 @@
      */
     PBMAC1Core(String kdfAlgo, String hashAlgo, int blockLength)
         throws NoSuchAlgorithmException {
-
         super(hashAlgo, blockLength);
         this.kdfAlgo = kdfAlgo;
         this.hashAlgo = hashAlgo;
         this.blockLength = blockLength;
+    }
 
-        switch(kdfAlgo) {
+    private static PBKDF2Core getKDFImpl(String algo) {
+        PBKDF2Core kdf = null;
+        switch(algo) {
         case "HmacSHA1":
                 kdf = new PBKDF2Core.HmacSHA1();
                 break;
@@ -79,9 +79,10 @@
                 kdf = new PBKDF2Core.HmacSHA512();
                 break;
         default:
-                throw new NoSuchAlgorithmException(
-                    "No MAC implementation for " + kdfAlgo);
+                throw new ProviderException(
+                    "No MAC implementation for " + algo);
         }
+        return kdf;
     }
 
     /**
@@ -120,12 +121,13 @@
             throw new InvalidKeyException("SecretKey of PBE type required");
         }
         if (params == null) {
-            // generate default for salt and iteration count if necessary
-            if (salt == null) {
-                salt = new byte[DEFAULT_SALT_LENGTH];
-                SunJCE.getRandom().nextBytes(salt);
+            // should not auto-generate default values since current
+            // javax.crypto.Mac api does not have any method for caller to
+            // retrieve the generated defaults.
+            if ((salt == null) || (iCount == 0)) {
+                throw new InvalidAlgorithmParameterException
+                    ("PBEParameterSpec required for salt and iteration count");
             }
-            if (iCount == 0) iCount = DEFAULT_COUNT;
         } else if (!(params instanceof PBEParameterSpec)) {
             throw new InvalidAlgorithmParameterException
                 ("PBEParameterSpec type required");
@@ -168,7 +170,7 @@
         java.util.Arrays.fill(passwdChars, ' ');
 
         SecretKey s = null;
-
+        PBKDF2Core kdf = getKDFImpl(kdfAlgo);
         try {
             s = kdf.engineGenerateSecret(pbeSpec);
 
--- a/jdk/src/share/classes/com/sun/crypto/provider/SunJCE.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/com/sun/crypto/provider/SunJCE.java	Mon Jun 10 10:38:33 2013 +0100
@@ -731,10 +731,11 @@
                     put("Mac.HmacSHA384 SupportedKeyFormats", "RAW");
                     put("Mac.HmacSHA512 SupportedKeyFormats", "RAW");
                     put("Mac.HmacPBESHA1 SupportedKeyFormats", "RAW");
-                    put("Mac.HmacPBESHA224 SupportedKeyFormats", "RAW");
-                    put("Mac.HmacPBESHA256 SupportedKeyFormats", "RAW");
-                    put("Mac.HmacPBESHA384 SupportedKeyFormats", "RAW");
-                    put("Mac.HmacPBESHA512 SupportedKeyFormats", "RAW");
+                    put("Mac.PBEWithHmacSHA1 SupportedKeyFormatS", "RAW");
+                    put("Mac.PBEWithHmacSHA224 SupportedKeyFormats", "RAW");
+                    put("Mac.PBEWithHmacSHA256 SupportedKeyFormats", "RAW");
+                    put("Mac.PBEWithHmacSHA384 SupportedKeyFormats", "RAW");
+                    put("Mac.PBEWithHmacSHA512 SupportedKeyFormats", "RAW");
                     put("Mac.SslMacMD5 SupportedKeyFormats", "RAW");
                     put("Mac.SslMacSHA1 SupportedKeyFormats", "RAW");
 
--- a/jdk/src/share/classes/com/sun/jndi/toolkit/ctx/Continuation.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/com/sun/jndi/toolkit/ctx/Continuation.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -90,14 +90,16 @@
      * Constructs a new instance of Continuation.
      * @param top The name of the object that is to be resolved/operated upon.
      *          This becomes the Continuation's 'starter' and is used to
-     *          calculate the "resolved name" when filling  in a NamingException.
+     *          calculate the "resolved name" when filling in a NamingException.
      * @param environment The environment used by the caller. It is used
-     * when setting the "environment" of a CannotProceedException.
+     *          when setting the "environment" of a CannotProceedException.
      */
+    @SuppressWarnings("unchecked")  // For Hashtable clone: environment.clone()
     public Continuation(Name top, Hashtable<?,?> environment) {
         super();
         starter = top;
-        this.environment = environment;
+        this.environment = (Hashtable<?,?>)
+                ((environment == null) ? null : environment.clone());
     }
 
     /**
--- a/jdk/src/share/classes/com/sun/jndi/toolkit/dir/LazySearchEnumerationImpl.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/com/sun/jndi/toolkit/dir/LazySearchEnumerationImpl.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -69,6 +69,7 @@
             }
     }
 
+    @SuppressWarnings("unchecked")      // For Hashtable clone: env.clone()
     public LazySearchEnumerationImpl(NamingEnumeration<Binding> candidates,
         AttrFilter filter, SearchControls cons,
         Context ctx, Hashtable<String, Object> env, boolean useFactory)
@@ -76,7 +77,8 @@
 
             this.candidates = candidates;
             this.filter = filter;
-            this.env = env;
+            this.env = (Hashtable<String, Object>)
+                    ((env == null) ? null : env.clone());
             this.context = ctx;
             this.useFactory = useFactory;
 
--- a/jdk/src/share/classes/com/sun/jndi/toolkit/dir/SearchFilter.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/com/sun/jndi/toolkit/dir/SearchFilter.java	Mon Jun 10 10:38:33 2013 +0100
@@ -396,7 +396,7 @@
 
             // do we need to begin with the first token?
             if(proto.charAt(0) != WILDCARD_TOKEN &&
-                    !value.toString().toLowerCase(Locale.ENGLISH).startsWith(
+                    !value.toLowerCase(Locale.ENGLISH).startsWith(
                         subStrs.nextToken().toLowerCase(Locale.ENGLISH))) {
                 if(debug) {
                     System.out.println("faild initial test");
--- a/jdk/src/share/classes/com/sun/jndi/toolkit/url/GenericURLContext.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/com/sun/jndi/toolkit/url/GenericURLContext.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -53,7 +53,8 @@
     @SuppressWarnings("unchecked") // Expect Hashtable<String, Object>
     public GenericURLContext(Hashtable<?,?> env) {
         // context that is not tied to any specific URL
-        myEnv = (Hashtable<String, Object>)env;  // copied on write
+        myEnv =
+            (Hashtable<String, Object>)(env == null ? null : env.clone());
     }
 
     public void close() throws NamingException {
@@ -488,22 +489,19 @@
         return result;
     }
 
-    @SuppressWarnings("unchecked") // clone()
     public Object removeFromEnvironment(String propName)
         throws NamingException {
             if (myEnv == null) {
                 return null;
             }
-            myEnv = (Hashtable<String, Object>)myEnv.clone();
             return myEnv.remove(propName);
     }
 
-    @SuppressWarnings("unchecked") // clone()
     public Object addToEnvironment(String propName, Object propVal)
         throws NamingException {
-            myEnv = (myEnv == null)
-                    ? new Hashtable<String, Object>(11, 0.75f)
-                    : (Hashtable<String, Object>)myEnv.clone();
+            if (myEnv == null) {
+                myEnv = new Hashtable<String, Object>(11, 0.75f);
+            }
             return myEnv.put(propName, propVal);
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/management/DiagnosticCommandMBean.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,220 @@
+/*
+ * 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 com.sun.management;
+
+import java.lang.management.PlatformManagedObject;
+import javax.management.DynamicMBean;
+
+/**
+ * Management interface for the diagnostic commands for the HotSpot Virtual Machine.
+ *
+ * <p>The {code DiagnosticCommandMBean} is registered to the
+ * {@linkplain java.lang.management.ManagementFactory#getPlatformMBeanServer
+ * platform MBeanServer} as are other platform MBeans.
+ *
+ * <p>The {@link javax.management.ObjectName ObjectName} for uniquely identifying
+ * the diagnostic MBean within an MBeanServer is:
+ * <blockquote>
+ *    {@code com.sun.management:type=DiagnosticCommand}
+ * </blockquote>
+ *
+ * <p>This MBean is a {@link javax.management.DynamicMBean DynamicMBean}
+ * and also a {@link javax.management.NotificationEmitter}.
+ * The {@code DiagnosticCommandMBean} is generated at runtime and is subject to
+ * modifications during the lifetime of the Java virtual machine.
+ *
+ * A <em>diagnostic command</em> is represented as an operation of
+ * the {@code DiagnosticCommandMBean} interface. Each diagnostic command has:
+ * <ul>
+ * <li>the diagnostic command name which is the name being referenced in
+ *     the HotSpot Virtual Machine</li>
+ * <li>the MBean operation name which is the
+ *     {@linkplain javax.management.MBeanOperationInfo#getName() name}
+ *     generated for the diagnostic command operation invocation.
+ *     The MBean operation name is implementation dependent</li>
+ * </ul>
+ *
+ * The recommended way to transform a diagnostic command name into a MBean
+ * operation name is as follows:
+ * <ul>
+ * <li>All characters from the first one to the first dot are set to be
+ *      lower-case characters</li>
+ * <li>Every dot or underline character is removed and the following
+ *   character is set to be an upper-case character</li>
+ * <li>All other characters are copied without modification</li>
+ * </ul>
+ *
+ * <p>The diagnostic command name is always provided with the meta-data on the
+ * operation in a field named {@code dcmd.name} (see below).
+ *
+ * <p>A diagnostic command may or may not support options or arguments.
+ * All the operations return {@code String} and either take
+ * no parameter for operations that do not support any option or argument,
+ * or take a {@code String[]} parameter for operations that support at least
+ * one option or argument.
+ * Each option or argument must be stored in a single String.
+ * Options or arguments split across several String instances are not supported.
+ *
+ * <p>The distinction between options and arguments: options are identified by
+ * the option name while arguments are identified by their position in the
+ * command line. Options and arguments are processed in the order of the array
+ * passed to the invocation method.
+ *
+ * <p>Like any operation of a dynamic MBean, each of these operations is
+ * described by {@link javax.management.MBeanOperationInfo MBeanOperationInfo}
+ * instance. Here's the values returned by this object:
+ * <ul>
+ *  <li>{@link javax.management.MBeanOperationInfo#getName() getName()}
+ *      returns the operation name generated from the diagnostic command name</li>
+ *  <li>{@link javax.management.MBeanOperationInfo#getDescription() getDescription()}
+ *      returns the diagnostic command description
+ *      (the same as the one return in the 'help' command)</li>
+ *  <li>{@link javax.management.MBeanOperationInfo#getImpact() getImpact()}
+ *      returns <code>ACTION_INFO</code></li>
+ *  <li>{@link javax.management.MBeanOperationInfo#getReturnType() getReturnType()}
+ *      returns {@code java.lang.String}</li>
+ *  <li>{@link javax.management.MBeanOperationInfo#getDescriptor() getDescriptor()}
+ *      returns a Descriptor instance (see below)</li>
+ * </ul>
+ *
+ * <p>The {@link javax.management.Descriptor Descriptor}
+ * is a collection of fields containing additional
+ * meta-data for a JMX element. A field is a name and an associated value.
+ * The additional meta-data provided for an operation associated with a
+ * diagnostic command are described in the table below:
+ * <p>
+ *
+ * <table border="1" cellpadding="5">
+ *   <tr>
+ *     <th>Name</th><th>Type</th><th>Description</th>
+ *   </tr>
+ *   <tr>
+ *     <td>dcmd.name</td><td>String</td>
+ *     <td>The original diagnostic command name (not the operation name)</td>
+ *   </tr>
+ *   <tr>
+ *     <td>dcmd.description</td><td>String</td>
+ *     <td>The diagnostic command description</td>
+ *   </tr>
+ *   <tr>
+ *     <td>dcmd.help</td><td>String</td>
+ *     <td>The full help message for this diagnostic command (same output as
+ *          the one produced by the 'help' command)</td>
+ *   </tr>
+ *   <tr>
+ *     <td>dcmd.vmImpact</td><td>String</td>
+ *     <td>The impact of the diagnostic command,
+ *      this value is the same as the one printed in the 'impact'
+ *      section of the help message of the diagnostic command, and it
+ *      is different from the getImpact() of the MBeanOperationInfo</td>
+ *   </tr>
+ *   <tr>
+ *     <td>dcmd.enabled</td><td>boolean</td>
+ *     <td>True if the diagnostic command is enabled, false otherwise</td>
+ *   </tr>
+ *   <tr>
+ *     <td>dcmd.permissionClass</td><td>String</td>
+ *     <td>Some diagnostic command might require a specific permission to be
+ *          executed, in addition to the MBeanPermission to invoke their
+ *          associated MBean operation. This field returns the fully qualified
+ *          name of the permission class or null if no permission is required
+ *   </td>
+ *   </tr>
+ *   <tr>
+ *     <td>dcmd.permissionName</td><td>String</td>
+ *     <td>The fist argument of the permission required to execute this
+ *          diagnostic command or null if no permission is required</td>
+ *   </tr>
+ *   <tr>
+ *     <td>dcmd.permissionAction</td><td>String</td>
+ *     <td>The second argument of the permission required to execute this
+ *          diagnostic command or null if the permission constructor has only
+ *          one argument (like the ManagementPermission) or if no permission
+ *          is required</td>
+ *   </tr>
+ *   <tr>
+ *     <td>dcmd.arguments</td><td>Descriptor</td>
+ *     <td>A Descriptor instance containing the descriptions of options and
+ *          arguments supported by the diagnostic command (see below)</td>
+ *   </tr>
+ * </table>
+ * <p>
+ *
+ * <p>The description of parameters (options or arguments) of a diagnostic
+ * command is provided within a Descriptor instance. In this Descriptor,
+ * each field name is a parameter name, and each field value is itself
+ * a Descriptor instance. The fields provided in this second Descriptor
+ * instance are described in the table below:
+ *
+ * <table border="1" cellpadding="5">
+ *   <tr>
+ *     <th>Name</th><th>Type</th><th>Description</th>
+ *   </tr>
+ *   <tr>
+ *     <td>dcmd.arg.name</td><td>String</td>
+ *     <td>The name of the parameter</td>
+ *   </tr>
+ *   <tr>
+ *     <td>dcmd.arg.type</td><td>String</td>
+ *     <td>The type of the parameter. The returned String is the name of a type
+ *          recognized by the diagnostic command parser. These types are not
+ *          Java types and are implementation dependent.
+ *          </td>
+ *   </tr>
+ *   <tr>
+ *     <td>dcmd.arg.description</td><td>String</td>
+ *     <td>The parameter description</td>
+ *   </tr>
+ *   <tr>
+ *     <td>dcmd.arg.isMandatory</td><td>boolean</td>
+ *     <td>True if the parameter is mandatory, false otherwise</td>
+ *   </tr>
+ *   <tr>
+ *     <td>dcmd.arg.isOption</td><td>boolean</td>
+ *     <td>True if the parameter is an option, false if it is an argument</td>
+ *   </tr>
+ *   <tr>
+ *     <td>dcmd.arg.isMultiple</td><td>boolean</td>
+ *     <td>True if the parameter can be specified several times, false
+ *          otherwise</td>
+ *   </tr>
+ * </table>
+ *
+ * <p>When the set of diagnostic commands currently supported by the Java
+ * Virtual Machine is modified, the {@code DiagnosticCommandMBean} emits
+ * a {@link javax.management.Notification} with a
+ * {@linkplain javax.management.Notification#getType() type} of
+ * <a href="{@docRoot}/../../../../api/javax/management/MBeanInfo.html#info-changed">
+ * {@code "jmx.mbean.info.changed"}</a> and a
+ * {@linkplain javax.management.Notification#getUserData() userData} that
+ * is the new {@code MBeanInfo}.
+ *
+ * @since 8
+ */
+public interface DiagnosticCommandMBean extends DynamicMBean
+{
+
+}
--- a/jdk/src/share/classes/java/io/FileInputStream.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/io/FileInputStream.java	Mon Jun 10 10:38:33 2013 +0100
@@ -240,13 +240,15 @@
      *
      * <p>The <code>skip</code> method may, for a variety of
      * reasons, end up skipping over some smaller number of bytes,
-     * possibly <code>0</code>. If <code>n</code> is negative, an
-     * <code>IOException</code> is thrown, even though the <code>skip</code>
-     * method of the {@link InputStream} superclass does nothing in this case.
-     * The actual number of bytes skipped is returned.
+     * possibly <code>0</code>. If <code>n</code> is negative, the method
+     * will try to skip backwards. In case the backing file does not support
+     * backward skip at its current position, an <code>IOException</code> is
+     * thrown. The actual number of bytes skipped is returned. If it skips
+     * forwards, it returns a positive value. If it skips backwards, it
+     * returns a negative value.
      *
-     * <p>This method may skip more bytes than are remaining in the backing
-     * file. This produces no exception and the number of bytes skipped
+     * <p>This method may skip more bytes than what are remaining in the
+     * backing file. This produces no exception and the number of bytes skipped
      * may include some number of bytes that were beyond the EOF of the
      * backing file. Attempting to read from the stream after skipping past
      * the end will result in -1 indicating the end of the file.
@@ -261,9 +263,10 @@
     /**
      * Returns an estimate of the number of remaining bytes that can be read (or
      * skipped over) from this input stream without blocking by the next
-     * invocation of a method for this input stream. The next invocation might be
-     * the same thread or another thread.  A single read or skip of this
-     * many bytes will not block, but may read or skip fewer bytes.
+     * invocation of a method for this input stream. Returns 0 when the file
+     * position is beyond EOF. The next invocation might be the same thread
+     * or another thread. A single read or skip of this many bytes will not
+     * block, but may read or skip fewer bytes.
      *
      * <p> In some cases, a non-blocking read (or skip) may appear to be
      * blocked when it is merely slow, for example when reading large
--- a/jdk/src/share/classes/java/io/InputStream.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/io/InputStream.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -193,8 +193,10 @@
      * up skipping over some smaller number of bytes, possibly <code>0</code>.
      * This may result from any of a number of conditions; reaching end of file
      * before <code>n</code> bytes have been skipped is only one possibility.
-     * The actual number of bytes skipped is returned.  If <code>n</code> is
-     * negative, no bytes are skipped.
+     * The actual number of bytes skipped is returned. If {@code n} is
+     * negative, the {@code skip} method for class {@code InputStream} always
+     * returns 0, and no bytes are skipped. Subclasses may handle the negative
+     * value differently.
      *
      * <p> The <code>skip</code> method of this class creates a
      * byte array and then repeatedly reads into it until <code>n</code> bytes
--- a/jdk/src/share/classes/java/lang/AbstractStringBuilder.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/lang/AbstractStringBuilder.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -689,7 +689,7 @@
      * @return  a reference to this object.
      */
     public AbstractStringBuilder append(float f) {
-        new FloatingDecimal(f).appendTo(this);
+        FloatingDecimal.appendTo(f,this);
         return this;
     }
 
@@ -706,7 +706,7 @@
      * @return  a reference to this object.
      */
     public AbstractStringBuilder append(double d) {
-        new FloatingDecimal(d).appendTo(this);
+        FloatingDecimal.appendTo(d,this);
         return this;
     }
 
--- a/jdk/src/share/classes/java/lang/CharSequence.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/lang/CharSequence.java	Mon Jun 10 10:38:33 2013 +0100
@@ -179,10 +179,25 @@
 
             @Override
             public void forEachRemaining(IntConsumer block) {
-                while (cur < length()) {
-                    int cp = Character.codePointAt(CharSequence.this, cur);
-                    cur += Character.charCount(cp);
-                    block.accept(cp);
+                final int length = length();
+                int i = cur;
+                try {
+                    while (i < length) {
+                        char c1 = charAt(i++);
+                        if (!Character.isHighSurrogate(c1) || i >= length) {
+                            block.accept(c1);
+                        } else {
+                            char c2 = charAt(i);
+                            if (Character.isLowSurrogate(c2)) {
+                                i++;
+                                block.accept(Character.toCodePoint(c1, c2));
+                            } else {
+                                block.accept(c1);
+                            }
+                        }
+                    }
+                } finally {
+                    cur = i;
                 }
             }
 
@@ -191,12 +206,20 @@
             }
 
             public int nextInt() {
-                if (!hasNext()) {
+                final int length = length();
+
+                if (cur >= length) {
                     throw new NoSuchElementException();
                 }
-                int cp = Character.codePointAt(CharSequence.this, cur);
-                cur += Character.charCount(cp);
-                return cp;
+                char c1 = charAt(cur++);
+                if (Character.isHighSurrogate(c1) && cur < length) {
+                    char c2 = charAt(cur);
+                    if (Character.isLowSurrogate(c2)) {
+                        cur++;
+                        return Character.toCodePoint(c1, c2);
+                    }
+                }
+                return c1;
             }
         }
 
--- a/jdk/src/share/classes/java/lang/Class.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/lang/Class.java	Mon Jun 10 10:38:33 2013 +0100
@@ -28,6 +28,7 @@
 import java.lang.reflect.AnnotatedElement;
 import java.lang.reflect.Array;
 import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.GenericDeclaration;
 import java.lang.reflect.Member;
 import java.lang.reflect.Field;
 import java.lang.reflect.Executable;
@@ -115,9 +116,9 @@
  * @since   JDK1.0
  */
 public final class Class<T> implements java.io.Serializable,
-                              java.lang.reflect.GenericDeclaration,
-                              java.lang.reflect.Type,
-                              java.lang.reflect.AnnotatedElement {
+                              GenericDeclaration,
+                              Type,
+                              AnnotatedElement {
     private static final int ANNOTATION= 0x00002000;
     private static final int ENUM      = 0x00004000;
     private static final int SYNTHETIC = 0x00001000;
@@ -2284,14 +2285,6 @@
      */
     private native java.security.ProtectionDomain getProtectionDomain0();
 
-
-    /**
-     * Set the ProtectionDomain for this class. Called by
-     * ClassLoader.defineClass.
-     */
-    native void setProtectionDomain0(java.security.ProtectionDomain pd);
-
-
     /*
      * Return the Virtual Machine's Class object for the named
      * primitive type.
@@ -3255,7 +3248,7 @@
      */
     @Override
     public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
-        return AnnotatedElement.super.isAnnotationPresent(annotationClass);
+        return GenericDeclaration.super.isAnnotationPresent(annotationClass);
     }
 
     /**
--- a/jdk/src/share/classes/java/lang/Double.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/lang/Double.java	Mon Jun 10 10:38:33 2013 +0100
@@ -201,7 +201,7 @@
      * @return a string representation of the argument.
      */
     public static String toString(double d) {
-        return new FloatingDecimal(d).toJavaFormatString();
+        return FloatingDecimal.toJavaFormatString(d);
     }
 
     /**
@@ -509,7 +509,7 @@
      *             parsable number.
      */
     public static Double valueOf(String s) throws NumberFormatException {
-        return new Double(FloatingDecimal.readJavaFormatString(s).doubleValue());
+        return new Double(parseDouble(s));
     }
 
     /**
@@ -545,7 +545,7 @@
      * @since 1.2
      */
     public static double parseDouble(String s) throws NumberFormatException {
-        return FloatingDecimal.readJavaFormatString(s).doubleValue();
+        return FloatingDecimal.parseDouble(s);
     }
 
     /**
--- a/jdk/src/share/classes/java/lang/Float.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/lang/Float.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -203,7 +203,7 @@
      * @return a string representation of the argument.
      */
     public static String toString(float f) {
-        return new FloatingDecimal(f).toJavaFormatString();
+        return FloatingDecimal.toJavaFormatString(f);
     }
 
     /**
@@ -421,7 +421,7 @@
      *          parsable number.
      */
     public static Float valueOf(String s) throws NumberFormatException {
-        return new Float(FloatingDecimal.readJavaFormatString(s).floatValue());
+        return new Float(parseFloat(s));
     }
 
     /**
@@ -456,7 +456,7 @@
      * @since 1.2
      */
     public static float parseFloat(String s) throws NumberFormatException {
-        return FloatingDecimal.readJavaFormatString(s).floatValue();
+        return FloatingDecimal.parseFloat(s);
     }
 
     /**
--- a/jdk/src/share/classes/java/lang/Integer.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/lang/Integer.java	Mon Jun 10 10:38:33 2013 +0100
@@ -26,7 +26,6 @@
 package java.lang;
 
 import java.lang.annotation.Native;
-import java.util.Properties;
 
 /**
  * The {@code Integer} class wraps a value of the primitive type
@@ -185,7 +184,7 @@
      * @since 1.8
      */
     public static String toUnsignedString(int i, int radix) {
-        return Long.toString(toUnsignedLong(i), radix);
+        return Long.toUnsignedString(toUnsignedLong(i), radix);
     }
 
     /**
@@ -307,20 +306,39 @@
     /**
      * Convert the integer to an unsigned number.
      */
-    private static String toUnsignedString0(int i, int shift) {
-        char[] buf = new char[32];
-        int charPos = 32;
+    private static String toUnsignedString0(int val, int shift) {
+        // assert shift > 0 && shift <=5 : "Illegal shift value";
+        int mag = Integer.SIZE - Integer.numberOfLeadingZeros(val);
+        int chars = Math.max(((mag + (shift - 1)) / shift), 1);
+        char[] buf = new char[chars];
+
+        formatUnsignedInt(val, shift, buf, 0, chars);
+
+        // Use special constructor which takes over "buf".
+        return new String(buf, true);
+    }
+
+    /**
+     * Format a long (treated as unsigned) into a character buffer.
+     * @param val the unsigned int to format
+     * @param shift the log2 of the base to format in (4 for hex, 3 for octal, 1 for binary)
+     * @param buf the character buffer to write to
+     * @param offset the offset in the destination buffer to start at
+     * @param len the number of characters to write
+     * @return the lowest character  location used
+     */
+     static int formatUnsignedInt(int val, int shift, char[] buf, int offset, int len) {
+        int charPos = len;
         int radix = 1 << shift;
         int mask = radix - 1;
         do {
-            buf[--charPos] = digits[i & mask];
-            i >>>= shift;
-        } while (i != 0);
+            buf[offset + --charPos] = Integer.digits[val & mask];
+            val >>>= shift;
+        } while (val != 0 && charPos > 0);
 
-        return new String(buf, charPos, (32 - charPos));
+        return charPos;
     }
 
-
     final static char [] DigitTens = {
         '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
         '1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
@@ -875,6 +893,7 @@
      * Returns the value of this {@code Integer} as a {@code long}
      * after a widening primitive conversion.
      * @jls 5.1.2 Widening Primitive Conversions
+     * @see Integer#toUnsignedLong(int)
      */
     public long longValue() {
         return (long)value;
--- a/jdk/src/share/classes/java/lang/Long.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/lang/Long.java	Mon Jun 10 10:38:33 2013 +0100
@@ -28,6 +28,7 @@
 import java.lang.annotation.Native;
 import java.math.*;
 
+
 /**
  * The {@code Long} class wraps a value of the primitive type {@code
  * long} in an object. An object of type {@code Long} contains a
@@ -344,18 +345,39 @@
     }
 
     /**
-     * Convert the integer to an unsigned number.
+     * Format a long (treated as unsigned) into a String.
+     * @param val the value to format
+     * @param shift the log2 of the base to format in (4 for hex, 3 for octal, 1 for binary)
      */
-    private static String toUnsignedString0(long i, int shift) {
-        char[] buf = new char[64];
-        int charPos = 64;
+    static String toUnsignedString0(long val, int shift) {
+        // assert shift > 0 && shift <=5 : "Illegal shift value";
+        int mag = Long.SIZE - Long.numberOfLeadingZeros(val);
+        int chars = Math.max(((mag + (shift - 1)) / shift), 1);
+        char[] buf = new char[chars];
+
+        formatUnsignedLong(val, shift, buf, 0, chars);
+        return new String(buf, true);
+    }
+
+    /**
+     * Format a long (treated as unsigned) into a character buffer.
+     * @param val the unsigned long to format
+     * @param shift the log2 of the base to format in (4 for hex, 3 for octal, 1 for binary)
+     * @param buf the character buffer to write to
+     * @param offset the offset in the destination buffer to start at
+     * @param len the number of characters to write
+     * @return the lowest character location used
+     */
+     static int formatUnsignedLong(long val, int shift, char[] buf, int offset, int len) {
+        int charPos = len;
         int radix = 1 << shift;
-        long mask = radix - 1;
+        int mask = radix - 1;
         do {
-            buf[--charPos] = Integer.digits[(int)(i & mask)];
-            i >>>= shift;
-        } while (i != 0);
-        return new String(buf, charPos, (64 - charPos));
+            buf[offset + --charPos] = Integer.digits[((int) val) & mask];
+            val >>>= shift;
+        } while (val != 0 && charPos > 0);
+
+        return charPos;
     }
 
     /**
--- a/jdk/src/share/classes/java/lang/String.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/lang/String.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1010,13 +1010,14 @@
     private boolean nonSyncContentEquals(AbstractStringBuilder sb) {
         char v1[] = value;
         char v2[] = sb.getValue();
-        int i = 0;
-        int n = value.length;
-        while (n-- != 0) {
+        int n = v1.length;
+        if (n != sb.length()) {
+            return false;
+        }
+        for (int i = 0; i < n; i++) {
             if (v1[i] != v2[i]) {
                 return false;
             }
-            i++;
         }
         return true;
     }
@@ -1038,8 +1039,6 @@
      * @since  1.5
      */
     public boolean contentEquals(CharSequence cs) {
-        if (value.length != cs.length())
-            return false;
         // Argument is a StringBuffer, StringBuilder
         if (cs instanceof AbstractStringBuilder) {
             if (cs instanceof StringBuffer) {
@@ -1055,12 +1054,14 @@
             return true;
         // Argument is a generic CharSequence
         char v1[] = value;
-        int i = 0;
-        int n = value.length;
-        while (n-- != 0) {
-            if (v1[i] != cs.charAt(i))
+        int n = v1.length;
+        if (n != cs.length()) {
+            return false;
+        }
+        for (int i = 0; i < n; i++) {
+            if (v1[i] != cs.charAt(i)) {
                 return false;
-            i++;
+            }
         }
         return true;
     }
--- a/jdk/src/share/classes/java/lang/StringBuffer.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/lang/StringBuffer.java	Mon Jun 10 10:38:33 2013 +0100
@@ -335,10 +335,8 @@
      * @since 1.5
      */
     @Override
-    public StringBuffer append(CharSequence s) {
-        // Note, synchronization achieved via invocations of other StringBuffer methods after
-        // narrowing of s to specific type
-        // Ditto for toStringCache clearing
+    public synchronized StringBuffer append(CharSequence s) {
+        toStringCache = null;
         super.append(s);
         return this;
     }
--- a/jdk/src/share/classes/java/lang/Thread.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/lang/Thread.java	Mon Jun 10 10:38:33 2013 +0100
@@ -145,10 +145,10 @@
         registerNatives();
     }
 
-    private char        name[];
-    private int         priority;
-    private Thread      threadQ;
-    private long        eetop;
+    private volatile char  name[];
+    private int            priority;
+    private Thread         threadQ;
+    private long           eetop;
 
     /* Whether or not to single_step this thread. */
     private boolean     single_step;
@@ -1135,7 +1135,7 @@
      * @see        #getName
      * @see        #checkAccess()
      */
-    public final void setName(String name) {
+    public final synchronized void setName(String name) {
         checkAccess();
         this.name = name.toCharArray();
         if (threadStatus != 0) {
@@ -1150,7 +1150,7 @@
      * @see     #setName(String)
      */
     public final String getName() {
-        return String.valueOf(name);
+        return new String(name, true);
     }
 
     /**
--- a/jdk/src/share/classes/java/lang/annotation/IncompleteAnnotationException.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/lang/annotation/IncompleteAnnotationException.java	Mon Jun 10 10:38:33 2013 +0100
@@ -55,8 +55,7 @@
     public IncompleteAnnotationException(
             Class<? extends Annotation> annotationType,
             String elementName) {
-        super(annotationType.getName().toString() +
-              " missing element " +
+        super(annotationType.getName() + " missing element " +
               elementName.toString());
 
         this.annotationType = annotationType;
--- a/jdk/src/share/classes/java/lang/management/ManagementFactory.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/lang/management/ManagementFactory.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -42,7 +42,9 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Map;
 import java.security.AccessController;
 import java.security.Permission;
 import java.security.PrivilegedAction;
@@ -482,6 +484,11 @@
                     }
                 }
             }
+            HashMap<ObjectName, DynamicMBean> dynmbeans =
+                    ManagementFactoryHelper.getPlatformDynamicMBeans();
+            for (Map.Entry<ObjectName, DynamicMBean> e : dynmbeans.entrySet()) {
+                addDynamicMBean(platformMBeanServer, e.getValue(), e.getKey());
+            }
         }
         return platformMBeanServer;
     }
@@ -825,4 +832,24 @@
         }
     }
 
+    /**
+     * Registers a DynamicMBean.
+     */
+    private static void addDynamicMBean(final MBeanServer mbs,
+                                        final DynamicMBean dmbean,
+                                        final ObjectName on) {
+        try {
+            AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
+                @Override
+                public Void run() throws InstanceAlreadyExistsException,
+                                         MBeanRegistrationException,
+                                         NotCompliantMBeanException {
+                    mbs.registerMBean(dmbean, on);
+                    return null;
+                }
+            });
+        } catch (PrivilegedActionException e) {
+            throw new RuntimeException(e.getException());
+        }
+    }
 }
--- a/jdk/src/share/classes/java/lang/ref/Reference.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/lang/ref/Reference.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -138,8 +138,23 @@
                         pending = r.discovered;
                         r.discovered = null;
                     } else {
+                        // The waiting on the lock may cause an OOME because it may try to allocate
+                        // exception objects, so also catch OOME here to avoid silent exit of the
+                        // reference handler thread.
+                        //
+                        // Explicitly define the order of the two exceptions we catch here
+                        // when waiting for the lock.
+                        //
+                        // We do not want to try to potentially load the InterruptedException class
+                        // (which would be done if this was its first use, and InterruptedException
+                        // were checked first) in this situation.
+                        //
+                        // This may lead to the VM not ever trying to load the InterruptedException
+                        // class again.
                         try {
-                            lock.wait();
+                            try {
+                                lock.wait();
+                            } catch (OutOfMemoryError x) { }
                         } catch (InterruptedException x) { }
                         continue;
                     }
--- a/jdk/src/share/classes/java/lang/reflect/GenericDeclaration.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/lang/reflect/GenericDeclaration.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -30,7 +30,7 @@
  *
  * @since 1.5
  */
-public interface GenericDeclaration {
+public interface GenericDeclaration extends AnnotatedElement {
     /**
      * Returns an array of {@code TypeVariable} objects that
      * represent the type variables declared by the generic
--- a/jdk/src/share/classes/java/net/CookiePolicy.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/net/CookiePolicy.java	Mon Jun 10 10:38:33 2013 +0100
@@ -59,6 +59,8 @@
      */
     public static final CookiePolicy ACCEPT_ORIGINAL_SERVER  = new CookiePolicy(){
         public boolean shouldAccept(URI uri, HttpCookie cookie) {
+            if (uri == null || cookie == null)
+                return false;
             return HttpCookie.domainMatches(cookie.getDomain(), uri.getHost());
         }
     };
--- a/jdk/src/share/classes/java/net/HttpCookie.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/net/HttpCookie.java	Mon Jun 10 10:38:33 2013 +0100
@@ -128,8 +128,7 @@
      *         a {@code String} specifying the value of the cookie
      *
      * @throws  IllegalArgumentException
-     *          if the cookie name contains illegal characters or it is one of
-     *          the tokens reserved for use by the cookie protocol
+     *          if the cookie name contains illegal characters
      * @throws  NullPointerException
      *          if {@code name} is {@code null}
      *
@@ -142,7 +141,7 @@
 
     private HttpCookie(String name, String value, String header) {
         name = name.trim();
-        if (name.length() == 0 || !isToken(name)) {
+        if (name.length() == 0 || !isToken(name) || name.charAt(0) == '$') {
             throw new IllegalArgumentException("Illegal cookie name");
         }
 
@@ -170,9 +169,8 @@
      * @return  a List of cookie parsed from header line string
      *
      * @throws  IllegalArgumentException
-     *          if header string violates the cookie specification's syntax, or
-     *          the cookie name contains illegal characters, or the cookie name
-     *          is one of the tokens reserved for use by the cookie protocol
+     *          if header string violates the cookie specification's syntax or
+     *          the cookie name contains illegal characters.
      * @throws  NullPointerException
      *          if the header string is {@code null}
      */
--- a/jdk/src/share/classes/java/net/HttpURLPermission.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/net/HttpURLPermission.java	Mon Jun 10 10:38:33 2013 +0100
@@ -377,7 +377,7 @@
             throw new IllegalArgumentException ("unexpected URL scheme");
         }
         if (!u.getSchemeSpecificPart().equals("*")) {
-            u = URI.create(scheme + "://" + u.getAuthority() + u.getPath());
+            u = URI.create(scheme + "://" + u.getRawAuthority() + u.getRawPath());
         }
         return u;
     }
--- a/jdk/src/share/classes/java/nio/Buffer.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/nio/Buffer.java	Mon Jun 10 10:38:33 2013 +0100
@@ -25,6 +25,7 @@
 
 package java.nio;
 
+import java.util.Spliterator;
 
 /**
  * A container for data of a specific primitive type.
@@ -173,6 +174,13 @@
 
 public abstract class Buffer {
 
+    /**
+     * The characteristics of Spliterators that traverse and split elements
+     * maintained in Buffers.
+     */
+    static final int SPLITERATOR_CHARACTERISTICS =
+        Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.ORDERED;
+
     // Invariants: mark <= position <= limit <= capacity
     private int mark = -1;
     private int position = 0;
--- a/jdk/src/share/classes/java/nio/ByteBufferAs-X-Buffer.java.template	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/nio/ByteBufferAs-X-Buffer.java.template	Mon Jun 10 10:38:33 2013 +0100
@@ -115,6 +115,12 @@
         return Bits.get$Type$$BO$(bb, ix(checkIndex(i)));
     }
 
+#if[streamableType]
+   $type$ getUnchecked(int i) {
+        return Bits.get$Type$$BO$(bb, ix(i));
+    }
+#end[streamableType]
+
 #end[rw]
 
     public $Type$Buffer put($type$ x) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/CharBufferSpliterator.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+* particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio;
+
+import java.util.Comparator;
+import java.util.Spliterator;
+import java.util.function.IntConsumer;
+
+/**
+ * A Spliterator.OfInt for sources that traverse and split elements
+ * maintained in a CharBuffer.
+ *
+ * @implNote
+ * The implementation is based on the code for the Array-based spliterators.
+ */
+class CharBufferSpliterator implements Spliterator.OfInt {
+    private final CharBuffer buffer;
+    private int index;   // current index, modified on advance/split
+    private final int limit;
+
+    CharBufferSpliterator(CharBuffer buffer) {
+        this(buffer, buffer.position(), buffer.limit());
+    }
+
+    CharBufferSpliterator(CharBuffer buffer, int origin, int limit) {
+        assert origin <= limit;
+        this.buffer = buffer;
+        this.index = (origin <= limit) ? origin : limit;
+        this.limit = limit;
+    }
+
+    @Override
+    public OfInt trySplit() {
+        int lo = index, mid = (lo + limit) >>> 1;
+        return (lo >= mid)
+               ? null
+               : new CharBufferSpliterator(buffer, lo, index = mid);
+    }
+
+    @Override
+    public void forEachRemaining(IntConsumer action) {
+        if (action == null)
+            throw new NullPointerException();
+        CharBuffer cb = buffer;
+        int i = index;
+        int hi = limit;
+        index = hi;
+        while (i < hi) {
+            action.accept(cb.getUnchecked(i++));
+        }
+    }
+
+    @Override
+    public boolean tryAdvance(IntConsumer action) {
+        if (action == null)
+            throw new NullPointerException();
+        if (index >= 0 && index < limit) {
+            action.accept(buffer.getUnchecked(index++));
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public long estimateSize() {
+        return (long)(limit - index);
+    }
+
+    @Override
+    public int characteristics() {
+        return Buffer.SPLITERATOR_CHARACTERISTICS;
+    }
+}
--- a/jdk/src/share/classes/java/nio/Direct-X-Buffer.java.template	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/nio/Direct-X-Buffer.java.template	Mon Jun 10 10:38:33 2013 +0100
@@ -253,6 +253,12 @@
         return $fromBits$($swap$(unsafe.get$Swaptype$(ix(checkIndex(i)))));
     }
 
+#if[streamableType]
+    $type$ getUnchecked(int i) {
+        return $fromBits$($swap$(unsafe.get$Swaptype$(ix(i))));
+    }
+#end[streamableType]
+
     public $Type$Buffer get($type$[] dst, int offset, int length) {
 #if[rw]
         if ((length << $LG_BYTES_PER_VALUE$) > Bits.JNI_COPY_TO_ARRAY_THRESHOLD) {
--- a/jdk/src/share/classes/java/nio/Heap-X-Buffer.java.template	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/nio/Heap-X-Buffer.java.template	Mon Jun 10 10:38:33 2013 +0100
@@ -139,6 +139,12 @@
         return hb[ix(checkIndex(i))];
     }
 
+#if[streamableType]
+    $type$ getUnchecked(int i) {
+	return hb[ix(i)];
+    }
+#end[streamableType]
+
     public $Type$Buffer get($type$[] dst, int offset, int length) {
         checkBounds(offset, length, dst.length);
         if (length > remaining())
--- a/jdk/src/share/classes/java/nio/StringCharBuffer.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/nio/StringCharBuffer.java	Mon Jun 10 10:38:33 2013 +0100
@@ -77,6 +77,10 @@
         return str.charAt(checkIndex(index) + offset);
     }
 
+    char getUnchecked(int index) {
+        return str.charAt(index + offset);
+    }
+
     // ## Override bulk get methods for better performance
 
     public final CharBuffer put(char c) {
--- a/jdk/src/share/classes/java/nio/X-Buffer.java.template	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/nio/X-Buffer.java.template	Mon Jun 10 10:38:33 2013 +0100
@@ -30,6 +30,11 @@
 #if[char]
 import java.io.IOException;
 #end[char]
+#if[streamableType]
+import java.util.Spliterator;
+import java.util.stream.StreamSupport;
+import java.util.stream.$Streamtype$Stream;
+#end[streamableType]
 
 /**
  * $A$ $type$ buffer.
@@ -589,6 +594,19 @@
      */
     public abstract $type$ get(int index);
 
+#if[streamableType]
+    /**
+     * Absolute <i>get</i> method.  Reads the $type$ at the given
+     * index without any validation of the index.
+     *
+     * @param  index
+     *         The index from which the $type$ will be read
+     *
+     * @return  The $type$ at the given index
+     */
+    abstract $type$ getUnchecked(int index);   // package-private
+#end[streamableType]
+
     /**
      * Absolute <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
      *
@@ -1458,4 +1476,16 @@
 
 #end[byte]
 
+#if[streamableType]
+
+#if[char]
+    @Override
+#end[char]
+    public $Streamtype$Stream $type$s() {
+        return StreamSupport.$streamtype$Stream(() -> new $Type$BufferSpliterator(this),
+            Buffer.SPLITERATOR_CHARACTERISTICS);
+    }
+
+#end[streamableType]
+
 }
--- a/jdk/src/share/classes/java/nio/charset/Charset-X-Coder.java.template	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/nio/charset/Charset-X-Coder.java.template	Mon Jun 10 10:38:33 2013 +0100
@@ -34,6 +34,7 @@
 import java.nio.BufferUnderflowException;
 import java.lang.ref.WeakReference;
 import java.nio.charset.CoderMalfunctionError;                  // javadoc
+import java.util.Arrays;
 
 
 /**
@@ -244,7 +245,12 @@
      *          which is never <tt>null</tt> and is never empty
      */
     public final $replType$ replacement() {
+#if[decoder]
         return replacement;
+#end[decoder]
+#if[encoder]
+        return Arrays.copyOf(replacement, replacement.$replLength$);
+#end[encoder]
     }
 
     /**
@@ -280,12 +286,15 @@
             throw new IllegalArgumentException("Empty replacement");
         if (len > max$ItypesPerOtype$)
             throw new IllegalArgumentException("Replacement too long");
+#if[decoder]
+        this.replacement = newReplacement;
+#end[decoder]
 #if[encoder]
         if (!isLegalReplacement(newReplacement))
             throw new IllegalArgumentException("Illegal replacement");
+        this.replacement = Arrays.copyOf(newReplacement, newReplacement.$replLength$);
 #end[encoder]
-        this.replacement = newReplacement;
-        implReplaceWith(newReplacement);
+        implReplaceWith(this.replacement);
         return this;
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/FileTreeIterator.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.nio.file.FileTreeWalker.Event;
+
+/**
+ * An {@code Iterator to iterate over the nodes of a file tree.
+ *
+ * <pre>{@code
+ *     try (FileTreeIterator iterator = new FileTreeIterator(start, maxDepth, options)) {
+ *         while (iterator.hasNext()) {
+ *             Event ev = iterator.next();
+ *             Path path = ev.file();
+ *             BasicFileAttributes attrs = ev.attributes();
+ *         }
+ *     }
+ * }</pre>
+ */
+
+class FileTreeIterator implements Iterator<Event>, Closeable {
+    private final FileTreeWalker walker;
+    private Event next;
+
+    /**
+     * Creates a new iterator to walk the file tree starting at the given file.
+     *
+     * @throws  IllegalArgumentException
+     *          if {@code maxDepth} is negative
+     * @throws  IOException
+     *          if an I/O errors occurs opening the starting file
+     * @throws  SecurityException
+     *          if the security manager denies access to the starting file
+     * @throws  NullPointerException
+     *          if {@code start} or {@code options} is {@ocde null} or
+     *          the options array contains a {@code null} element
+     */
+    FileTreeIterator(Path start, int maxDepth, FileVisitOption... options)
+        throws IOException
+    {
+        this.walker = new FileTreeWalker(Arrays.asList(options), maxDepth);
+        this.next = walker.walk(start);
+        assert next.type() == FileTreeWalker.EventType.ENTRY ||
+               next.type() == FileTreeWalker.EventType.START_DIRECTORY;
+
+        // IOException if there a problem accessing the starting file
+        IOException ioe = next.ioeException();
+        if (ioe != null)
+            throw ioe;
+    }
+
+    private void fetchNextIfNeeded() {
+        if (next == null) {
+            FileTreeWalker.Event ev = walker.next();
+            while (ev != null) {
+                IOException ioe = ev.ioeException();
+                if (ioe != null)
+                    throw new UncheckedIOException(ioe);
+
+                // END_DIRECTORY events are ignored
+                if (ev.type() != FileTreeWalker.EventType.END_DIRECTORY) {
+                    next = ev;
+                    return;
+                }
+                ev = walker.next();
+            }
+        }
+    }
+
+    @Override
+    public boolean hasNext() {
+        if (!walker.isOpen())
+            throw new IllegalStateException();
+        fetchNextIfNeeded();
+        return next != null;
+    }
+
+    @Override
+    public Event next() {
+        if (!walker.isOpen())
+            throw new IllegalStateException();
+        fetchNextIfNeeded();
+        if (next == null)
+            throw new NoSuchElementException();
+        Event result = next;
+        next = null;
+        return result;
+    }
+
+    @Override
+    public void close() {
+        walker.close();
+    }
+}
--- a/jdk/src/share/classes/java/nio/file/FileTreeWalker.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/nio/file/FileTreeWalker.java	Mon Jun 10 10:38:33 2013 +0100
@@ -29,8 +29,8 @@
 import java.io.Closeable;
 import java.io.IOException;
 import java.util.ArrayDeque;
+import java.util.Collection;
 import java.util.Iterator;
-import java.util.Set;
 import sun.nio.fs.BasicFileAttributesHolder;
 
 /**
@@ -164,8 +164,17 @@
 
     /**
      * Creates a {@code FileTreeWalker}.
+     *
+     * @throws  IllegalArgumentException
+     *          if {@code maxDepth} is negative
+     * @throws  ClassCastException
+     *          if (@code options} contains an element that is not a
+     *          {@code FileVisitOption}
+     * @throws  NullPointerException
+     *          if {@code options} is {@ocde null} or the options
+     *          array contains a {@code null} element
      */
-    FileTreeWalker(Set<FileVisitOption> options, int maxDepth) {
+    FileTreeWalker(Collection<FileVisitOption> options, int maxDepth) {
         boolean fl = false;
         for (FileVisitOption option: options) {
             // will throw NPE if options contains null
@@ -175,6 +184,9 @@
                     throw new AssertionError("Should not get here");
             }
         }
+        if (maxDepth < 0)
+            throw new IllegalArgumentException("'maxDepth' is negative");
+
         this.followLinks = fl;
         this.linkOptions = (fl) ? new LinkOption[0] :
             new LinkOption[] { LinkOption.NOFOLLOW_LINKS };
--- a/jdk/src/share/classes/java/nio/file/Files.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/nio/file/Files.java	Mon Jun 10 10:38:33 2013 +0100
@@ -25,10 +25,13 @@
 
 package java.nio.file;
 
+import java.nio.ByteBuffer;
 import java.nio.file.attribute.*;
 import java.nio.file.spi.FileSystemProvider;
 import java.nio.file.spi.FileTypeDetector;
+import java.nio.channels.FileChannel;
 import java.nio.channels.SeekableByteChannel;
+import java.io.Closeable;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.Reader;
@@ -38,7 +41,13 @@
 import java.io.InputStreamReader;
 import java.io.OutputStreamWriter;
 import java.io.IOException;
+import java.io.UncheckedIOException;
 import java.util.*;
+import java.util.function.BiPredicate;
+import java.util.stream.CloseableStream;
+import java.util.stream.DelegatingStream;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.nio.charset.Charset;
@@ -2596,9 +2605,6 @@
                                     FileVisitor<? super Path> visitor)
         throws IOException
     {
-        if (maxDepth < 0)
-            throw new IllegalArgumentException("'maxDepth' is negative");
-
         /**
          * Create a FileTreeWalker to walk the file tree, invoking the visitor
          * for each event.
@@ -2950,40 +2956,6 @@
     }
 
     /**
-     * Read all the bytes from an input stream. The {@code initialSize}
-     * parameter indicates the initial size of the byte[] to allocate.
-     */
-    private static byte[] read(InputStream source, int initialSize)
-        throws IOException
-    {
-        int capacity = initialSize;
-        byte[] buf = new byte[capacity];
-        int nread = 0;
-        int rem = buf.length;
-        int n;
-        // read to EOF which may read more or less than initialSize (eg: file
-        // is truncated while we are reading)
-        while ((n = source.read(buf, nread, rem)) > 0) {
-            nread += n;
-            rem -= n;
-            assert rem >= 0;
-            if (rem == 0) {
-                // need larger buffer
-                int newCapacity = capacity << 1;
-                if (newCapacity < 0) {
-                    if (capacity == Integer.MAX_VALUE)
-                        throw new OutOfMemoryError("Required array size too large");
-                    newCapacity = Integer.MAX_VALUE;
-                }
-                rem = newCapacity - capacity;
-                buf = Arrays.copyOf(buf, newCapacity);
-                capacity = newCapacity;
-            }
-        }
-        return (capacity == nread) ? buf : Arrays.copyOf(buf, nread);
-    }
-
-    /**
      * Read all the bytes from a file. The method ensures that the file is
      * closed when all bytes have been read or an I/O error, or other runtime
      * exception, is thrown.
@@ -3008,12 +2980,22 @@
      *          method is invoked to check read access to the file.
      */
     public static byte[] readAllBytes(Path path) throws IOException {
-        long size = size(path);
-        if (size > (long)Integer.MAX_VALUE)
-            throw new OutOfMemoryError("Required array size too large");
+        try (FileChannel fc = FileChannel.open(path)) {
+            long size = fc.size();
+            if (size > (long)Integer.MAX_VALUE)
+                throw new OutOfMemoryError("Required array size too large");
 
-        try (InputStream in = newInputStream(path)) {
-             return read(in, (int)size);
+            byte[] arr = new byte[(int)size];
+            ByteBuffer bb = ByteBuffer.wrap(arr);
+            while (bb.hasRemaining()) {
+                if (fc.read(bb) < 0) {
+                    // truncated
+                    break;
+                }
+            }
+
+            int nread = bb.position();
+            return (nread == size) ? arr : Arrays.copyOf(arr, nread);
         }
     }
 
@@ -3186,4 +3168,336 @@
         }
         return path;
     }
+
+    // -- Stream APIs --
+
+    /**
+     * Implementation of CloseableStream
+     */
+    private static class DelegatingCloseableStream<T> extends DelegatingStream<T>
+        implements CloseableStream<T>
+    {
+        private final Closeable closeable;
+
+        DelegatingCloseableStream(Closeable c, Stream<T> delegate) {
+            super(delegate);
+            this.closeable = c;
+        }
+
+        public void close() {
+            try {
+                closeable.close();
+            } catch (IOException ex) {
+                throw new UncheckedIOException(ex);
+            }
+        }
+    }
+
+    /**
+     * Return a lazily populated {@code CloseableStream}, the elements of
+     * which are the entries in the directory.  The listing is not recursive.
+     *
+     * <p> The elements of the stream are {@link Path} objects that are
+     * obtained as if by {@link Path#resolve(Path) resolving} the name of the
+     * directory entry against {@code dir}. Some file systems maintain special
+     * links to the directory itself and the directory's parent directory.
+     * Entries representing these links are not included.
+     *
+     * <p> The stream is <i>weakly consistent</i>. It is thread safe but does
+     * not freeze the directory while iterating, so it may (or may not)
+     * reflect updates to the directory that occur after returning from this
+     * method.
+     *
+     * <p> When not using the try-with-resources construct, then the stream's
+     * {@link CloseableStream#close close} method should be invoked after the
+     * operation is completed so as to free any resources held for the open
+     * directory. Operating on a closed stream behaves as if the end of stream
+     * has been reached. Due to read-ahead, one or more elements may be
+     * returned after the stream has been closed.
+     *
+     * <p> If an {@link IOException} is thrown when accessing the directory
+     * after this method has returned, it is wrapped in an {@link
+     * UncheckedIOException} which will be thrown from the method that caused
+     * the access to take place.
+     *
+     * @param   dir  The path to the directory
+     *
+     * @return  The {@code CloseableStream} describing the content of the
+     *          directory
+     *
+     * @throws  NotDirectoryException
+     *          if the file could not otherwise be opened because it is not
+     *          a directory <i>(optional specific exception)</i>
+     * @throws  IOException
+     *          if an I/O error occurs when opening the directory
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to the directory.
+     *
+     * @see     #newDirectoryStream(Path)
+     * @since   1.8
+     */
+    public static CloseableStream<Path> list(Path dir) throws IOException {
+        DirectoryStream<Path> ds = Files.newDirectoryStream(dir);
+        final Iterator<Path> delegate = ds.iterator();
+
+        // Re-wrap DirectoryIteratorException to UncheckedIOException
+        Iterator<Path> it = new Iterator<Path>() {
+            public boolean hasNext() {
+                try {
+                    return delegate.hasNext();
+                } catch (DirectoryIteratorException e) {
+                    throw new UncheckedIOException(e.getCause());
+                }
+            }
+            public Path next() {
+                try {
+                    return delegate.next();
+                } catch (DirectoryIteratorException e) {
+                    throw new UncheckedIOException(e.getCause());
+                }
+            }
+        };
+
+        return new DelegatingCloseableStream<>(ds,
+            StreamSupport.stream(Spliterators.spliteratorUnknownSize(it,
+                                                                     Spliterator.DISTINCT)));
+    }
+
+    /**
+     * Return a {@code CloseableStream} that is lazily populated with {@code
+     * Path} by walking the file tree rooted at a given starting file.  The
+     * file tree is traversed <em>depth-first</em>, the elements in the stream
+     * are {@link Path} objects that are obtained as if by {@link
+     * Path#resolve(Path) resolving} the relative path against {@code start}.
+     *
+     * <p> The {@code stream} walks the file tree as elements are consumed.
+     * The {@code CloseableStream} returned is guaranteed to have at least one
+     * element, the starting file itself. For each file visited, the stream
+     * attempts to read its {@link BasicFileAttributes}. If the file is a
+     * directory and can be opened successfully, entries in the directory, and
+     * their <em>descendants</em> will follow the directory in the stream as
+     * they are encountered. When all entries have been visited, then the
+     * directory is closed. The file tree walk then continues at the next
+     * <em>sibling</em> of the directory.
+     *
+     * <p> The stream is <i>weakly consistent</i>. It does not freeze the
+     * file tree while iterating, so it may (or may not) reflect updates to
+     * the file tree that occur after returned from this method.
+     *
+     * <p> By default, symbolic links are not automatically followed by this
+     * method. If the {@code options} parameter contains the {@link
+     * FileVisitOption#FOLLOW_LINKS FOLLOW_LINKS} option then symbolic links are
+     * followed. When following links, and the attributes of the target cannot
+     * be read, then this method attempts to get the {@code BasicFileAttributes}
+     * of the link.
+     *
+     * <p> If the {@code options} parameter contains the {@link
+     * FileVisitOption#FOLLOW_LINKS FOLLOW_LINKS} option then the stream keeps
+     * track of directories visited so that cycles can be detected. A cycle
+     * arises when there is an entry in a directory that is an ancestor of the
+     * directory. Cycle detection is done by recording the {@link
+     * java.nio.file.attribute.BasicFileAttributes#fileKey file-key} of directories,
+     * or if file keys are not available, by invoking the {@link #isSameFile
+     * isSameFile} method to test if a directory is the same file as an
+     * ancestor. When a cycle is detected it is treated as an I/O error with
+     * an instance of {@link FileSystemLoopException}.
+     *
+     * <p> The {@code maxDepth} parameter is the maximum number of levels of
+     * directories to visit. A value of {@code 0} means that only the starting
+     * file is visited, unless denied by the security manager. A value of
+     * {@link Integer#MAX_VALUE MAX_VALUE} may be used to indicate that all
+     * levels should be visited.
+     *
+     * <p> When a security manager is installed and it denies access to a file
+     * (or directory), then it is ignored and not included in the stream.
+     *
+     * <p> When not using the try-with-resources construct, then the stream's
+     * {@link CloseableStream#close close} method should be invoked after the
+     * operation is completed so as to free any resources held for the open
+     * directory. Operate the stream after it is closed will throw an
+     * {@link java.lang.IllegalStateException}.
+     *
+     * <p> If an {@link IOException} is thrown when accessing the directory
+     * after this method has returned, it is wrapped in an {@link
+     * UncheckedIOException} which will be thrown from the method that caused
+     * the access to take place.
+     *
+     * @param   start
+     *          the starting file
+     * @param   maxDepth
+     *          the maximum number of directory levels to visit
+     * @param   options
+     *          options to configure the traversal
+     *
+     * @return  the {@link CloseableStream} of {@link Path}
+     *
+     * @throws  IllegalArgumentException
+     *          if the {@code maxDepth} parameter is negative
+     * @throws  SecurityException
+     *          If the security manager denies access to the starting file.
+     *          In the case of the default provider, the {@link
+     *          SecurityManager#checkRead(String) checkRead} method is invoked
+     *          to check read access to the directory.
+     * @throws  IOException
+     *          if an I/O error is thrown when accessing the starting file.
+     * @since   1.8
+     */
+    public static CloseableStream<Path> walk(Path start, int maxDepth,
+                                             FileVisitOption... options)
+        throws IOException
+    {
+        FileTreeIterator iterator = new FileTreeIterator(start, maxDepth, options);
+        return new DelegatingCloseableStream<>(iterator,
+            StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT))
+                   .map(entry -> entry.file()));
+    }
+
+    /**
+     * Return a {@code CloseableStream} that is lazily populated with {@code
+     * Path} by walking the file tree rooted at a given starting file.  The
+     * file tree is traversed <em>depth-first</em>, the elements in the stream
+     * are {@link Path} objects that are obtained as if by {@link
+     * Path#resolve(Path) resolving} the relative path against {@code start}.
+     *
+     * <p> This method works as if invoking it were equivalent to evaluating the
+     * expression:
+     * <blockquote><pre>
+     * walk(start, Integer.MAX_VALUE, options)
+     * </pre></blockquote>
+     * In other words, it visits all levels of the file tree.
+     *
+     * @param   start
+     *          the starting file
+     * @param   options
+     *          options to configure the traversal
+     *
+     * @return  the {@link CloseableStream} of {@link Path}
+     *
+     * @throws  SecurityException
+     *          If the security manager denies access to the starting file.
+     *          In the case of the default provider, the {@link
+     *          SecurityManager#checkRead(String) checkRead} method is invoked
+     *          to check read access to the directory.
+     * @throws  IOException
+     *          if an I/O error is thrown when accessing the starting file.
+     *
+     * @see     #walk(Path, int, FileVisitOption...)
+     * @since   1.8
+     */
+    public static CloseableStream<Path> walk(Path start,
+                                             FileVisitOption... options)
+        throws IOException
+    {
+        return walk(start, Integer.MAX_VALUE, options);
+    }
+
+    /**
+     * Return a {@code CloseableStream} that is lazily populated with {@code
+     * Path} by searching for files in a file tree rooted at a given starting
+     * file.
+     *
+     * <p> This method walks the file tree in exactly the manner specified by
+     * the {@link #walk walk} method. For each file encountered, the given
+     * {@link BiPredicate} is invoked with its {@link Path} and {@link
+     * BasicFileAttributes}. The {@code Path} object is obtained as if by
+     * {@link Path#resolve(Path) resolving} the relative path against {@code
+     * start} and is only included in the returned {@link CloseableStream} if
+     * the {@code BiPredicate} returns true. Compare to calling {@link
+     * java.util.stream.Stream#filter filter} on the {@code Stream}
+     * returned by {@code walk} method, this method may be more efficient by
+     * avoiding redundant retrieval of the {@code BasicFileAttributes}.
+     *
+     * <p> If an {@link IOException} is thrown when accessing the directory
+     * after returned from this method, it is wrapped in an {@link
+     * UncheckedIOException} which will be thrown from the method that caused
+     * the access to take place.
+     *
+     * @param   start
+     *          the starting file
+     * @param   maxDepth
+     *          the maximum number of directory levels to search
+     * @param   matcher
+     *          the function used to decide whether a file should be included
+     *          in the returned stream
+     * @param   options
+     *          options to configure the traversal
+     *
+     * @return  the {@link CloseableStream} of {@link Path}
+     *
+     * @throws  IllegalArgumentException
+     *          if the {@code maxDepth} parameter is negative
+     * @throws  SecurityException
+     *          If the security manager denies access to the starting file.
+     *          In the case of the default provider, the {@link
+     *          SecurityManager#checkRead(String) checkRead} method is invoked
+     *          to check read access to the directory.
+     * @throws  IOException
+     *          if an I/O error is thrown when accessing the starting file.
+     *
+     * @see     #walk(Path, int, FileVisitOption...)
+     * @since   1.8
+     */
+    public static CloseableStream<Path> find(Path start,
+                                             int maxDepth,
+                                             BiPredicate<Path, BasicFileAttributes> matcher,
+                                             FileVisitOption... options)
+        throws IOException
+    {
+        FileTreeIterator iterator = new FileTreeIterator(start, maxDepth, options);
+        return new DelegatingCloseableStream<>(iterator,
+            StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT))
+                   .filter(entry -> matcher.test(entry.file(), entry.attributes()))
+                   .map(entry -> entry.file()));
+    }
+
+    /**
+     * Read all lines from a file as a {@code CloseableStream}.  Unlike {@link
+     * #readAllLines(Path, Charset) readAllLines}, this method does not read
+     * all lines into a {@code List}, but instead populates lazily as the stream
+     * is consumed.
+     *
+     * <p> Bytes from the file are decoded into characters using the specified
+     * charset and the same line terminators as specified by {@code
+     * readAllLines} are supported.
+     *
+     * <p> After this method returns, then any subsequent I/O exception that
+     * occurs while reading from the file or when a malformed or unmappable byte
+     * sequence is read, is wrapped in an {@link UncheckedIOException} that will
+     * be thrown form the
+     * {@link java.util.stream.Stream} method that caused the read to take
+     * place. In case an {@code IOException} is thrown when closing the file,
+     * it is also wrapped as an {@code UncheckedIOException}.
+     *
+     * <p> When not using the try-with-resources construct, then stream's
+     * {@link CloseableStream#close close} method should be invoked after
+     * operation is completed so as to free any resources held for the open
+     * file.
+     *
+     * @param   path
+     *          the path to the file
+     * @param   cs
+     *          the charset to use for decoding
+     *
+     * @return  the lines from the file as a {@code CloseableStream}
+     *
+     * @throws  IOException
+     *          if an I/O error occurs opening the file
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to the file.
+     *
+     * @see     #readAllLines(Path, Charset)
+     * @see     #newBufferedReader(Path, Charset)
+     * @see     java.io.BufferedReader#lines()
+     * @since   1.8
+     */
+    public static CloseableStream<String> lines(Path path, Charset cs)
+        throws IOException
+    {
+        BufferedReader br = Files.newBufferedReader(path, cs);
+        return new DelegatingCloseableStream<>(br, br.lines());
+    }
 }
--- a/jdk/src/share/classes/java/security/AccessControlContext.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/security/AccessControlContext.java	Mon Jun 10 10:38:33 2013 +0100
@@ -88,6 +88,15 @@
 
     private DomainCombiner combiner = null;
 
+    // limited privilege scope
+    private Permission permissions[];
+    private AccessControlContext parent;
+    private boolean isWrapped;
+
+    // is constrained by limited privilege scope?
+    private boolean isLimited;
+    private ProtectionDomain limitedContext[];
+
     private static boolean debugInit = false;
     private static Debug debug = null;
 
@@ -182,15 +191,80 @@
 
     /**
      * package private for AccessController
+     *
+     * This "argument wrapper" context will be passed as the actual context
+     * parameter on an internal doPrivileged() call used in the implementation.
      */
-    AccessControlContext(ProtectionDomain context[], DomainCombiner combiner) {
+    AccessControlContext(ProtectionDomain caller, DomainCombiner combiner,
+        AccessControlContext parent, AccessControlContext context,
+        Permission[] perms)
+    {
+        /*
+         * Combine the domains from the doPrivileged() context into our
+         * wrapper context, if necessary.
+         */
+        ProtectionDomain[] callerPDs = null;
+        if (caller != null) {
+             callerPDs = new ProtectionDomain[] { caller };
+        }
         if (context != null) {
-            this.context = context.clone();
+            if (combiner != null) {
+                this.context = combiner.combine(callerPDs, context.context);
+            } else {
+                this.context = combine(callerPDs, context.context);
+            }
+        } else {
+            /*
+             * Call combiner even if there is seemingly nothing to combine.
+             */
+            if (combiner != null) {
+                this.context = combiner.combine(callerPDs, null);
+            } else {
+                this.context = combine(callerPDs, null);
+            }
         }
         this.combiner = combiner;
+
+        Permission[] tmp = null;
+        if (perms != null) {
+            tmp = new Permission[perms.length];
+            for (int i=0; i < perms.length; i++) {
+                if (perms[i] == null) {
+                    throw new NullPointerException("permission can't be null");
+                }
+
+                /*
+                 * An AllPermission argument is equivalent to calling
+                 * doPrivileged() without any limit permissions.
+                 */
+                if (perms[i].getClass() == AllPermission.class) {
+                    parent = null;
+                }
+                tmp[i] = perms[i];
+            }
+        }
+
+        /*
+         * For a doPrivileged() with limited privilege scope, initialize
+         * the relevant fields.
+         *
+         * The limitedContext field contains the union of all domains which
+         * are enclosed by this limited privilege scope. In other words,
+         * it contains all of the domains which could potentially be checked
+         * if none of the limiting permissions implied a requested permission.
+         */
+        if (parent != null) {
+            this.limitedContext = combine(parent.context, parent.limitedContext);
+            this.isLimited = true;
+            this.isWrapped = true;
+            this.permissions = tmp;
+            this.parent = parent;
+            this.privilegedContext = context; // used in checkPermission2()
+        }
         this.isAuthorized = true;
     }
 
+
     /**
      * package private constructor for AccessController.getContext()
      */
@@ -266,6 +340,13 @@
         if (sm != null) {
             sm.checkPermission(SecurityConstants.GET_COMBINER_PERMISSION);
         }
+        return getCombiner();
+    }
+
+    /**
+     * package private for AccessController
+     */
+    DomainCombiner getCombiner() {
         return combiner;
     }
 
@@ -341,8 +422,10 @@
            or the first domain was a Privileged system domain. This
            is to make the common case for system code very fast */
 
-        if (context == null)
+        if (context == null) {
+            checkPermission2(perm);
             return;
+        }
 
         for (int i=0; i< context.length; i++) {
             if (context[i] != null &&  !context[i].implies(perm)) {
@@ -376,20 +459,108 @@
             debug.println("access allowed "+perm);
         }
 
-        return;
+        checkPermission2(perm);
+    }
+
+    /*
+     * Check the domains associated with the limited privilege scope.
+     */
+    private void checkPermission2(Permission perm) {
+        if (!isLimited) {
+            return;
+        }
+
+        /*
+         * Check the doPrivileged() context parameter, if present.
+         */
+        if (privilegedContext != null) {
+            privilegedContext.checkPermission2(perm);
+        }
+
+        /*
+         * Ignore the limited permissions and parent fields of a wrapper
+         * context since they were already carried down into the unwrapped
+         * context.
+         */
+        if (isWrapped) {
+            return;
+        }
+
+        /*
+         * Try to match any limited privilege scope.
+         */
+        if (permissions != null) {
+            Class<?> permClass = perm.getClass();
+            for (int i=0; i < permissions.length; i++) {
+                Permission limit = permissions[i];
+                if (limit.getClass().equals(permClass) && limit.implies(perm)) {
+                    return;
+                }
+            }
+        }
+
+        /*
+         * Check the limited privilege scope up the call stack or the inherited
+         * parent thread call stack of this ACC.
+         */
+        if (parent != null) {
+            /*
+             * As an optimization, if the parent context is the inherited call
+             * stack context from a parent thread then checking the protection
+             * domains of the parent context is redundant since they have
+             * already been merged into the child thread's context by
+             * optimize(). When parent is set to an inherited context this
+             * context was not directly created by a limited scope
+             * doPrivileged() and it does not have its own limited permissions.
+             */
+            if (permissions == null) {
+                parent.checkPermission2(perm);
+            } else {
+                parent.checkPermission(perm);
+            }
+        }
     }
 
     /**
      * Take the stack-based context (this) and combine it with the
-     * privileged or inherited context, if need be.
+     * privileged or inherited context, if need be. Any limited
+     * privilege scope is flagged regardless of whether the assigned
+     * context comes from an immediately enclosing limited doPrivileged().
+     * The limited privilege scope can indirectly flow from the inherited
+     * parent thread or an assigned context previously captured by getContext().
      */
     AccessControlContext optimize() {
         // the assigned (privileged or inherited) context
         AccessControlContext acc;
+        DomainCombiner combiner = null;
+        AccessControlContext parent = null;
+        Permission[] permissions = null;
+
         if (isPrivileged) {
             acc = privilegedContext;
+            if (acc != null) {
+                /*
+                 * If the context is from a limited scope doPrivileged() then
+                 * copy the permissions and parent fields out of the wrapper
+                 * context that was created to hold them.
+                 */
+                if (acc.isWrapped) {
+                    permissions = acc.permissions;
+                    parent = acc.parent;
+                }
+            }
         } else {
             acc = AccessController.getInheritedAccessControlContext();
+            if (acc != null) {
+                /*
+                 * If the inherited context is constrained by a limited scope
+                 * doPrivileged() then set it as our parent so we will process
+                 * the non-domain-related state.
+                 */
+                if (acc.isLimited) {
+                    parent = acc;
+                }
+            }
         }
 
         // this.context could be null if only system code is on the stack;
@@ -399,53 +570,98 @@
         // acc.context could be null if only system code was involved;
         // in that case, ignore the assigned context
         boolean skipAssigned = (acc == null || acc.context == null);
+        ProtectionDomain[] assigned = (skipAssigned) ? null : acc.context;
+        ProtectionDomain[] pd;
+
+        // if there is no enclosing limited privilege scope on the stack or
+        // inherited from a parent thread
+        boolean skipLimited = ((acc == null || !acc.isWrapped) && parent == null);
 
         if (acc != null && acc.combiner != null) {
             // let the assigned acc's combiner do its thing
-            return goCombiner(context, acc);
+            if (getDebug() != null) {
+                debug.println("AccessControlContext invoking the Combiner");
+            }
+
+            // No need to clone current and assigned.context
+            // combine() will not update them
+            combiner = acc.combiner;
+            pd = combiner.combine(context, assigned);
+        } else {
+            if (skipStack) {
+                if (skipAssigned) {
+                    calculateFields(acc, parent, permissions);
+                    return this;
+                } else if (skipLimited) {
+                    return acc;
+                }
+            } else if (assigned != null) {
+                if (skipLimited) {
+                    // optimization: if there is a single stack domain and
+                    // that domain is already in the assigned context; no
+                    // need to combine
+                    if (context.length == 1 && context[0] == assigned[0]) {
+                        return acc;
+                    }
+                }
+            }
+
+            pd = combine(context, assigned);
+            if (skipLimited && !skipAssigned && pd == assigned) {
+                return acc;
+            } else if (skipAssigned && pd == context) {
+                calculateFields(acc, parent, permissions);
+                return this;
+            }
         }
 
-        // optimization: if neither have contexts; return acc if possible
-        // rather than this, because acc might have a combiner
-        if (skipAssigned && skipStack) {
-            return this;
-        }
+        // Reuse existing ACC
+        this.context = pd;
+        this.combiner = combiner;
+        this.isPrivileged = false;
+
+        calculateFields(acc, parent, permissions);
+        return this;
+    }
+
 
-        // optimization: if there is no stack context; there is no reason
-        // to compress the assigned context, it already is compressed
-        if (skipStack) {
-            return acc;
-        }
+    /*
+     * Combine the current (stack) and assigned domains.
+     */
+    private static ProtectionDomain[] combine(ProtectionDomain[]current,
+        ProtectionDomain[] assigned) {
 
-        int slen = context.length;
+        // current could be null if only system code is on the stack;
+        // in that case, ignore the stack context
+        boolean skipStack = (current == null);
+
+        // assigned could be null if only system code was involved;
+        // in that case, ignore the assigned context
+        boolean skipAssigned = (assigned == null);
+
+        int slen = (skipStack) ? 0 : current.length;
 
         // optimization: if there is no assigned context and the stack length
         // is less then or equal to two; there is no reason to compress the
         // stack context, it already is
         if (skipAssigned && slen <= 2) {
-            return this;
+            return current;
         }
 
-        // optimization: if there is a single stack domain and that domain
-        // is already in the assigned context; no need to combine
-        if ((slen == 1) && (context[0] == acc.context[0])) {
-            return acc;
-        }
-
-        int n = (skipAssigned) ? 0 : acc.context.length;
+        int n = (skipAssigned) ? 0 : assigned.length;
 
         // now we combine both of them, and create a new context
         ProtectionDomain pd[] = new ProtectionDomain[slen + n];
 
         // first copy in the assigned context domains, no need to compress
         if (!skipAssigned) {
-            System.arraycopy(acc.context, 0, pd, 0, n);
+            System.arraycopy(assigned, 0, pd, 0, n);
         }
 
         // now add the stack context domains, discarding nulls and duplicates
     outer:
-        for (int i = 0; i < context.length; i++) {
-            ProtectionDomain sd = context[i];
+        for (int i = 0; i < slen; i++) {
+            ProtectionDomain sd = current[i];
             if (sd != null) {
                 for (int j = 0; j < n; j++) {
                     if (sd == pd[j]) {
@@ -459,54 +675,47 @@
         // if length isn't equal, we need to shorten the array
         if (n != pd.length) {
             // optimization: if we didn't really combine anything
-            if (!skipAssigned && n == acc.context.length) {
-                return acc;
+            if (!skipAssigned && n == assigned.length) {
+                return assigned;
             } else if (skipAssigned && n == slen) {
-                return this;
+                return current;
             }
             ProtectionDomain tmp[] = new ProtectionDomain[n];
             System.arraycopy(pd, 0, tmp, 0, n);
             pd = tmp;
         }
 
-        //      return new AccessControlContext(pd, false);
-
-        // Reuse existing ACC
-
-        this.context = pd;
-        this.combiner = null;
-        this.isPrivileged = false;
-
-        return this;
+        return pd;
     }
 
-    private AccessControlContext goCombiner(ProtectionDomain[] current,
-                                            AccessControlContext assigned) {
-
-        // the assigned ACC's combiner is not null --
-        // let the combiner do its thing
-
-        // XXX we could add optimizations to 'current' here ...
-
-        if (getDebug() != null) {
-            debug.println("AccessControlContext invoking the Combiner");
-        }
 
-        // No need to clone current and assigned.context
-        // combine() will not update them
-        ProtectionDomain[] combinedPds = assigned.combiner.combine(
-            current, assigned.context);
-
-        // return new AccessControlContext(combinedPds, assigned.combiner);
+    /*
+     * Calculate the additional domains that could potentially be reached via
+     * limited privilege scope. Mark the context as being subject to limited
+     * privilege scope unless the reachable domains (if any) are already
+     * contained in this domain context (in which case any limited
+     * privilege scope checking would be redundant).
+     */
+    private void calculateFields(AccessControlContext assigned,
+        AccessControlContext parent, Permission[] permissions)
+    {
+        ProtectionDomain[] parentLimit = null;
+        ProtectionDomain[] assignedLimit = null;
+        ProtectionDomain[] newLimit;
 
-        // Reuse existing ACC
-        this.context = combinedPds;
-        this.combiner = assigned.combiner;
-        this.isPrivileged = false;
-        this.isAuthorized = assigned.isAuthorized;
+        parentLimit = (parent != null)? parent.limitedContext: null;
+        assignedLimit = (assigned != null)? assigned.limitedContext: null;
+        newLimit = combine(parentLimit, assignedLimit);
+        if (newLimit != null) {
+            if (context == null || !containsAllPDs(newLimit, context)) {
+                this.limitedContext = newLimit;
+                this.permissions = permissions;
+                this.parent = parent;
+                this.isLimited = true;
+            }
+        }
+    }
 
-        return this;
-    }
 
     /**
      * Checks two AccessControlContext objects for equality.
@@ -527,31 +736,131 @@
 
         AccessControlContext that = (AccessControlContext) obj;
 
+        if (!equalContext(that))
+            return false;
 
-        if (context == null) {
-            return (that.context == null);
-        }
+        if (!equalLimitedContext(that))
+            return false;
+
+        return true;
+    }
 
-        if (that.context == null)
+    /*
+     * Compare for equality based on state that is free of limited
+     * privilege complications.
+     */
+    private boolean equalContext(AccessControlContext that) {
+        if (!equalPDs(this.context, that.context))
             return false;
 
-        if (!(this.containsAllPDs(that) && that.containsAllPDs(this)))
+        if (this.combiner == null && that.combiner != null)
+            return false;
+
+        if (this.combiner != null && !this.combiner.equals(that.combiner))
             return false;
 
-        if (this.combiner == null)
-            return (that.combiner == null);
+        return true;
+    }
 
-        if (that.combiner == null)
+    private boolean equalPDs(ProtectionDomain[] a, ProtectionDomain[] b) {
+        if (a == null) {
+            return (b == null);
+        }
+
+        if (b == null)
             return false;
 
-        if (!this.combiner.equals(that.combiner))
+        if (!(containsAllPDs(a, b) && containsAllPDs(b, a)))
             return false;
 
         return true;
     }
 
-    private boolean containsAllPDs(AccessControlContext that) {
+    /*
+     * Compare for equality based on state that is captured during a
+     * call to AccessController.getContext() when a limited privilege
+     * scope is in effect.
+     */
+    private boolean equalLimitedContext(AccessControlContext that) {
+        if (that == null)
+            return false;
+
+        /*
+         * If neither instance has limited privilege scope then we're done.
+         */
+        if (!this.isLimited && !that.isLimited)
+            return true;
+
+        /*
+         * If only one instance has limited privilege scope then we're done.
+         */
+         if (!(this.isLimited && that.isLimited))
+             return false;
+
+        /*
+         * Wrapped instances should never escape outside the implementation
+         * this class and AccessController so this will probably never happen
+         * but it only makes any sense to compare if they both have the same
+         * isWrapped state.
+         */
+        if ((this.isWrapped && !that.isWrapped) ||
+            (!this.isWrapped && that.isWrapped)) {
+            return false;
+        }
+
+        if (this.permissions == null && that.permissions != null)
+            return false;
+
+        if (this.permissions != null && that.permissions == null)
+            return false;
+
+        if (!(this.containsAllLimits(that) && that.containsAllLimits(this)))
+            return false;
+
+        /*
+         * Skip through any wrapped contexts.
+         */
+        AccessControlContext thisNextPC = getNextPC(this);
+        AccessControlContext thatNextPC = getNextPC(that);
+
+        /*
+         * The protection domains and combiner of a privilegedContext are
+         * not relevant because they have already been included in the context
+         * of this instance by optimize() so we only care about any limited
+         * privilege state they may have.
+         */
+        if (thisNextPC == null && thatNextPC != null && thatNextPC.isLimited)
+            return false;
+
+        if (thisNextPC != null && !thisNextPC.equalLimitedContext(thatNextPC))
+            return false;
+
+        if (this.parent == null && that.parent != null)
+            return false;
+
+        if (this.parent != null && !this.parent.equals(that.parent))
+            return false;
+
+        return true;
+    }
+
+    /*
+     * Follow the privilegedContext link making our best effort to skip
+     * through any wrapper contexts.
+     */
+    private static AccessControlContext getNextPC(AccessControlContext acc) {
+        while (acc != null && acc.privilegedContext != null) {
+            acc = acc.privilegedContext;
+            if (!acc.isWrapped)
+                return acc;
+        }
+        return null;
+    }
+
+    private static boolean containsAllPDs(ProtectionDomain[] thisContext,
+        ProtectionDomain[] thatContext) {
         boolean match = false;
+
         //
         // ProtectionDomains within an ACC currently cannot be null
         // and this is enforced by the constructor and the various
@@ -559,17 +868,17 @@
         // to support the notion of a null PD and therefore this logic continues
         // to support that notion.
         ProtectionDomain thisPd;
-        for (int i = 0; i < context.length; i++) {
+        for (int i = 0; i < thisContext.length; i++) {
             match = false;
-            if ((thisPd = context[i]) == null) {
-                for (int j = 0; (j < that.context.length) && !match; j++) {
-                    match = (that.context[j] == null);
+            if ((thisPd = thisContext[i]) == null) {
+                for (int j = 0; (j < thatContext.length) && !match; j++) {
+                    match = (thatContext[j] == null);
                 }
             } else {
                 Class<?> thisPdClass = thisPd.getClass();
                 ProtectionDomain thatPd;
-                for (int j = 0; (j < that.context.length) && !match; j++) {
-                    thatPd = that.context[j];
+                for (int j = 0; (j < thatContext.length) && !match; j++) {
+                    thatPd = thatContext[j];
 
                     // Class check required to avoid PD exposure (4285406)
                     match = (thatPd != null &&
@@ -580,6 +889,29 @@
         }
         return match;
     }
+
+    private boolean containsAllLimits(AccessControlContext that) {
+        boolean match = false;
+        Permission thisPerm;
+
+        if (this.permissions == null && that.permissions == null)
+            return true;
+
+        for (int i = 0; i < this.permissions.length; i++) {
+            Permission limit = this.permissions[i];
+            Class <?> limitClass = limit.getClass();
+            match = false;
+            for (int j = 0; (j < that.permissions.length) && !match; j++) {
+                Permission perm = that.permissions[j];
+                match = (limitClass.equals(perm.getClass()) &&
+                    limit.equals(perm));
+            }
+            if (!match) return false;
+        }
+        return match;
+    }
+
+
     /**
      * Returns the hash code value for this context. The hash code
      * is computed by exclusive or-ing the hash code of all the protection
@@ -598,6 +930,7 @@
             if (context[i] != null)
                 hashCode ^= context[i].hashCode();
         }
+
         return hashCode;
     }
 }
--- a/jdk/src/share/classes/java/security/AccessController.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/security/AccessController.java	Mon Jun 10 10:38:33 2013 +0100
@@ -82,9 +82,15 @@
  *     else if (caller i is marked as privileged) {
  *         if (a context was specified in the call to doPrivileged)
  *             context.checkPermission(permission)
- *         return;
+ *         if (limited permissions were specified in the call to doPrivileged) {
+ *             for (each limited permission) {
+ *                 if (the limited permission implies the requested permission)
+ *                     return;
+ *             }
+ *         } else
+ *             return;
  *     }
- * };
+ * }
  *
  * // Next, check the context inherited when the thread was created.
  * // Whenever a new thread is created, the AccessControlContext at
@@ -101,11 +107,16 @@
  * was marked as "privileged" via a <code>doPrivileged</code>
  * call without a context argument (see below for information about a
  * context argument). If that caller's domain has the
- * specified permission, no further checking is done and
+ * specified permission and at least one limiting permission argument (if any)
+ * implies the requested permission, no further checking is done and
  * <code>checkPermission</code>
  * returns quietly, indicating that the requested access is allowed.
  * If that domain does not have the specified permission, an exception
- * is thrown, as usual.
+ * is thrown, as usual. If the caller's domain had the specified permission
+ * but it was not implied by any limiting permission arguments given in the call
+ * to <code>doPrivileged</code> then the permission checking continues
+ * until there are no more callers or another <code>doPrivileged</code>
+ * call matches the requested permission and returns normally.
  *
  * <p> The normal use of the "privileged" feature is as follows. If you
  * don't need to return a value from within the "privileged" block, do
@@ -180,6 +191,9 @@
  *
  * <p> Be *very* careful in your use of the "privileged" construct, and
  * always remember to make the privileged code section as small as possible.
+ * You can pass <code>Permission</code> arguments to further limit the
+ * scope of the "privilege" (see below).
+ *
  *
  * <p> Note that <code>checkPermission</code> always performs security checks
  * within the context of the currently executing thread.
@@ -215,7 +229,9 @@
  *
  * <p> There are also times where you don't know a priori which permissions
  * to check the context against. In these cases you can use the
- * doPrivileged method that takes a context:
+ * doPrivileged method that takes a context. You can also limit the scope
+ * of the privileged code by passing additional <code>Permission</code>
+ * parameters.
  *
  *  <pre> {@code
  * somemethod() {
@@ -223,12 +239,21 @@
  *         public Object run() {
  *             // Code goes here. Any permission checks within this
  *             // run method will require that the intersection of the
- *             // callers protection domain and the snapshot's
- *             // context have the desired permission.
+ *             // caller's protection domain and the snapshot's
+ *             // context have the desired permission. If a requested
+ *             // permission is not implied by the limiting FilePermission
+ *             // argument then checking of the thread continues beyond the
+ *             // caller of doPrivileged.
  *         }
- *     }, acc);
+ *     }, acc, new FilePermission("/temp/*", read));
  *     ...normal code here...
  * }}</pre>
+ * <p> Passing a limiting <code>Permission</code> argument of an instance of
+ * <code>AllPermission</code> is equivalent to calling the equivalent
+ * <code>doPrivileged</code> method without limiting <code>Permission</code>
+ * arguments. Passing a zero length array of <code>Permission</code> disables
+ * the code privileges so that checking always continues beyond the caller of
+ * that <code>doPrivileged</code> method.
  *
  * @see AccessControlContext
  *
@@ -337,6 +362,112 @@
     public static native <T> T doPrivileged(PrivilegedAction<T> action,
                                             AccessControlContext context);
 
+
+    /**
+     * Performs the specified <code>PrivilegedAction</code> with privileges
+     * enabled and restricted by the specified
+     * <code>AccessControlContext</code> and with a privilege scope limited
+     * by specified <code>Permission</code> arguments.
+     *
+     * The action is performed with the intersection of the permissions
+     * possessed by the caller's protection domain, and those possessed
+     * by the domains represented by the specified
+     * <code>AccessControlContext</code>.
+     * <p>
+     * If the action's <code>run</code> method throws an (unchecked) exception,
+     * it will propagate through this method.
+     *
+     * @param action the action to be performed.
+     * @param context an <i>access control context</i>
+     *                representing the restriction to be applied to the
+     *                caller's domain's privileges before performing
+     *                the specified action.  If the context is
+     *                <code>null</code>,
+     *                then no additional restriction is applied.
+     * @param perms the <code>Permission</code> arguments which limit the
+     *              scope of the caller's privileges. The number of arguments
+     *              is variable.
+     *
+     * @return the value returned by the action's <code>run</code> method.
+     *
+     * @throws NullPointerException if action or perms or any element of
+     *         perms is <code>null</code>
+     *
+     * @see #doPrivileged(PrivilegedAction)
+     * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
+     *
+     * @since 1.8
+     */
+    @CallerSensitive
+    public static <T> T doPrivileged(PrivilegedAction<T> action,
+        AccessControlContext context, Permission... perms) {
+
+        AccessControlContext parent = getContext();
+        if (perms == null) {
+            throw new NullPointerException("null permissions parameter");
+        }
+        Class <?> caller = Reflection.getCallerClass();
+        return AccessController.doPrivileged(action, createWrapper(null,
+            caller, parent, context, perms));
+    }
+
+
+    /**
+     * Performs the specified <code>PrivilegedAction</code> with privileges
+     * enabled and restricted by the specified
+     * <code>AccessControlContext</code> and with a privilege scope limited
+     * by specified <code>Permission</code> arguments.
+     *
+     * The action is performed with the intersection of the permissions
+     * possessed by the caller's protection domain, and those possessed
+     * by the domains represented by the specified
+     * <code>AccessControlContext</code>.
+     * <p>
+     * If the action's <code>run</code> method throws an (unchecked) exception,
+     * it will propagate through this method.
+     *
+     * <p> This method preserves the current AccessControlContext's
+     * DomainCombiner (which may be null) while the action is performed.
+     *
+     * @param action the action to be performed.
+     * @param context an <i>access control context</i>
+     *                representing the restriction to be applied to the
+     *                caller's domain's privileges before performing
+     *                the specified action.  If the context is
+     *                <code>null</code>,
+     *                then no additional restriction is applied.
+     * @param perms the <code>Permission</code> arguments which limit the
+     *              scope of the caller's privileges. The number of arguments
+     *              is variable.
+     *
+     * @return the value returned by the action's <code>run</code> method.
+     *
+     * @throws NullPointerException if action or perms or any element of
+     *         perms is <code>null</code>
+     *
+     * @see #doPrivileged(PrivilegedAction)
+     * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
+     * @see java.security.DomainCombiner
+     *
+     * @since 1.8
+     */
+    @CallerSensitive
+    public static <T> T doPrivilegedWithCombiner(PrivilegedAction<T> action,
+        AccessControlContext context, Permission... perms) {
+
+        AccessControlContext parent = getContext();
+        DomainCombiner dc = parent.getCombiner();
+        if (dc == null && context != null) {
+            dc = context.getCombiner();
+        }
+        if (perms == null) {
+            throw new NullPointerException("null permissions parameter");
+        }
+        Class <?> caller = Reflection.getCallerClass();
+        return AccessController.doPrivileged(action, createWrapper(dc, caller,
+            parent, context, perms));
+    }
+
     /**
      * Performs the specified <code>PrivilegedExceptionAction</code> with
      * privileges enabled.  The action is performed with <i>all</i> of the
@@ -411,6 +542,22 @@
     private static AccessControlContext preserveCombiner(DomainCombiner combiner,
                                                          Class<?> caller)
     {
+        return createWrapper(combiner, caller, null, null, null);
+    }
+
+    /**
+     * Create a wrapper to contain the limited privilege scope data.
+     */
+    private static AccessControlContext
+        createWrapper(DomainCombiner combiner, Class<?> caller,
+                      AccessControlContext parent, AccessControlContext context,
+                      Permission[] perms)
+    {
+        return new AccessControlContext(getCallerPD(caller), combiner, parent,
+                                        context, perms);
+    }
+
+    private static ProtectionDomain getCallerPD(final Class <?> caller) {
         ProtectionDomain callerPd = doPrivileged
             (new PrivilegedAction<ProtectionDomain>() {
             public ProtectionDomain run() {
@@ -418,18 +565,9 @@
             }
         });
 
-        // perform 'combine' on the caller of doPrivileged,
-        // even if the caller is from the bootclasspath
-        ProtectionDomain[] pds = new ProtectionDomain[] {callerPd};
-        if (combiner == null) {
-            return new AccessControlContext(pds);
-        } else {
-            return new AccessControlContext(combiner.combine(pds, null),
-                                            combiner);
-        }
+        return callerPd;
     }
 
-
     /**
      * Performs the specified {@code PrivilegedExceptionAction} with
      * privileges enabled and restricted by the specified
@@ -461,7 +599,7 @@
      * @exception NullPointerException if the action is {@code null}
      *
      * @see #doPrivileged(PrivilegedAction)
-     * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
+     * @see #doPrivileged(PrivilegedAction,AccessControlContext)
      */
     @CallerSensitive
     public static native <T> T
@@ -469,6 +607,118 @@
                      AccessControlContext context)
         throws PrivilegedActionException;
 
+
+    /**
+     * Performs the specified <code>PrivilegedExceptionAction</code> with
+     * privileges enabled and restricted by the specified
+     * <code>AccessControlContext</code> and with a privilege scope limited by
+     * specified <code>Permission</code> arguments.
+     *
+     * The action is performed with the intersection of the permissions
+     * possessed by the caller's protection domain, and those possessed
+     * by the domains represented by the specified
+     * <code>AccessControlContext</code>.
+     * <p>
+     * If the action's <code>run</code> method throws an (unchecked) exception,
+     * it will propagate through this method.
+     *
+     * @param action the action to be performed.
+     * @param context an <i>access control context</i>
+     *                representing the restriction to be applied to the
+     *                caller's domain's privileges before performing
+     *                the specified action.  If the context is
+     *                <code>null</code>,
+     *                then no additional restriction is applied.
+     * @param perms the <code>Permission</code> arguments which limit the
+     *              scope of the caller's privileges. The number of arguments
+     *              is variable.
+     *
+     * @return the value returned by the action's <code>run</code> method.
+     *
+     * @throws PrivilegedActionException if the specified action's
+     *         <code>run</code> method threw a <i>checked</i> exception
+     * @throws NullPointerException if action or perms or any element of
+     *         perms is <code>null</code>
+     *
+     * @see #doPrivileged(PrivilegedAction)
+     * @see #doPrivileged(PrivilegedAction,AccessControlContext)
+     *
+     * @since 1.8
+     */
+    @CallerSensitive
+    public static <T> T doPrivileged(PrivilegedExceptionAction<T> action,
+                                     AccessControlContext context, Permission... perms)
+        throws PrivilegedActionException
+    {
+        AccessControlContext parent = getContext();
+        if (perms == null) {
+            throw new NullPointerException("null permissions parameter");
+        }
+        Class <?> caller = Reflection.getCallerClass();
+        return AccessController.doPrivileged(action, createWrapper(null, caller, parent, context, perms));
+    }
+
+
+    /**
+     * Performs the specified <code>PrivilegedExceptionAction</code> with
+     * privileges enabled and restricted by the specified
+     * <code>AccessControlContext</code> and with a privilege scope limited by
+     * specified <code>Permission</code> arguments.
+     *
+     * The action is performed with the intersection of the permissions
+     * possessed by the caller's protection domain, and those possessed
+     * by the domains represented by the specified
+     * <code>AccessControlContext</code>.
+     * <p>
+     * If the action's <code>run</code> method throws an (unchecked) exception,
+     * it will propagate through this method.
+     *
+     * <p> This method preserves the current AccessControlContext's
+     * DomainCombiner (which may be null) while the action is performed.
+     *
+     * @param action the action to be performed.
+     * @param context an <i>access control context</i>
+     *                representing the restriction to be applied to the
+     *                caller's domain's privileges before performing
+     *                the specified action.  If the context is
+     *                <code>null</code>,
+     *                then no additional restriction is applied.
+     * @param perms the <code>Permission</code> arguments which limit the
+     *              scope of the caller's privileges. The number of arguments
+     *              is variable.
+     *
+     * @return the value returned by the action's <code>run</code> method.
+     *
+     * @throws PrivilegedActionException if the specified action's
+     *         <code>run</code> method threw a <i>checked</i> exception
+     * @throws NullPointerException if action or perms or any element of
+     *         perms is <code>null</code>
+     *
+     * @see #doPrivileged(PrivilegedAction)
+     * @see #doPrivileged(PrivilegedAction,AccessControlContext)
+     * @see java.security.DomainCombiner
+     *
+     * @since 1.8
+     */
+    @CallerSensitive
+    public static <T> T doPrivilegedWithCombiner(PrivilegedExceptionAction<T> action,
+                                                 AccessControlContext context,
+                                                 Permission... perms)
+        throws PrivilegedActionException
+    {
+        AccessControlContext parent = getContext();
+        DomainCombiner dc = parent.getCombiner();
+        if (dc == null && context != null) {
+            dc = context.getCombiner();
+        }
+        if (perms == null) {
+            throw new NullPointerException("null permissions parameter");
+        }
+        Class <?> caller = Reflection.getCallerClass();
+        return AccessController.doPrivileged(action, createWrapper(dc, caller,
+            parent, context, perms));
+    }
+
     /**
      * Returns the AccessControl context. i.e., it gets
      * the protection domains of all the callers on the stack,
@@ -481,6 +731,7 @@
 
     private static native AccessControlContext getStackAccessControlContext();
 
+
     /**
      * Returns the "inherited" AccessControl context. This is the context
      * that existed when the thread was created. Package private so
@@ -491,9 +742,9 @@
 
     /**
      * This method takes a "snapshot" of the current calling context, which
-     * includes the current Thread's inherited AccessControlContext,
-     * and places it in an AccessControlContext object. This context may then
-     * be checked at a later point, possibly in another thread.
+     * includes the current Thread's inherited AccessControlContext and any
+     * limited privilege scope, and places it in an AccessControlContext object.
+     * This context may then be checked at a later point, possibly in another thread.
      *
      * @see AccessControlContext
      *
@@ -531,7 +782,7 @@
      */
 
     public static void checkPermission(Permission perm)
-                 throws AccessControlException
+        throws AccessControlException
     {
         //System.err.println("checkPermission "+perm);
         //Thread.currentThread().dumpStack();
--- a/jdk/src/share/classes/java/security/DigestOutputStream.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/security/DigestOutputStream.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 1999, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -112,10 +112,10 @@
      * @see MessageDigest#update(byte)
      */
     public void write(int b) throws IOException {
+        out.write(b);
         if (on) {
             digest.update((byte)b);
         }
-        out.write(b);
     }
 
     /**
@@ -142,10 +142,10 @@
      * @see MessageDigest#update(byte[], int, int)
      */
     public void write(byte[] b, int off, int len) throws IOException {
+        out.write(b, off, len);
         if (on) {
             digest.update(b, off, len);
         }
-        out.write(b, off, len);
     }
 
     /**
--- a/jdk/src/share/classes/java/text/DateFormatSymbols.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/text/DateFormatSymbols.java	Mon Jun 10 10:38:33 2013 +0100
@@ -59,7 +59,7 @@
  * <code>DateFormatSymbols</code> is a public class for encapsulating
  * localizable date-time formatting data, such as the names of the
  * months, the names of the days of the week, and the time zone data.
- * <code>DateFormat</code> and <code>SimpleDateFormat</code> both use
+ * <code>SimpleDateFormat</code> uses
  * <code>DateFormatSymbols</code> to encapsulate this information.
  *
  * <p>
--- a/jdk/src/share/classes/java/text/DigitList.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/text/DigitList.java	Mon Jun 10 10:38:33 2013 +0100
@@ -271,7 +271,7 @@
      * @param maximumFractionDigits The most fractional digits which should
      * be converted.
      */
-    public final void set(boolean isNegative, double source, int maximumFractionDigits) {
+    final void set(boolean isNegative, double source, int maximumFractionDigits) {
         set(isNegative, source, maximumFractionDigits, true);
     }
 
@@ -288,10 +288,11 @@
      */
     final void set(boolean isNegative, double source, int maximumDigits, boolean fixedPoint) {
 
-        FloatingDecimal fd = new FloatingDecimal(source);
-        boolean hasBeenRoundedUp = fd.digitsRoundedUp();
-        boolean allDecimalDigits = fd.decimalDigitsExact();
-        String digitsString = fd.toJavaFormatString();
+        FloatingDecimal.BinaryToASCIIConverter fdConverter  = FloatingDecimal.getBinaryToASCIIConverter(source);
+        boolean hasBeenRoundedUp = fdConverter.digitsRoundedUp();
+        boolean allDecimalDigits = fdConverter.decimalDigitsExact();
+        assert !fdConverter.isExceptional();
+        String digitsString = fdConverter.toJavaFormatString();
 
         set(isNegative, digitsString,
             hasBeenRoundedUp, allDecimalDigits,
@@ -305,9 +306,9 @@
      * @param allDecimalDigits Boolean value indicating if the digits in s are
      * an exact decimal representation of the double that was passed.
      */
-    final void set(boolean isNegative, String s,
-                   boolean roundedUp, boolean allDecimalDigits,
-                   int maximumDigits, boolean fixedPoint) {
+    private void set(boolean isNegative, String s,
+                     boolean roundedUp, boolean allDecimalDigits,
+                     int maximumDigits, boolean fixedPoint) {
         this.isNegative = isNegative;
         int len = s.length();
         char[] source = getDataChars(len);
@@ -607,7 +608,7 @@
     /**
      * Utility routine to set the value of the digit list from a long
      */
-    public final void set(boolean isNegative, long source) {
+    final void set(boolean isNegative, long source) {
         set(isNegative, source, 0);
     }
 
@@ -620,7 +621,7 @@
      * If maximumDigits is lower than the number of significant digits
      * in source, the representation will be rounded.  Ignored if <= 0.
      */
-    public final void set(boolean isNegative, long source, int maximumDigits) {
+    final void set(boolean isNegative, long source, int maximumDigits) {
         this.isNegative = isNegative;
 
         // This method does not expect a negative number. However,
--- a/jdk/src/share/classes/java/text/SimpleDateFormat.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/text/SimpleDateFormat.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1845,6 +1845,8 @@
             }
             ++pos.index;
         }
+        // Remember the actual start index
+        int actualStart = pos.index;
 
       parsing:
         {
@@ -1924,9 +1926,9 @@
                 // we made adjustments to place the 2-digit year in the proper
                 // century, for parsed strings from "00" to "99".  Any other string
                 // is treated literally:  "2250", "-1", "1", "002".
-                if (count <= 2 && (pos.index - start) == 2
-                    && Character.isDigit(text.charAt(start))
-                    && Character.isDigit(text.charAt(start+1))) {
+                if (count <= 2 && (pos.index - actualStart) == 2
+                    && Character.isDigit(text.charAt(actualStart))
+                    && Character.isDigit(text.charAt(actualStart + 1))) {
                     // Assume for example that the defaultCenturyStart is 6/18/1903.
                     // This means that two-digit years will be forced into the range
                     // 6/18/1903 to 6/17/2003.  As a result, years 00, 01, and 02
--- a/jdk/src/share/classes/java/util/Arrays.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/Arrays.java	Mon Jun 10 10:38:33 2013 +0100
@@ -40,7 +40,6 @@
 import java.util.stream.LongStream;
 import java.util.stream.Stream;
 import java.util.stream.StreamSupport;
-import static java.util.ArraysParallelSortHelpers.*;
 
 /**
  * This class contains various methods for manipulating arrays (such as
@@ -70,17 +69,62 @@
 public class Arrays {
 
     /**
-     * The minimum array length below which the sorting algorithm will not
-     * further partition the sorting task.
+     * The minimum array length below which a parallel sorting
+     * algorithm will not further partition the sorting task. Using
+     * smaller sizes typically results in memory contention across
+     * tasks that makes parallel speedups unlikely.
      */
-    // reasonable default so that we don't overcreate tasks
-    private static final int MIN_ARRAY_SORT_GRAN = 256;
+    private static final int MIN_ARRAY_SORT_GRAN = 1 << 13;
 
     // Suppresses default constructor, ensuring non-instantiability.
     private Arrays() {}
 
+    /**
+     * A comparator that implements the natural ordering of a group of
+     * mutually comparable elements. May be used when a supplied
+     * comparator is null. To simplify code-sharing within underlying
+     * implementations, the compare method only declares type Object
+     * for its second argument.
+     *
+     * Arrays class implementor's note: It is an empirical matter
+     * whether ComparableTimSort offers any performance benefit over
+     * TimSort used with this comparator.  If not, you are better off
+     * deleting or bypassing ComparableTimSort.  There is currently no
+     * empirical case for separating them for parallel sorting, so all
+     * public Object parallelSort methods use the same comparator
+     * based implementation.
+     */
+    static final class NaturalOrder implements Comparator<Object> {
+        @SuppressWarnings("unchecked")
+        public int compare(Object first, Object second) {
+            return ((Comparable<Object>)first).compareTo(second);
+        }
+        static final NaturalOrder INSTANCE = new NaturalOrder();
+    }
+
+    /**
+     * Checks that {@code fromIndex} and {@code toIndex} are in
+     * the range and throws an exception if they aren't.
+     */
+    private static void rangeCheck(int arrayLength, int fromIndex, int toIndex) {
+        if (fromIndex > toIndex) {
+            throw new IllegalArgumentException(
+                    "fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");
+        }
+        if (fromIndex < 0) {
+            throw new ArrayIndexOutOfBoundsException(fromIndex);
+        }
+        if (toIndex > arrayLength) {
+            throw new ArrayIndexOutOfBoundsException(toIndex);
+        }
+    }
+
     /*
-     * Sorting of primitive type arrays.
+     * Sorting methods. Note that all public "sort" methods take the
+     * same form: Performing argument checks if necessary, and then
+     * expanding arguments into those required for the internal
+     * implementation methods residing in other package-private
+     * classes (except for legacyMergeSort, included in this class).
      */
 
     /**
@@ -95,7 +139,7 @@
      * @param a the array to be sorted
      */
     public static void sort(int[] a) {
-        DualPivotQuicksort.sort(a);
+        DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
     }
 
     /**
@@ -120,7 +164,7 @@
      */
     public static void sort(int[] a, int fromIndex, int toIndex) {
         rangeCheck(a.length, fromIndex, toIndex);
-        DualPivotQuicksort.sort(a, fromIndex, toIndex - 1);
+        DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
     }
 
     /**
@@ -135,7 +179,7 @@
      * @param a the array to be sorted
      */
     public static void sort(long[] a) {
-        DualPivotQuicksort.sort(a);
+        DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
     }
 
     /**
@@ -160,7 +204,7 @@
      */
     public static void sort(long[] a, int fromIndex, int toIndex) {
         rangeCheck(a.length, fromIndex, toIndex);
-        DualPivotQuicksort.sort(a, fromIndex, toIndex - 1);
+        DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
     }
 
     /**
@@ -175,7 +219,7 @@
      * @param a the array to be sorted
      */
     public static void sort(short[] a) {
-        DualPivotQuicksort.sort(a);
+        DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
     }
 
     /**
@@ -200,7 +244,7 @@
      */
     public static void sort(short[] a, int fromIndex, int toIndex) {
         rangeCheck(a.length, fromIndex, toIndex);
-        DualPivotQuicksort.sort(a, fromIndex, toIndex - 1);
+        DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
     }
 
     /**
@@ -215,7 +259,7 @@
      * @param a the array to be sorted
      */
     public static void sort(char[] a) {
-        DualPivotQuicksort.sort(a);
+        DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
     }
 
     /**
@@ -240,7 +284,7 @@
      */
     public static void sort(char[] a, int fromIndex, int toIndex) {
         rangeCheck(a.length, fromIndex, toIndex);
-        DualPivotQuicksort.sort(a, fromIndex, toIndex - 1);
+        DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
     }
 
     /**
@@ -255,7 +299,7 @@
      * @param a the array to be sorted
      */
     public static void sort(byte[] a) {
-        DualPivotQuicksort.sort(a);
+        DualPivotQuicksort.sort(a, 0, a.length - 1);
     }
 
     /**
@@ -303,7 +347,7 @@
      * @param a the array to be sorted
      */
     public static void sort(float[] a) {
-        DualPivotQuicksort.sort(a);
+        DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
     }
 
     /**
@@ -336,7 +380,7 @@
      */
     public static void sort(float[] a, int fromIndex, int toIndex) {
         rangeCheck(a.length, fromIndex, toIndex);
-        DualPivotQuicksort.sort(a, fromIndex, toIndex - 1);
+        DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
     }
 
     /**
@@ -359,7 +403,7 @@
      * @param a the array to be sorted
      */
     public static void sort(double[] a) {
-        DualPivotQuicksort.sort(a);
+        DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
     }
 
     /**
@@ -392,7 +436,742 @@
      */
     public static void sort(double[] a, int fromIndex, int toIndex) {
         rangeCheck(a.length, fromIndex, toIndex);
-        DualPivotQuicksort.sort(a, fromIndex, toIndex - 1);
+        DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(byte[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(byte[]) Arrays.sort} method. The algorithm requires a
+     * working space no greater than the size of the original array. The
+     * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
+     * execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(byte[] a) {
+        int n = a.length, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, 0, n - 1);
+        else
+            new ArraysParallelSortHelpers.FJByte.Sorter
+                (null, a, new byte[n], 0, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending numerical order.
+     * The range to be sorted extends from the index {@code fromIndex},
+     * inclusive, to the index {@code toIndex}, exclusive. If
+     * {@code fromIndex == toIndex}, the range to be sorted is empty.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(byte[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(byte[]) Arrays.sort} method. The algorithm requires a working
+     * space no greater than the size of the specified range of the original
+     * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(byte[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        int n = toIndex - fromIndex, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, fromIndex, toIndex - 1);
+        else
+            new ArraysParallelSortHelpers.FJByte.Sorter
+                (null, a, new byte[n], fromIndex, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(char[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(char[]) Arrays.sort} method. The algorithm requires a
+     * working space no greater than the size of the original array. The
+     * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
+     * execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(char[] a) {
+        int n = a.length, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJChar.Sorter
+                (null, a, new char[n], 0, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending numerical order.
+     * The range to be sorted extends from the index {@code fromIndex},
+     * inclusive, to the index {@code toIndex}, exclusive. If
+     * {@code fromIndex == toIndex}, the range to be sorted is empty.
+     *
+      @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(char[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(char[]) Arrays.sort} method. The algorithm requires a working
+     * space no greater than the size of the specified range of the original
+     * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(char[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        int n = toIndex - fromIndex, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJChar.Sorter
+                (null, a, new char[n], fromIndex, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(short[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(short[]) Arrays.sort} method. The algorithm requires a
+     * working space no greater than the size of the original array. The
+     * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
+     * execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(short[] a) {
+        int n = a.length, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJShort.Sorter
+                (null, a, new short[n], 0, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending numerical order.
+     * The range to be sorted extends from the index {@code fromIndex},
+     * inclusive, to the index {@code toIndex}, exclusive. If
+     * {@code fromIndex == toIndex}, the range to be sorted is empty.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(short[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(short[]) Arrays.sort} method. The algorithm requires a working
+     * space no greater than the size of the specified range of the original
+     * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(short[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        int n = toIndex - fromIndex, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJShort.Sorter
+                (null, a, new short[n], fromIndex, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(int[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(int[]) Arrays.sort} method. The algorithm requires a
+     * working space no greater than the size of the original array. The
+     * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
+     * execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(int[] a) {
+        int n = a.length, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJInt.Sorter
+                (null, a, new int[n], 0, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending numerical order.
+     * The range to be sorted extends from the index {@code fromIndex},
+     * inclusive, to the index {@code toIndex}, exclusive. If
+     * {@code fromIndex == toIndex}, the range to be sorted is empty.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(int[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(int[]) Arrays.sort} method. The algorithm requires a working
+     * space no greater than the size of the specified range of the original
+     * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(int[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        int n = toIndex - fromIndex, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJInt.Sorter
+                (null, a, new int[n], fromIndex, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(long[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(long[]) Arrays.sort} method. The algorithm requires a
+     * working space no greater than the size of the original array. The
+     * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
+     * execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(long[] a) {
+        int n = a.length, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJLong.Sorter
+                (null, a, new long[n], 0, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending numerical order.
+     * The range to be sorted extends from the index {@code fromIndex},
+     * inclusive, to the index {@code toIndex}, exclusive. If
+     * {@code fromIndex == toIndex}, the range to be sorted is empty.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(long[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(long[]) Arrays.sort} method. The algorithm requires a working
+     * space no greater than the size of the specified range of the original
+     * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(long[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        int n = toIndex - fromIndex, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJLong.Sorter
+                (null, a, new long[n], fromIndex, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * <p>The {@code <} relation does not provide a total order on all float
+     * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN}
+     * value compares neither less than, greater than, nor equal to any value,
+     * even itself. This method uses the total order imposed by the method
+     * {@link Float#compareTo}: {@code -0.0f} is treated as less than value
+     * {@code 0.0f} and {@code Float.NaN} is considered greater than any
+     * other value and all {@code Float.NaN} values are considered equal.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(float[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(float[]) Arrays.sort} method. The algorithm requires a
+     * working space no greater than the size of the original array. The
+     * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
+     * execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(float[] a) {
+        int n = a.length, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJFloat.Sorter
+                (null, a, new float[n], 0, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending numerical order.
+     * The range to be sorted extends from the index {@code fromIndex},
+     * inclusive, to the index {@code toIndex}, exclusive. If
+     * {@code fromIndex == toIndex}, the range to be sorted is empty.
+     *
+     * <p>The {@code <} relation does not provide a total order on all float
+     * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN}
+     * value compares neither less than, greater than, nor equal to any value,
+     * even itself. This method uses the total order imposed by the method
+     * {@link Float#compareTo}: {@code -0.0f} is treated as less than value
+     * {@code 0.0f} and {@code Float.NaN} is considered greater than any
+     * other value and all {@code Float.NaN} values are considered equal.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(float[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(float[]) Arrays.sort} method. The algorithm requires a working
+     * space no greater than the size of the specified range of the original
+     * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(float[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        int n = toIndex - fromIndex, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJFloat.Sorter
+                (null, a, new float[n], fromIndex, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * <p>The {@code <} relation does not provide a total order on all double
+     * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN}
+     * value compares neither less than, greater than, nor equal to any value,
+     * even itself. This method uses the total order imposed by the method
+     * {@link Double#compareTo}: {@code -0.0d} is treated as less than value
+     * {@code 0.0d} and {@code Double.NaN} is considered greater than any
+     * other value and all {@code Double.NaN} values are considered equal.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(double[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(double[]) Arrays.sort} method. The algorithm requires a
+     * working space no greater than the size of the original array. The
+     * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
+     * execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(double[] a) {
+        int n = a.length, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJDouble.Sorter
+                (null, a, new double[n], 0, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending numerical order.
+     * The range to be sorted extends from the index {@code fromIndex},
+     * inclusive, to the index {@code toIndex}, exclusive. If
+     * {@code fromIndex == toIndex}, the range to be sorted is empty.
+     *
+     * <p>The {@code <} relation does not provide a total order on all double
+     * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN}
+     * value compares neither less than, greater than, nor equal to any value,
+     * even itself. This method uses the total order imposed by the method
+     * {@link Double#compareTo}: {@code -0.0d} is treated as less than value
+     * {@code 0.0d} and {@code Double.NaN} is considered greater than any
+     * other value and all {@code Double.NaN} values are considered equal.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(double[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(double[]) Arrays.sort} method. The algorithm requires a working
+     * space no greater than the size of the specified range of the original
+     * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(double[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        int n = toIndex - fromIndex, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJDouble.Sorter
+                (null, a, new double[n], fromIndex, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified array of objects into ascending order, according
+     * to the {@linkplain Comparable natural ordering} of its elements.
+     * All elements in the array must implement the {@link Comparable}
+     * interface.  Furthermore, all elements in the array must be
+     * <i>mutually comparable</i> (that is, {@code e1.compareTo(e2)} must
+     * not throw a {@code ClassCastException} for any elements {@code e1}
+     * and {@code e2} in the array).
+     *
+     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
+     * not be reordered as a result of the sort.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(Object[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(Object[]) Arrays.sort} method. The algorithm requires a
+     * working space no greater than the size of the original array. The
+     * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
+     * execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     *
+     * @throws ClassCastException if the array contains elements that are not
+     *         <i>mutually comparable</i> (for example, strings and integers)
+     * @throws IllegalArgumentException (optional) if the natural
+     *         ordering of the array elements is found to violate the
+     *         {@link Comparable} contract
+     *
+     * @since 1.8
+     */
+    @SuppressWarnings("unchecked")
+    public static <T extends Comparable<? super T>> void parallelSort(T[] a) {
+        int n = a.length, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            TimSort.sort(a, 0, n, NaturalOrder.INSTANCE, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJObject.Sorter<T>
+                (null, a,
+                 (T[])Array.newInstance(a.getClass().getComponentType(), n),
+                 0, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g, NaturalOrder.INSTANCE).invoke();
+    }
+
+    /**
+     * Sorts the specified range of the specified array of objects into
+     * ascending order, according to the
+     * {@linkplain Comparable natural ordering} of its
+     * elements.  The range to be sorted extends from index
+     * {@code fromIndex}, inclusive, to index {@code toIndex}, exclusive.
+     * (If {@code fromIndex==toIndex}, the range to be sorted is empty.)  All
+     * elements in this range must implement the {@link Comparable}
+     * interface.  Furthermore, all elements in this range must be <i>mutually
+     * comparable</i> (that is, {@code e1.compareTo(e2)} must not throw a
+     * {@code ClassCastException} for any elements {@code e1} and
+     * {@code e2} in the array).
+     *
+     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
+     * not be reordered as a result of the sort.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(Object[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(Object[]) Arrays.sort} method. The algorithm requires a working
+     * space no greater than the size of the specified range of the original
+     * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        sorted
+     * @param toIndex the index of the last element (exclusive) to be sorted
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex} or
+     *         (optional) if the natural ordering of the array elements is
+     *         found to violate the {@link Comparable} contract
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
+     *         {@code toIndex > a.length}
+     * @throws ClassCastException if the array contains elements that are
+     *         not <i>mutually comparable</i> (for example, strings and
+     *         integers).
+     *
+     * @since 1.8
+     */
+    @SuppressWarnings("unchecked")
+    public static <T extends Comparable<? super T>>
+    void parallelSort(T[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        int n = toIndex - fromIndex, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            TimSort.sort(a, fromIndex, toIndex, NaturalOrder.INSTANCE, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJObject.Sorter<T>
+                (null, a,
+                 (T[])Array.newInstance(a.getClass().getComponentType(), n),
+                 fromIndex, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g, NaturalOrder.INSTANCE).invoke();
+    }
+
+    /**
+     * Sorts the specified array of objects according to the order induced by
+     * the specified comparator.  All elements in the array must be
+     * <i>mutually comparable</i> by the specified comparator (that is,
+     * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException}
+     * for any elements {@code e1} and {@code e2} in the array).
+     *
+     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
+     * not be reordered as a result of the sort.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(Object[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(Object[]) Arrays.sort} method. The algorithm requires a
+     * working space no greater than the size of the original array. The
+     * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
+     * execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     * @param cmp the comparator to determine the order of the array.  A
+     *        {@code null} value indicates that the elements'
+     *        {@linkplain Comparable natural ordering} should be used.
+     * @throws ClassCastException if the array contains elements that are
+     *         not <i>mutually comparable</i> using the specified comparator
+     * @throws IllegalArgumentException (optional) if the comparator is
+     *         found to violate the {@link java.util.Comparator} contract
+     *
+     * @since 1.8
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> void parallelSort(T[] a, Comparator<? super T> cmp) {
+        if (cmp == null)
+            cmp = NaturalOrder.INSTANCE;
+        int n = a.length, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            TimSort.sort(a, 0, n, cmp, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJObject.Sorter<T>
+                (null, a,
+                 (T[])Array.newInstance(a.getClass().getComponentType(), n),
+                 0, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g, cmp).invoke();
+    }
+
+    /**
+     * Sorts the specified range of the specified array of objects according
+     * to the order induced by the specified comparator.  The range to be
+     * sorted extends from index {@code fromIndex}, inclusive, to index
+     * {@code toIndex}, exclusive.  (If {@code fromIndex==toIndex}, the
+     * range to be sorted is empty.)  All elements in the range must be
+     * <i>mutually comparable</i> by the specified comparator (that is,
+     * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException}
+     * for any elements {@code e1} and {@code e2} in the range).
+     *
+     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
+     * not be reordered as a result of the sort.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(Object[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(Object[]) Arrays.sort} method. The algorithm requires a working
+     * space no greater than the size of the specified range of the original
+     * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        sorted
+     * @param toIndex the index of the last element (exclusive) to be sorted
+     * @param cmp the comparator to determine the order of the array.  A
+     *        {@code null} value indicates that the elements'
+     *        {@linkplain Comparable natural ordering} should be used.
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex} or
+     *         (optional) if the natural ordering of the array elements is
+     *         found to violate the {@link Comparable} contract
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
+     *         {@code toIndex > a.length}
+     * @throws ClassCastException if the array contains elements that are
+     *         not <i>mutually comparable</i> (for example, strings and
+     *         integers).
+     *
+     * @since 1.8
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> void parallelSort(T[] a, int fromIndex, int toIndex,
+                                        Comparator<? super T> cmp) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        if (cmp == null)
+            cmp = NaturalOrder.INSTANCE;
+        int n = toIndex - fromIndex, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            TimSort.sort(a, fromIndex, toIndex, cmp, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJObject.Sorter<T>
+                (null, a,
+                 (T[])Array.newInstance(a.getClass().getComponentType(), n),
+                 fromIndex, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g, cmp).invoke();
     }
 
     /*
@@ -412,39 +1191,6 @@
                     "java.util.Arrays.useLegacyMergeSort")).booleanValue();
     }
 
-    /*
-     * If this platform has an optimizing VM, check whether ComparableTimSort
-     * offers any performance benefit over TimSort in conjunction with a
-     * comparator that returns:
-     *    {@code ((Comparable)first).compareTo(Second)}.
-     * If not, you are better off deleting ComparableTimSort to
-     * eliminate the code duplication.  In other words, the commented
-     * out code below is the preferable implementation for sorting
-     * arrays of Comparables if it offers sufficient performance.
-     */
-
-//    /**
-//     * A comparator that implements the natural ordering of a group of
-//     * mutually comparable elements.  Using this comparator saves us
-//     * from duplicating most of the code in this file (one version for
-//     * Comparables, one for explicit Comparators).
-//     */
-//    private static final Comparator<Object> NATURAL_ORDER =
-//            new Comparator<Object>() {
-//        @SuppressWarnings("unchecked")
-//        public int compare(Object first, Object second) {
-//            return ((Comparable<Object>)first).compareTo(second);
-//        }
-//    };
-//
-//    public static void sort(Object[] a) {
-//        sort(a, 0, a.length, NATURAL_ORDER);
-//    }
-//
-//    public static void sort(Object[] a, int fromIndex, int toIndex) {
-//        sort(a, fromIndex, toIndex, NATURAL_ORDER);
-//    }
-
     /**
      * Sorts the specified array of objects into ascending order, according
      * to the {@linkplain Comparable natural ordering} of its elements.
@@ -491,7 +1237,7 @@
         if (LegacyMergeSort.userRequested)
             legacyMergeSort(a);
         else
-            ComparableTimSort.sort(a);
+            ComparableTimSort.sort(a, 0, a.length, null, 0, 0);
     }
 
     /** To be removed in a future release. */
@@ -553,16 +1299,16 @@
      *         integers).
      */
     public static void sort(Object[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
         if (LegacyMergeSort.userRequested)
             legacyMergeSort(a, fromIndex, toIndex);
         else
-            ComparableTimSort.sort(a, fromIndex, toIndex);
+            ComparableTimSort.sort(a, fromIndex, toIndex, null, 0, 0);
     }
 
     /** To be removed in a future release. */
     private static void legacyMergeSort(Object[] a,
                                         int fromIndex, int toIndex) {
-        rangeCheck(a.length, fromIndex, toIndex);
         Object[] aux = copyOfRange(a, fromIndex, toIndex);
         mergeSort(aux, a, fromIndex, toIndex, -fromIndex);
     }
@@ -676,10 +1422,12 @@
      *         found to violate the {@link Comparator} contract
      */
     public static <T> void sort(T[] a, Comparator<? super T> c) {
+        if (c == null)
+            c = NaturalOrder.INSTANCE;
         if (LegacyMergeSort.userRequested)
             legacyMergeSort(a, c);
         else
-            TimSort.sort(a, c);
+            TimSort.sort(a, 0, a.length, c, null, 0, 0);
     }
 
     /** To be removed in a future release. */
@@ -744,16 +1492,18 @@
      */
     public static <T> void sort(T[] a, int fromIndex, int toIndex,
                                 Comparator<? super T> c) {
+        if (c == null)
+            c = NaturalOrder.INSTANCE;
+        rangeCheck(a.length, fromIndex, toIndex);
         if (LegacyMergeSort.userRequested)
             legacyMergeSort(a, fromIndex, toIndex, c);
         else
-            TimSort.sort(a, fromIndex, toIndex, c);
+            TimSort.sort(a, fromIndex, toIndex, c, null, 0, 0);
     }
 
     /** To be removed in a future release. */
     private static <T> void legacyMergeSort(T[] a, int fromIndex, int toIndex,
                                             Comparator<? super T> c) {
-        rangeCheck(a.length, fromIndex, toIndex);
         T[] aux = copyOfRange(a, fromIndex, toIndex);
         if (c==null)
             mergeSort(aux, a, fromIndex, toIndex, -fromIndex);
@@ -809,630 +1559,6 @@
         }
     }
 
-    /*
-     * Parallel sorting of primitive type arrays.
-     */
-
-    /**
-     * Sorts the specified array into ascending numerical order.
-     *
-     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
-     * that breaks the array into sub-arrays that are themselves sorted and then
-     * merged. When the sub-array length reaches a minimum granularity, the
-     * sub-array is sorted using the appropriate {@link Arrays#sort(byte[])
-     * Arrays.sort} method. The algorithm requires a working space equal to the
-     * size of the original array. The {@link
-     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
-     * used to execute any parallel tasks.
-     *
-     * @param a the array to be sorted
-     *
-     * @since 1.8
-     */
-    public static void parallelSort(byte[] a) {
-        parallelSort(a, 0, a.length);
-    }
-
-    /**
-     * Sorts the specified range of the array into ascending order. The range
-     * to be sorted extends from the index {@code fromIndex}, inclusive, to
-     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
-     * the range to be sorted is empty.
-     *
-     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
-     * that breaks the array into sub-arrays that are themselves sorted and then
-     * merged. When the sub-array length reaches a minimum granularity, the
-     * sub-array is sorted using the appropriate {@link Arrays#sort(byte[])
-     * Arrays.sort} method. The algorithm requires a working space equal to the
-     * size of the original array. The {@link
-     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
-     * used to execute any parallel tasks.
-     *
-     * @param a the array to be sorted
-     * @param fromIndex the index of the first element, inclusive, to be sorted
-     * @param toIndex the index of the last element, exclusive, to be sorted
-     *
-     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
-     * @throws ArrayIndexOutOfBoundsException
-     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
-     *
-     * @since 1.8
-     */
-    public static void parallelSort(byte[] a, int fromIndex, int toIndex) {
-        rangeCheck(a.length, fromIndex, toIndex);
-        int nelements = toIndex - fromIndex;
-        int gran = getSplitThreshold(nelements);
-        FJByte.Sorter task = new FJByte.Sorter(a, new byte[a.length], fromIndex,
-                                               nelements, gran);
-        task.invoke();
-    }
-
-    /**
-     * Sorts the specified array into ascending numerical order.
-     *
-     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
-     * that breaks the array into sub-arrays that are themselves sorted and then
-     * merged. When the sub-array length reaches a minimum granularity, the
-     * sub-array is sorted using the appropriate {@link Arrays#sort(char[])
-     * Arrays.sort} method. The algorithm requires a working space equal to the
-     * size of the original array. The {@link
-     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
-     * used to execute any parallel tasks.
-     *
-     * @param a the array to be sorted
-     *
-     * @since 1.8
-     */
-    public static void parallelSort(char[] a) {
-        parallelSort(a, 0, a.length);
-    }
-
-    /**
-     * Sorts the specified range of the array into ascending order. The range
-     * to be sorted extends from the index {@code fromIndex}, inclusive, to
-     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
-     * the range to be sorted is empty.
-     *
-     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
-     * that breaks the array into sub-arrays that are themselves sorted and then
-     * merged. When the sub-array length reaches a minimum granularity, the
-     * sub-array is sorted using the appropriate {@link Arrays#sort(char[])
-     * Arrays.sort} method. The algorithm requires a working space equal to the
-     * size of the original array. The {@link
-     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
-     * used to execute any parallel tasks.
-     *
-     * @param a the array to be sorted
-     * @param fromIndex the index of the first element, inclusive, to be sorted
-     * @param toIndex the index of the last element, exclusive, to be sorted
-     *
-     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
-     * @throws ArrayIndexOutOfBoundsException
-     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
-     *
-     * @since 1.8
-     */
-    public static void parallelSort(char[] a, int fromIndex, int toIndex) {
-        rangeCheck(a.length, fromIndex, toIndex);
-        int nelements = toIndex - fromIndex;
-        int gran = getSplitThreshold(nelements);
-        FJChar.Sorter task = new FJChar.Sorter(a, new char[a.length], fromIndex,
-                                               nelements, gran);
-        task.invoke();
-    }
-
-    /**
-     * Sorts the specified array into ascending numerical order.
-     *
-     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
-     * that breaks the array into sub-arrays that are themselves sorted and then
-     * merged. When the sub-array length reaches a minimum granularity, the
-     * sub-array is sorted using the appropriate {@link Arrays#sort(short[])
-     * Arrays.sort} method. The algorithm requires a working space equal to the
-     * size of the original array. The {@link
-     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
-     * used to execute any parallel tasks.
-     *
-     * @param a the array to be sorted
-     *
-     * @since 1.8
-     */
-    public static void parallelSort(short[] a) {
-        parallelSort(a, 0, a.length);
-    }
-
-    /**
-     * Sorts the specified range of the array into ascending order. The range
-     * to be sorted extends from the index {@code fromIndex}, inclusive, to
-     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
-     * the range to be sorted is empty.
-     *
-     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
-     * that breaks the array into sub-arrays that are themselves sorted and then
-     * merged. When the sub-array length reaches a minimum granularity, the
-     * sub-array is sorted using the appropriate {@link Arrays#sort(short[])
-     * Arrays.sort} method. The algorithm requires a working space equal to the
-     * size of the original array. The {@link
-     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
-     * used to execute any parallel tasks.
-     *
-     * @param a the array to be sorted
-     * @param fromIndex the index of the first element, inclusive, to be sorted
-     * @param toIndex the index of the last element, exclusive, to be sorted
-     *
-     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
-     * @throws ArrayIndexOutOfBoundsException
-     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
-     *
-     * @since 1.8
-     */
-    public static void parallelSort(short[] a, int fromIndex, int toIndex) {
-        rangeCheck(a.length, fromIndex, toIndex);
-        int nelements = toIndex - fromIndex;
-        int gran = getSplitThreshold(nelements);
-        FJShort.Sorter task = new FJShort.Sorter(a, new short[a.length], fromIndex,
-                                                 nelements, gran);
-        task.invoke();
-    }
-
-    /**
-     * Sorts the specified array into ascending numerical order.
-     *
-     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
-     * that breaks the array into sub-arrays that are themselves sorted and then
-     * merged. When the sub-array length reaches a minimum granularity, the
-     * sub-array is sorted using the appropriate {@link Arrays#sort(int[])
-     * Arrays.sort} method. The algorithm requires a working space equal to the
-     * size of the original array. The {@link
-     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
-     * used to execute any parallel tasks.
-     *
-     * @param a the array to be sorted
-     *
-     * @since 1.8
-     */
-    public static void parallelSort(int[] a) {
-        parallelSort(a, 0, a.length);
-    }
-
-    /**
-     * Sorts the specified range of the array into ascending order. The range
-     * to be sorted extends from the index {@code fromIndex}, inclusive, to
-     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
-     * the range to be sorted is empty.
-     *
-     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
-     * that breaks the array into sub-arrays that are themselves sorted and then
-     * merged. When the sub-array length reaches a minimum granularity, the
-     * sub-array is sorted using the appropriate {@link Arrays#sort(int[])
-     * Arrays.sort} method. The algorithm requires a working space equal to the
-     * size of the original array. The {@link
-     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
-     * used to execute any parallel tasks.
-     *
-     * @param a the array to be sorted
-     * @param fromIndex the index of the first element, inclusive, to be sorted
-     * @param toIndex the index of the last element, exclusive, to be sorted
-     *
-     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
-     * @throws ArrayIndexOutOfBoundsException
-     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
-     *
-     * @since 1.8
-     */
-    public static void parallelSort(int[] a, int fromIndex, int toIndex) {
-        rangeCheck(a.length, fromIndex, toIndex);
-        int nelements = toIndex - fromIndex;
-        int gran = getSplitThreshold(nelements);
-        FJInt.Sorter task = new FJInt.Sorter(a, new int[a.length], fromIndex,
-                                             nelements, gran);
-        task.invoke();
-    }
-
-    /**
-     * Sorts the specified array into ascending numerical order.
-     *
-     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
-     * that breaks the array into sub-arrays that are themselves sorted and then
-     * merged. When the sub-array length reaches a minimum granularity, the
-     * sub-array is sorted using the appropriate {@link Arrays#sort(long[])
-     * Arrays.sort} method. The algorithm requires a working space equal to the
-     * size of the original array. The {@link
-     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
-     * used to execute any parallel tasks.
-     *
-     * @param a the array to be sorted
-     *
-     * @since 1.8
-     */
-    public static void parallelSort(long[] a) {
-        parallelSort(a, 0, a.length);
-    }
-
-    /**
-     * Sorts the specified range of the array into ascending order. The range
-     * to be sorted extends from the index {@code fromIndex}, inclusive, to
-     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
-     * the range to be sorted is empty.
-     *
-     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
-     * that breaks the array into sub-arrays that are themselves sorted and then
-     * merged. When the sub-array length reaches a minimum granularity, the
-     * sub-array is sorted using the appropriate {@link Arrays#sort(long[])
-     * Arrays.sort} method. The algorithm requires a working space equal to the
-     * size of the original array. The {@link
-     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
-     * used to execute any parallel tasks.
-     *
-     * @param a the array to be sorted
-     * @param fromIndex the index of the first element, inclusive, to be sorted
-     * @param toIndex the index of the last element, exclusive, to be sorted
-     *
-     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
-     * @throws ArrayIndexOutOfBoundsException
-     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
-     *
-     * @since 1.8
-     */
-    public static void parallelSort(long[] a, int fromIndex, int toIndex) {
-        rangeCheck(a.length, fromIndex, toIndex);
-        int nelements = toIndex - fromIndex;
-        int gran = getSplitThreshold(nelements);
-        FJLong.Sorter task = new FJLong.Sorter(a, new long[a.length], fromIndex,
-                                               nelements, gran);
-        task.invoke();
-    }
-
-    /**
-     * Sorts the specified array into ascending numerical order.
-     *
-     * <p>The {@code <} relation does not provide a total order on all float
-     * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN}
-     * value compares neither less than, greater than, nor equal to any value,
-     * even itself. This method uses the total order imposed by the method
-     * {@link Float#compareTo}: {@code -0.0f} is treated as less than value
-     * {@code 0.0f} and {@code Float.NaN} is considered greater than any
-     * other value and all {@code Float.NaN} values are considered equal.
-     *
-     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
-     * that breaks the array into sub-arrays that are themselves sorted and then
-     * merged. When the sub-array length reaches a minimum granularity, the
-     * sub-array is sorted using the appropriate {@link Arrays#sort(float[])
-     * Arrays.sort} method. The algorithm requires a working space equal to the
-     * size of the original array. The {@link
-     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
-     * used to execute any parallel tasks.
-     *
-     * @param a the array to be sorted
-     *
-     * @since 1.8
-     */
-    public static void parallelSort(float[] a) {
-        parallelSort(a, 0, a.length);
-    }
-
-    /**
-     * Sorts the specified range of the array into ascending order. The range
-     * to be sorted extends from the index {@code fromIndex}, inclusive, to
-     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
-     * the range to be sorted is empty.
-     *
-     * <p>The {@code <} relation does not provide a total order on all float
-     * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN}
-     * value compares neither less than, greater than, nor equal to any value,
-     * even itself. This method uses the total order imposed by the method
-     * {@link Float#compareTo}: {@code -0.0f} is treated as less than value
-     * {@code 0.0f} and {@code Float.NaN} is considered greater than any
-     * other value and all {@code Float.NaN} values are considered equal.
-     *
-     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
-     * that breaks the array into sub-arrays that are themselves sorted and then
-     * merged. When the sub-array length reaches a minimum granularity, the
-     * sub-array is sorted using the appropriate {@link Arrays#sort(float[])
-     * Arrays.sort} method. The algorithm requires a working space equal to the
-     * size of the original array. The {@link
-     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
-     * used to execute any parallel tasks.
-     *
-     * @param a the array to be sorted
-     * @param fromIndex the index of the first element, inclusive, to be sorted
-     * @param toIndex the index of the last element, exclusive, to be sorted
-     *
-     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
-     * @throws ArrayIndexOutOfBoundsException
-     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
-     *
-     * @since 1.8
-     */
-    public static void parallelSort(float[] a, int fromIndex, int toIndex) {
-        rangeCheck(a.length, fromIndex, toIndex);
-        int nelements = toIndex - fromIndex;
-        int gran = getSplitThreshold(nelements);
-        FJFloat.Sorter task = new FJFloat.Sorter(a, new float[a.length], fromIndex,
-                                                 nelements, gran);
-        task.invoke();
-    }
-
-    /**
-     * Sorts the specified array into ascending numerical order.
-     *
-     * <p>The {@code <} relation does not provide a total order on all double
-     * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN}
-     * value compares neither less than, greater than, nor equal to any value,
-     * even itself. This method uses the total order imposed by the method
-     * {@link Double#compareTo}: {@code -0.0d} is treated as less than value
-     * {@code 0.0d} and {@code Double.NaN} is considered greater than any
-     * other value and all {@code Double.NaN} values are considered equal.
-     *
-     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
-     * that breaks the array into sub-arrays that are themselves sorted and then
-     * merged. When the sub-array length reaches a minimum granularity, the
-     * sub-array is sorted using the appropriate {@link Arrays#sort(double[])
-     * Arrays.sort} method. The algorithm requires a working space equal to the
-     * size of the original array. The {@link
-     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
-     * used to execute any parallel tasks.
-     *
-     * @param a the array to be sorted
-     *
-     * @since 1.8
-     */
-    public static void parallelSort(double[] a) {
-        parallelSort(a, 0, a.length);
-    }
-
-    /**
-     * Sorts the specified range of the array into ascending order. The range
-     * to be sorted extends from the index {@code fromIndex}, inclusive, to
-     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
-     * the range to be sorted is empty.
-     *
-     * <p>The {@code <} relation does not provide a total order on all double
-     * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN}
-     * value compares neither less than, greater than, nor equal to any value,
-     * even itself. This method uses the total order imposed by the method
-     * {@link Double#compareTo}: {@code -0.0d} is treated as less than value
-     * {@code 0.0d} and {@code Double.NaN} is considered greater than any
-     * other value and all {@code Double.NaN} values are considered equal.
-     *
-     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
-     * that breaks the array into sub-arrays that are themselves sorted and then
-     * merged. When the sub-array length reaches a minimum granularity, the
-     * sub-array is sorted using the appropriate {@link Arrays#sort(double[])
-     * Arrays.sort} method. The algorithm requires a working space equal to the
-     * size of the original array. The {@link
-     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
-     * used to execute any parallel tasks.
-     *
-     * @param a the array to be sorted
-     * @param fromIndex the index of the first element, inclusive, to be sorted
-     * @param toIndex the index of the last element, exclusive, to be sorted
-     *
-     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
-     * @throws ArrayIndexOutOfBoundsException
-     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
-     *
-     * @since 1.8
-     */
-    public static void parallelSort(double[] a, int fromIndex, int toIndex) {
-        rangeCheck(a.length, fromIndex, toIndex);
-        int nelements = toIndex - fromIndex;
-        int gran = getSplitThreshold(nelements);
-        FJDouble.Sorter task = new FJDouble.Sorter(a, new double[a.length],
-                                                   fromIndex, nelements, gran);
-        task.invoke();
-    }
-
-    /*
-     * Parallel sorting of complex type arrays.
-     */
-
-    /**
-     * Sorts the specified array of objects into ascending order, according
-     * to the {@linkplain Comparable natural ordering} of its elements.
-     * All elements in the array must implement the {@link Comparable}
-     * interface.  Furthermore, all elements in the array must be
-     * <i>mutually comparable</i> (that is, {@code e1.compareTo(e2)} must
-     * not throw a {@code ClassCastException} for any elements {@code e1}
-     * and {@code e2} in the array).
-     *
-     * <p>This sort is not guaranteed to be <i>stable</i>:  equal elements
-     * may be reordered as a result of the sort.
-     *
-     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
-     * that breaks the array into sub-arrays that are themselves sorted and then
-     * merged. When the sub-array length reaches a minimum granularity, the
-     * sub-array is sorted using the appropriate {@link Arrays#sort(Object[])
-     * Arrays.sort} method. The algorithm requires a working space equal to the
-     * size of the original array. The {@link
-     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
-     * used to execute any parallel tasks.
-     *
-     * @param a the array to be sorted
-     *
-     * @throws ClassCastException if the array contains elements that are not
-     *         <i>mutually comparable</i> (for example, strings and integers)
-     * @throws IllegalArgumentException (optional) if the natural
-     *         ordering of the array elements is found to violate the
-     *         {@link Comparable} contract
-     *
-     * @since 1.8
-     */
-    public static <T extends Comparable<? super T>> void parallelSort(T[] a) {
-        parallelSort(a, 0, a.length);
-    }
-
-    /**
-     * Sorts the specified range of the specified array of objects into
-     * ascending order, according to the
-     * {@linkplain Comparable natural ordering} of its
-     * elements.  The range to be sorted extends from index
-     * {@code fromIndex}, inclusive, to index {@code toIndex}, exclusive.
-     * (If {@code fromIndex==toIndex}, the range to be sorted is empty.)  All
-     * elements in this range must implement the {@link Comparable}
-     * interface.  Furthermore, all elements in this range must be <i>mutually
-     * comparable</i> (that is, {@code e1.compareTo(e2)} must not throw a
-     * {@code ClassCastException} for any elements {@code e1} and
-     * {@code e2} in the array).
-     *
-     * <p>This sort is not guaranteed to be <i>stable</i>:  equal elements
-     * may be reordered as a result of the sort.
-     *
-     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
-     * that breaks the array into sub-arrays that are themselves sorted and then
-     * merged. When the sub-array length reaches a minimum granularity, the
-     * sub-array is sorted using the appropriate {@link Arrays#sort(Object[])
-     * Arrays.sort} method. The algorithm requires a working space equal to the
-     * size of the original array. The {@link
-     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
-     * used to execute any parallel tasks.
-     *
-     * @param a the array to be sorted
-     * @param fromIndex the index of the first element (inclusive) to be
-     *        sorted
-     * @param toIndex the index of the last element (exclusive) to be sorted
-     * @throws IllegalArgumentException if {@code fromIndex > toIndex} or
-     *         (optional) if the natural ordering of the array elements is
-     *         found to violate the {@link Comparable} contract
-     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
-     *         {@code toIndex > a.length}
-     * @throws ClassCastException if the array contains elements that are
-     *         not <i>mutually comparable</i> (for example, strings and
-     *         integers).
-     *
-     * @since 1.8
-     */
-    public static <T extends Comparable<? super T>>
-            void parallelSort(T[] a, int fromIndex, int toIndex) {
-        rangeCheck(a.length, fromIndex, toIndex);
-        int nelements = toIndex - fromIndex;
-        Class<?> tc = a.getClass().getComponentType();
-        @SuppressWarnings("unchecked")
-        T[] workspace = (T[])Array.newInstance(tc, a.length);
-        int gran = getSplitThreshold(nelements);
-        FJComparable.Sorter<T> task = new FJComparable.Sorter<>(a, workspace,
-                                                                fromIndex,
-                                                                nelements, gran);
-        task.invoke();
-    }
-
-    /**
-     * Sorts the specified array of objects according to the order induced by
-     * the specified comparator.  All elements in the array must be
-     * <i>mutually comparable</i> by the specified comparator (that is,
-     * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException}
-     * for any elements {@code e1} and {@code e2} in the array).
-     *
-     * <p>This sort is not guaranteed to be <i>stable</i>:  equal elements
-     * may be reordered as a result of the sort.
-     *
-     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
-     * that breaks the array into sub-arrays that are themselves sorted and then
-     * merged. When the sub-array length reaches a minimum granularity, the
-     * sub-array is sorted using the appropriate {@link Arrays#sort(Object[])
-     * Arrays.sort} method. The algorithm requires a working space equal to the
-     * size of the original array. The {@link
-     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
-     * used to execute any parallel tasks.
-     *
-     * @param a the array to be sorted
-     * @param c the comparator to determine the order of the array.  A
-     *        {@code null} value indicates that the elements'
-     *        {@linkplain Comparable natural ordering} should be used.
-     * @throws ClassCastException if the array contains elements that are
-     *         not <i>mutually comparable</i> using the specified comparator
-     * @throws IllegalArgumentException (optional) if the comparator is
-     *         found to violate the {@link java.util.Comparator} contract
-     *
-     * @since 1.8
-     */
-    public static <T> void parallelSort(T[] a, Comparator<? super T> c) {
-        parallelSort(a, 0, a.length, c);
-    }
-
-    /**
-     * Sorts the specified range of the specified array of objects according
-     * to the order induced by the specified comparator.  The range to be
-     * sorted extends from index {@code fromIndex}, inclusive, to index
-     * {@code toIndex}, exclusive.  (If {@code fromIndex==toIndex}, the
-     * range to be sorted is empty.)  All elements in the range must be
-     * <i>mutually comparable</i> by the specified comparator (that is,
-     * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException}
-     * for any elements {@code e1} and {@code e2} in the range).
-     *
-     * <p>This sort is not guaranteed to be <i>stable</i>:  equal elements
-     * may be reordered as a result of the sort.
-     *
-     * <p>Implementation note: The sorting algorithm is a parallel sort-merge
-     * that breaks the array into sub-arrays that are themselves sorted and then
-     * merged. When the sub-array length reaches a minimum granularity, the
-     * sub-array is sorted using the appropriate {@link Arrays#sort(Object[])
-     * Arrays.sort} method. The algorithm requires a working space equal to the
-     * size of the original array. The {@link
-     * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is
-     * used to execute any parallel tasks.
-     *
-     * @param a the array to be sorted
-     * @param fromIndex the index of the first element (inclusive) to be
-     *        sorted
-     * @param toIndex the index of the last element (exclusive) to be sorted
-     * @param c the comparator to determine the order of the array.  A
-     *        {@code null} value indicates that the elements'
-     *        {@linkplain Comparable natural ordering} should be used.
-     * @throws IllegalArgumentException if {@code fromIndex > toIndex} or
-     *         (optional) if the natural ordering of the array elements is
-     *         found to violate the {@link Comparable} contract
-     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
-     *         {@code toIndex > a.length}
-     * @throws ClassCastException if the array contains elements that are
-     *         not <i>mutually comparable</i> (for example, strings and
-     *         integers).
-     *
-     * @since 1.8
-     */
-    public static <T> void parallelSort(T[] a, int fromIndex, int toIndex,
-                                        Comparator<? super T> c) {
-        rangeCheck(a.length, fromIndex, toIndex);
-        int nelements = toIndex - fromIndex;
-        Class<?> tc = a.getClass().getComponentType();
-        @SuppressWarnings("unchecked")
-        T[] workspace = (T[])Array.newInstance(tc, a.length);
-        int gran = getSplitThreshold(nelements);
-        FJComparator.Sorter<T> task = new FJComparator.Sorter<>(a, workspace,
-                                                                fromIndex,
-                                                                nelements, gran, c);
-        task.invoke();
-    }
-
-    /**
-     * Returns the size threshold for splitting into subtasks.
-     * By default, uses about 8 times as many tasks as threads
-     *
-     * @param n number of elements in the array to be processed
-     */
-    private static int getSplitThreshold(int n) {
-        int p = java.util.concurrent.ForkJoinPool.getCommonPoolParallelism();
-        int t = (p > 1) ? (1 + n / (p << 3)) : n;
-        return t < MIN_ARRAY_SORT_GRAN ? MIN_ARRAY_SORT_GRAN : t;
-    }
-
-    /**
-     * Checks that {@code fromIndex} and {@code toIndex} are in
-     * the range and throws an appropriate exception, if they aren't.
-     */
-    private static void rangeCheck(int length, int fromIndex, int toIndex) {
-        if (fromIndex > toIndex) {
-            throw new IllegalArgumentException(
-                "fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");
-        }
-        if (fromIndex < 0) {
-            throw new ArrayIndexOutOfBoundsException(fromIndex);
-        }
-        if (toIndex > length) {
-            throw new ArrayIndexOutOfBoundsException(toIndex);
-        }
-    }
-
     // Searching
 
     /**
--- a/jdk/src/share/classes/java/util/ArraysParallelSortHelpers.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/ArraysParallelSortHelpers.java	Mon Jun 10 10:38:33 2013 +0100
@@ -25,6 +25,7 @@
 package java.util;
 
 import java.util.concurrent.RecursiveAction;
+import java.util.concurrent.CountedCompleter;
 
 /**
  * Helper utilities for the parallel sort methods in Arrays.parallelSort.
@@ -44,1180 +45,966 @@
  *             c. merge them together
  *         3. merge together the two halves.
  *
- * One reason for splitting in quarters is that this guarantees
- * that the final sort is in the main array, not the workspace
- * array.  (workspace and main swap roles on each subsort step.)
- * Leaf-level sorts use a Sequential quicksort, that in turn uses
- * insertion sort if under threshold.  Otherwise it uses median of
- * three to pick pivot, and loops rather than recurses along left
- * path.
- *
+ * One reason for splitting in quarters is that this guarantees that
+ * the final sort is in the main array, not the workspace array.
+ * (workspace and main swap roles on each subsort step.)  Leaf-level
+ * sorts use the associated sequential sort.
  *
- * Merger classes perform merging for Sorter. If big enough, splits Left
- * partition in half; finds the greatest point in Right partition
- * less than the beginning of the second half of Left via binary
- * search; and then, in parallel, merges left half of Left with
- * elements of Right up to split point, and merges right half of
- * Left with elements of R past split point. At leaf, it just
- * sequentially merges. This is all messy to code; sadly we need
- * distinct versions for each type.
+ * Merger classes perform merging for Sorter.  They are structured
+ * such that if the underlying sort is stable (as is true for
+ * TimSort), then so is the full sort.  If big enough, they split the
+ * largest of the two partitions in half, find the greatest point in
+ * smaller partition less than the beginning of the second half of
+ * larger via binary search; and then merge in parallel the two
+ * partitions.  In part to ensure tasks are triggered in
+ * stability-preserving order, the current CountedCompleter design
+ * requires some little tasks to serve as place holders for triggering
+ * completion tasks.  These classes (EmptyCompleter and Relay) don't
+ * need to keep track of the arrays, and are never themselves forked,
+ * so don't hold any task state.
  *
+ * The primitive class versions (FJByte... FJDouble) are
+ * identical to each other except for type declarations.
+ *
+ * The base sequential sorts rely on non-public versions of TimSort,
+ * ComparableTimSort, and DualPivotQuicksort sort methods that accept
+ * temp workspace array slices that we will have already allocated, so
+ * avoids redundant allocation. (Except for DualPivotQuicksort byte[]
+ * sort, that does not ever use a workspace array.)
  */
 /*package*/ class ArraysParallelSortHelpers {
 
-    // RFE: we should only need a working array as large as the subarray
-    //      to be sorted, but the logic assumes that indices in the two
-    //      arrays always line-up
+    /*
+     * Style note: The task classes have a lot of parameters, that are
+     * stored as task fields and copied to local variables and used in
+     * compute() methods, We pack these into as few lines as possible,
+     * and hoist consistency checks among them before main loops, to
+     * reduce distraction.
+     */
 
-    /** byte support class */
-    static final class FJByte {
-        static final class Sorter extends RecursiveAction {
-            static final long serialVersionUID = 749471161188027634L;
-            final byte[] a;     // array to be sorted.
-            final byte[] w;     // workspace for merge
-            final int origin;   // origin of the part of array we deal with
-            final int n;        // Number of elements in (sub)arrays.
-            final int gran;     // split control
+    /**
+     * A placeholder task for Sorters, used for the lowest
+     * quartile task, that does not need to maintain array state.
+     */
+    static final class EmptyCompleter extends CountedCompleter<Void> {
+        static final long serialVersionUID = 2446542900576103244L;
+        EmptyCompleter(CountedCompleter<?> p) { super(p); }
+        public final void compute() { }
+    }
 
-            Sorter(byte[] a, byte[] w, int origin, int n, int gran) {
-                this.a = a;
-                this.w = w;
-                this.origin = origin;
-                this.n = n;
-                this.gran = gran;
-            }
+    /**
+     * A trigger for secondary merge of two merges
+     */
+    static final class Relay extends CountedCompleter<Void> {
+        static final long serialVersionUID = 2446542900576103244L;
+        final CountedCompleter<?> task;
+        Relay(CountedCompleter<?> task) {
+            super(null, 1);
+            this.task = task;
+        }
+        public final void compute() { }
+        public final void onCompletion(CountedCompleter<?> t) {
+            task.compute();
+        }
+    }
 
-            public void compute() {
-                final int l = origin;
-                final int g = gran;
-                final int n = this.n;
-                final byte[] a = this.a;
-                final byte[] w = this.w;
-                if (n > g) {
-                    int h = n >>> 1; // half
-                    int q = n >>> 2; // lower quarter index
-                    int u = h + q;   // upper quarter
-                    FJSubSorter ls = new FJSubSorter(new Sorter(a, w, l, q,  g),
-                                                     new Sorter(a, w, l+q, h-q, g),
-                                                     new Merger(a, w, l,   q,
-                                                                l+q, h-q, l, g, null));
-                    FJSubSorter rs = new FJSubSorter(new Sorter(a, w, l+h, q,   g),
-                                                     new Sorter(a, w, l+u, n-u, g),
-                                                     new Merger(a, w, l+h, q,
-                                                                l+u, n-u, l+h, g, null));
-                    rs.fork();
-                    ls.compute();
-                    if (rs.tryUnfork()) rs.compute(); else rs.join();
-                    new Merger(w, a, l, h,
-                               l+h, n-h, l, g, null).compute();
-                } else {
-                    DualPivotQuicksort.sort(a, l, l+n-1);   //skip rangeCheck
+    /** Object + Comparator support class */
+    static final class FJObject {
+        static final class Sorter<T> extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final T[] a, w;
+            final int base, size, wbase, gran;
+            Comparator<? super T> comparator;
+            Sorter(CountedCompleter<?> par, T[] a, T[] w, int base, int size,
+                   int wbase, int gran,
+                   Comparator<? super T> comparator) {
+                super(par);
+                this.a = a; this.w = w; this.base = base; this.size = size;
+                this.wbase = wbase; this.gran = gran;
+                this.comparator = comparator;
+            }
+            public final void compute() {
+                CountedCompleter<?> s = this;
+                Comparator<? super T> c = this.comparator;
+                T[] a = this.a, w = this.w; // localize all params
+                int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
+                while (n > g) {
+                    int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
+                    Relay fc = new Relay(new Merger<T>(s, w, a, wb, h,
+                                                       wb+h, n-h, b, g, c));
+                    Relay rc = new Relay(new Merger<T>(fc, a, w, b+h, q,
+                                                       b+u, n-u, wb+h, g, c));
+                    new Sorter<T>(rc, a, w, b+u, n-u, wb+u, g, c).fork();
+                    new Sorter<T>(rc, a, w, b+h, q, wb+h, g, c).fork();;
+                    Relay bc = new Relay(new Merger<T>(fc, a, w, b, q,
+                                                       b+q, h-q, wb, g, c));
+                    new Sorter<T>(bc, a, w, b+q, h-q, wb+q, g, c).fork();
+                    s = new EmptyCompleter(bc);
+                    n = q;
                 }
+                TimSort.sort(a, b, b + n, c, w, wb, n);
+                s.tryComplete();
             }
         }
 
-        static final class Merger extends RecursiveAction {
-            static final long serialVersionUID = -9090258248781844470L;
-            final byte[] a;
-            final byte[] w;
-            final int lo;
-            final int ln;
-            final int ro;
-            final int rn;
-            final int wo;
-            final int gran;
-            final Merger next;
+        static final class Merger<T> extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final T[] a, w; // main and workspace arrays
+            final int lbase, lsize, rbase, rsize, wbase, gran;
+            Comparator<? super T> comparator;
+            Merger(CountedCompleter<?> par, T[] a, T[] w,
+                   int lbase, int lsize, int rbase,
+                   int rsize, int wbase, int gran,
+                   Comparator<? super T> comparator) {
+                super(par);
+                this.a = a; this.w = w;
+                this.lbase = lbase; this.lsize = lsize;
+                this.rbase = rbase; this.rsize = rsize;
+                this.wbase = wbase; this.gran = gran;
+                this.comparator = comparator;
+            }
 
-            Merger(byte[] a, byte[] w, int lo, int ln, int ro, int rn, int wo,
-                   int gran, Merger next) {
-                this.a = a;
-                this.w = w;
-                this.lo = lo;
-                this.ln = ln;
-                this.ro = ro;
-                this.rn = rn;
-                this.wo = wo;
-                this.gran = gran;
-                this.next = next;
+            public final void compute() {
+                Comparator<? super T> c = this.comparator;
+                T[] a = this.a, w = this.w; // localize all params
+                int lb = this.lbase, ln = this.lsize, rb = this.rbase,
+                    rn = this.rsize, k = this.wbase, g = this.gran;
+                if (a == null || w == null || lb < 0 || rb < 0 || k < 0 ||
+                    c == null)
+                    throw new IllegalStateException(); // hoist checks
+                for (int lh, rh;;) {  // split larger, find point in smaller
+                    if (ln >= rn) {
+                        if (ln <= g)
+                            break;
+                        rh = rn;
+                        T split = a[(lh = ln >>> 1) + lb];
+                        for (int lo = 0; lo < rh; ) {
+                            int rm = (lo + rh) >>> 1;
+                            if (c.compare(split, a[rm + rb]) <= 0)
+                                rh = rm;
+                            else
+                                lo = rm + 1;
+                        }
+                    }
+                    else {
+                        if (rn <= g)
+                            break;
+                        lh = ln;
+                        T split = a[(rh = rn >>> 1) + rb];
+                        for (int lo = 0; lo < lh; ) {
+                            int lm = (lo + lh) >>> 1;
+                            if (c.compare(split, a[lm + lb]) <= 0)
+                                lh = lm;
+                            else
+                                lo = lm + 1;
+                        }
+                    }
+                    Merger<T> m = new Merger<T>(this, a, w, lb + lh, ln - lh,
+                                                rb + rh, rn - rh,
+                                                k + lh + rh, g, c);
+                    rn = rh;
+                    ln = lh;
+                    addToPendingCount(1);
+                    m.fork();
+                }
+
+                int lf = lb + ln, rf = rb + rn; // index bounds
+                while (lb < lf && rb < rf) {
+                    T t, al, ar;
+                    if (c.compare((al = a[lb]), (ar = a[rb])) <= 0) {
+                        lb++; t = al;
+                    }
+                    else {
+                        rb++; t = ar;
+                    }
+                    w[k++] = t;
+                }
+                if (rb < rf)
+                    System.arraycopy(a, rb, w, k, rf - rb);
+                else if (lb < lf)
+                    System.arraycopy(a, lb, w, k, lf - lb);
+
+                tryComplete();
             }
 
-            public void compute() {
-                final byte[] a = this.a;
-                final byte[] w = this.w;
-                Merger rights = null;
-                int nleft = ln;
-                int nright = rn;
-                while (nleft > gran) {
-                    int lh = nleft >>> 1;
-                    int splitIndex = lo + lh;
-                    byte split = a[splitIndex];
-                    int rl = 0;
-                    int rh = nright;
-                    while (rl < rh) {
-                        int mid = (rl + rh) >>> 1;
-                        if (split <= a[ro + mid])
-                            rh = mid;
-                        else
-                            rl = mid + 1;
+        }
+    } // FJObject
+
+    /** byte support class */
+    static final class FJByte {
+        static final class Sorter extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final byte[] a, w;
+            final int base, size, wbase, gran;
+            Sorter(CountedCompleter<?> par, byte[] a, byte[] w, int base,
+                   int size, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w; this.base = base; this.size = size;
+                this.wbase = wbase; this.gran = gran;
+            }
+            public final void compute() {
+                CountedCompleter<?> s = this;
+                byte[] a = this.a, w = this.w; // localize all params
+                int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
+                while (n > g) {
+                    int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
+                    Relay fc = new Relay(new Merger(s, w, a, wb, h,
+                                                    wb+h, n-h, b, g));
+                    Relay rc = new Relay(new Merger(fc, a, w, b+h, q,
+                                                    b+u, n-u, wb+h, g));
+                    new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();
+                    new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;
+                    Relay bc = new Relay(new Merger(fc, a, w, b, q,
+                                                    b+q, h-q, wb, g));
+                    new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();
+                    s = new EmptyCompleter(bc);
+                    n = q;
+                }
+                DualPivotQuicksort.sort(a, b, b + n - 1);
+                s.tryComplete();
+            }
+        }
+
+        static final class Merger extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final byte[] a, w; // main and workspace arrays
+            final int lbase, lsize, rbase, rsize, wbase, gran;
+            Merger(CountedCompleter<?> par, byte[] a, byte[] w,
+                   int lbase, int lsize, int rbase,
+                   int rsize, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w;
+                this.lbase = lbase; this.lsize = lsize;
+                this.rbase = rbase; this.rsize = rsize;
+                this.wbase = wbase; this.gran = gran;
+            }
+
+            public final void compute() {
+                byte[] a = this.a, w = this.w; // localize all params
+                int lb = this.lbase, ln = this.lsize, rb = this.rbase,
+                    rn = this.rsize, k = this.wbase, g = this.gran;
+                if (a == null || w == null || lb < 0 || rb < 0 || k < 0)
+                    throw new IllegalStateException(); // hoist checks
+                for (int lh, rh;;) {  // split larger, find point in smaller
+                    if (ln >= rn) {
+                        if (ln <= g)
+                            break;
+                        rh = rn;
+                        byte split = a[(lh = ln >>> 1) + lb];
+                        for (int lo = 0; lo < rh; ) {
+                            int rm = (lo + rh) >>> 1;
+                            if (split <= a[rm + rb])
+                                rh = rm;
+                            else
+                                lo = rm + 1;
+                        }
                     }
-                    (rights = new Merger(a, w, splitIndex, nleft-lh, ro+rh,
-                                         nright-rh, wo+lh+rh, gran, rights)).fork();
-                    nleft = lh;
-                    nright = rh;
+                    else {
+                        if (rn <= g)
+                            break;
+                        lh = ln;
+                        byte split = a[(rh = rn >>> 1) + rb];
+                        for (int lo = 0; lo < lh; ) {
+                            int lm = (lo + lh) >>> 1;
+                            if (split <= a[lm + lb])
+                                lh = lm;
+                            else
+                                lo = lm + 1;
+                        }
+                    }
+                    Merger m = new Merger(this, a, w, lb + lh, ln - lh,
+                                          rb + rh, rn - rh,
+                                          k + lh + rh, g);
+                    rn = rh;
+                    ln = lh;
+                    addToPendingCount(1);
+                    m.fork();
                 }
 
-                int l = lo;
-                int lFence = l + nleft;
-                int r = ro;
-                int rFence = r + nright;
-                int k = wo;
-                while (l < lFence && r < rFence) {
-                    byte al = a[l];
-                    byte ar = a[r];
-                    byte t;
-                    if (al <= ar) {++l; t=al;} else {++r; t = ar;}
+                int lf = lb + ln, rf = rb + rn; // index bounds
+                while (lb < lf && rb < rf) {
+                    byte t, al, ar;
+                    if ((al = a[lb]) <= (ar = a[rb])) {
+                        lb++; t = al;
+                    }
+                    else {
+                        rb++; t = ar;
+                    }
                     w[k++] = t;
                 }
-                while (l < lFence)
-                    w[k++] = a[l++];
-                while (r < rFence)
-                    w[k++] = a[r++];
-                while (rights != null) {
-                    if (rights.tryUnfork())
-                        rights.compute();
-                    else
-                        rights.join();
-                    rights = rights.next;
-                }
+                if (rb < rf)
+                    System.arraycopy(a, rb, w, k, rf - rb);
+                else if (lb < lf)
+                    System.arraycopy(a, lb, w, k, lf - lb);
+                tryComplete();
             }
         }
     } // FJByte
 
     /** char support class */
     static final class FJChar {
-        static final class Sorter extends RecursiveAction {
-            static final long serialVersionUID = 8723376019074596641L;
-            final char[] a;     // array to be sorted.
-            final char[] w;     // workspace for merge
-            final int origin;   // origin of the part of array we deal with
-            final int n;        // Number of elements in (sub)arrays.
-            final int gran;     // split control
-
-            Sorter(char[] a, char[] w, int origin, int n, int gran) {
-                this.a = a;
-                this.w = w;
-                this.origin = origin;
-                this.n = n;
-                this.gran = gran;
+        static final class Sorter extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final char[] a, w;
+            final int base, size, wbase, gran;
+            Sorter(CountedCompleter<?> par, char[] a, char[] w, int base,
+                   int size, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w; this.base = base; this.size = size;
+                this.wbase = wbase; this.gran = gran;
             }
-
-            public void compute() {
-                final int l = origin;
-                final int g = gran;
-                final int n = this.n;
-                final char[] a = this.a;
-                final char[] w = this.w;
-                if (n > g) {
-                    int h = n >>> 1; // half
-                    int q = n >>> 2; // lower quarter index
-                    int u = h + q;   // upper quarter
-                    FJSubSorter ls = new FJSubSorter(new Sorter(a, w, l, q,   g),
-                                                     new Sorter(a, w, l+q, h-q, g),
-                                                     new Merger(a, w, l,   q,
-                                                                l+q, h-q, l, g, null));
-                    FJSubSorter rs = new FJSubSorter(new Sorter(a, w, l + h, q,   g),
-                                                     new Sorter(a, w, l+u, n-u, g),
-                                                     new Merger(a, w, l+h, q,
-                                                                l+u, n-u, l+h, g, null));
-                    rs.fork();
-                    ls.compute();
-                    if (rs.tryUnfork()) rs.compute(); else rs.join();
-                    new Merger(w, a, l, h, l + h, n - h, l, g, null).compute();
-                } else {
-                    DualPivotQuicksort.sort(a, l, l+n-1);   // skip rangeCheck
+            public final void compute() {
+                CountedCompleter<?> s = this;
+                char[] a = this.a, w = this.w; // localize all params
+                int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
+                while (n > g) {
+                    int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
+                    Relay fc = new Relay(new Merger(s, w, a, wb, h,
+                                                    wb+h, n-h, b, g));
+                    Relay rc = new Relay(new Merger(fc, a, w, b+h, q,
+                                                    b+u, n-u, wb+h, g));
+                    new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();
+                    new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;
+                    Relay bc = new Relay(new Merger(fc, a, w, b, q,
+                                                    b+q, h-q, wb, g));
+                    new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();
+                    s = new EmptyCompleter(bc);
+                    n = q;
                 }
+                DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);
+                s.tryComplete();
             }
         }
 
-        static final class Merger extends RecursiveAction {
-            static final long serialVersionUID = -1383975444621698926L;
-            final char[] a;
-            final char[] w;
-            final int lo;
-            final int ln;
-            final int ro;
-            final int rn;
-            final int wo;
-            final int gran;
-            final Merger next;
-
-            Merger(char[] a, char[] w, int lo, int ln, int ro, int rn, int wo,
-                   int gran, Merger next) {
-                this.a = a;
-                this.w = w;
-                this.lo = lo;
-                this.ln = ln;
-                this.ro = ro;
-                this.rn = rn;
-                this.wo = wo;
-                this.gran = gran;
-                this.next = next;
+        static final class Merger extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final char[] a, w; // main and workspace arrays
+            final int lbase, lsize, rbase, rsize, wbase, gran;
+            Merger(CountedCompleter<?> par, char[] a, char[] w,
+                   int lbase, int lsize, int rbase,
+                   int rsize, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w;
+                this.lbase = lbase; this.lsize = lsize;
+                this.rbase = rbase; this.rsize = rsize;
+                this.wbase = wbase; this.gran = gran;
             }
 
-            public void compute() {
-                final char[] a = this.a;
-                final char[] w = this.w;
-                Merger rights = null;
-                int nleft = ln;
-                int nright = rn;
-                while (nleft > gran) {
-                    int lh = nleft >>> 1;
-                    int splitIndex = lo + lh;
-                    char split = a[splitIndex];
-                    int rl = 0;
-                    int rh = nright;
-                    while (rl < rh) {
-                        int mid = (rl + rh) >>> 1;
-                        if (split <= a[ro + mid])
-                            rh = mid;
-                        else
-                            rl = mid + 1;
+            public final void compute() {
+                char[] a = this.a, w = this.w; // localize all params
+                int lb = this.lbase, ln = this.lsize, rb = this.rbase,
+                    rn = this.rsize, k = this.wbase, g = this.gran;
+                if (a == null || w == null || lb < 0 || rb < 0 || k < 0)
+                    throw new IllegalStateException(); // hoist checks
+                for (int lh, rh;;) {  // split larger, find point in smaller
+                    if (ln >= rn) {
+                        if (ln <= g)
+                            break;
+                        rh = rn;
+                        char split = a[(lh = ln >>> 1) + lb];
+                        for (int lo = 0; lo < rh; ) {
+                            int rm = (lo + rh) >>> 1;
+                            if (split <= a[rm + rb])
+                                rh = rm;
+                            else
+                                lo = rm + 1;
+                        }
                     }
-                    (rights = new Merger(a, w, splitIndex, nleft-lh, ro+rh,
-                                         nright-rh, wo+lh+rh, gran, rights)).fork();
-                    nleft = lh;
-                    nright = rh;
+                    else {
+                        if (rn <= g)
+                            break;
+                        lh = ln;
+                        char split = a[(rh = rn >>> 1) + rb];
+                        for (int lo = 0; lo < lh; ) {
+                            int lm = (lo + lh) >>> 1;
+                            if (split <= a[lm + lb])
+                                lh = lm;
+                            else
+                                lo = lm + 1;
+                        }
+                    }
+                    Merger m = new Merger(this, a, w, lb + lh, ln - lh,
+                                          rb + rh, rn - rh,
+                                          k + lh + rh, g);
+                    rn = rh;
+                    ln = lh;
+                    addToPendingCount(1);
+                    m.fork();
                 }
 
-                int l = lo;
-                int lFence = l + nleft;
-                int r = ro;
-                int rFence = r + nright;
-                int k = wo;
-                while (l < lFence && r < rFence) {
-                    char al = a[l];
-                    char ar = a[r];
-                    char t;
-                    if (al <= ar) {++l; t=al;} else {++r; t = ar;}
+                int lf = lb + ln, rf = rb + rn; // index bounds
+                while (lb < lf && rb < rf) {
+                    char t, al, ar;
+                    if ((al = a[lb]) <= (ar = a[rb])) {
+                        lb++; t = al;
+                    }
+                    else {
+                        rb++; t = ar;
+                    }
                     w[k++] = t;
                 }
-                while (l < lFence)
-                    w[k++] = a[l++];
-                while (r < rFence)
-                    w[k++] = a[r++];
-                while (rights != null) {
-                    if (rights.tryUnfork())
-                        rights.compute();
-                    else
-                        rights.join();
-                    rights = rights.next;
-                }
+                if (rb < rf)
+                    System.arraycopy(a, rb, w, k, rf - rb);
+                else if (lb < lf)
+                    System.arraycopy(a, lb, w, k, lf - lb);
+                tryComplete();
             }
         }
     } // FJChar
 
     /** short support class */
     static final class FJShort {
-        static final class Sorter extends RecursiveAction {
-            static final long serialVersionUID = -7886754793730583084L;
-            final short[] a;    // array to be sorted.
-            final short[] w;    // workspace for merge
-            final int origin;   // origin of the part of array we deal with
-            final int n;        // Number of elements in (sub)arrays.
-            final int gran;     // split control
-
-            Sorter(short[] a, short[] w, int origin, int n, int gran) {
-                this.a = a;
-                this.w = w;
-                this.origin = origin;
-                this.n = n;
-                this.gran = gran;
+        static final class Sorter extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final short[] a, w;
+            final int base, size, wbase, gran;
+            Sorter(CountedCompleter<?> par, short[] a, short[] w, int base,
+                   int size, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w; this.base = base; this.size = size;
+                this.wbase = wbase; this.gran = gran;
             }
-
-            public void compute() {
-                final int l = origin;
-                final int g = gran;
-                final int n = this.n;
-                final short[] a = this.a;
-                final short[] w = this.w;
-                if (n > g) {
-                    int h = n >>> 1; // half
-                    int q = n >>> 2; // lower quarter index
-                    int u = h + q;   // upper quarter
-                    FJSubSorter ls = new FJSubSorter(new Sorter(a, w, l, q,   g),
-                                                     new Sorter(a, w, l+q, h-q, g),
-                                                     new Merger(a, w, l,   q,
-                                                                l+q, h-q, l, g, null));
-                    FJSubSorter rs = new FJSubSorter(new Sorter(a, w, l + h, q,   g),
-                                                     new Sorter(a, w, l+u, n-u, g),
-                                                     new Merger(a, w, l+h, q,
-                                                                l+u, n-u, l+h, g, null));
-                    rs.fork();
-                    ls.compute();
-                    if (rs.tryUnfork()) rs.compute(); else rs.join();
-                    new Merger(w, a, l, h, l + h, n - h, l, g, null).compute();
-                } else {
-                    DualPivotQuicksort.sort(a, l, l+n-1);   // skip rangeCheck
+            public final void compute() {
+                CountedCompleter<?> s = this;
+                short[] a = this.a, w = this.w; // localize all params
+                int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
+                while (n > g) {
+                    int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
+                    Relay fc = new Relay(new Merger(s, w, a, wb, h,
+                                                    wb+h, n-h, b, g));
+                    Relay rc = new Relay(new Merger(fc, a, w, b+h, q,
+                                                    b+u, n-u, wb+h, g));
+                    new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();
+                    new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;
+                    Relay bc = new Relay(new Merger(fc, a, w, b, q,
+                                                    b+q, h-q, wb, g));
+                    new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();
+                    s = new EmptyCompleter(bc);
+                    n = q;
                 }
+                DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);
+                s.tryComplete();
             }
         }
 
-        static final class Merger extends RecursiveAction {
-            static final long serialVersionUID = 3895749408536700048L;
-            final short[] a;
-            final short[] w;
-            final int lo;
-            final int ln;
-            final int ro;
-            final int rn;
-            final int wo;
-            final int gran;
-            final Merger next;
-
-            Merger(short[] a, short[] w, int lo, int ln, int ro, int rn, int wo,
-                   int gran, Merger next) {
-                this.a = a;
-                this.w = w;
-                this.lo = lo;
-                this.ln = ln;
-                this.ro = ro;
-                this.rn = rn;
-                this.wo = wo;
-                this.gran = gran;
-                this.next = next;
+        static final class Merger extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final short[] a, w; // main and workspace arrays
+            final int lbase, lsize, rbase, rsize, wbase, gran;
+            Merger(CountedCompleter<?> par, short[] a, short[] w,
+                   int lbase, int lsize, int rbase,
+                   int rsize, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w;
+                this.lbase = lbase; this.lsize = lsize;
+                this.rbase = rbase; this.rsize = rsize;
+                this.wbase = wbase; this.gran = gran;
             }
 
-            public void compute() {
-                final short[] a = this.a;
-                final short[] w = this.w;
-                Merger rights = null;
-                int nleft = ln;
-                int nright = rn;
-                while (nleft > gran) {
-                    int lh = nleft >>> 1;
-                    int splitIndex = lo + lh;
-                    short split = a[splitIndex];
-                    int rl = 0;
-                    int rh = nright;
-                    while (rl < rh) {
-                        int mid = (rl + rh) >>> 1;
-                        if (split <= a[ro + mid])
-                            rh = mid;
-                        else
-                            rl = mid + 1;
+            public final void compute() {
+                short[] a = this.a, w = this.w; // localize all params
+                int lb = this.lbase, ln = this.lsize, rb = this.rbase,
+                    rn = this.rsize, k = this.wbase, g = this.gran;
+                if (a == null || w == null || lb < 0 || rb < 0 || k < 0)
+                    throw new IllegalStateException(); // hoist checks
+                for (int lh, rh;;) {  // split larger, find point in smaller
+                    if (ln >= rn) {
+                        if (ln <= g)
+                            break;
+                        rh = rn;
+                        short split = a[(lh = ln >>> 1) + lb];
+                        for (int lo = 0; lo < rh; ) {
+                            int rm = (lo + rh) >>> 1;
+                            if (split <= a[rm + rb])
+                                rh = rm;
+                            else
+                                lo = rm + 1;
+                        }
                     }
-                    (rights = new Merger(a, w, splitIndex, nleft-lh, ro+rh,
-                                         nright-rh, wo+lh+rh, gran, rights)).fork();
-                    nleft = lh;
-                    nright = rh;
+                    else {
+                        if (rn <= g)
+                            break;
+                        lh = ln;
+                        short split = a[(rh = rn >>> 1) + rb];
+                        for (int lo = 0; lo < lh; ) {
+                            int lm = (lo + lh) >>> 1;
+                            if (split <= a[lm + lb])
+                                lh = lm;
+                            else
+                                lo = lm + 1;
+                        }
+                    }
+                    Merger m = new Merger(this, a, w, lb + lh, ln - lh,
+                                          rb + rh, rn - rh,
+                                          k + lh + rh, g);
+                    rn = rh;
+                    ln = lh;
+                    addToPendingCount(1);
+                    m.fork();
                 }
 
-                int l = lo;
-                int lFence = l + nleft;
-                int r = ro;
-                int rFence = r + nright;
-                int k = wo;
-                while (l < lFence && r < rFence) {
-                    short al = a[l];
-                    short ar = a[r];
-                    short t;
-                    if (al <= ar) {++l; t=al;} else {++r; t = ar;}
+                int lf = lb + ln, rf = rb + rn; // index bounds
+                while (lb < lf && rb < rf) {
+                    short t, al, ar;
+                    if ((al = a[lb]) <= (ar = a[rb])) {
+                        lb++; t = al;
+                    }
+                    else {
+                        rb++; t = ar;
+                    }
                     w[k++] = t;
                 }
-                while (l < lFence)
-                    w[k++] = a[l++];
-                while (r < rFence)
-                    w[k++] = a[r++];
-                while (rights != null) {
-                    if (rights.tryUnfork())
-                        rights.compute();
-                    else
-                        rights.join();
-                    rights = rights.next;
-                }
+                if (rb < rf)
+                    System.arraycopy(a, rb, w, k, rf - rb);
+                else if (lb < lf)
+                    System.arraycopy(a, lb, w, k, lf - lb);
+                tryComplete();
             }
         }
     } // FJShort
 
     /** int support class */
     static final class FJInt {
-        static final class Sorter extends RecursiveAction {
-            static final long serialVersionUID = 4263311808957292729L;
-            final int[] a;     // array to be sorted.
-            final int[] w;     // workspace for merge
-            final int origin;  // origin of the part of array we deal with
-            final int n;       // Number of elements in (sub)arrays.
-            final int gran;    // split control
-
-            Sorter(int[] a, int[] w, int origin, int n, int gran) {
-                this.a = a;
-                this.w = w;
-                this.origin = origin;
-                this.n = n;
-                this.gran = gran;
+        static final class Sorter extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final int[] a, w;
+            final int base, size, wbase, gran;
+            Sorter(CountedCompleter<?> par, int[] a, int[] w, int base,
+                   int size, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w; this.base = base; this.size = size;
+                this.wbase = wbase; this.gran = gran;
             }
-
-            public void compute() {
-                final int l = origin;
-                final int g = gran;
-                final int n = this.n;
-                final int[] a = this.a;
-                final int[] w = this.w;
-                if (n > g) {
-                    int h = n >>> 1; // half
-                    int q = n >>> 2; // lower quarter index
-                    int u = h + q;   // upper quarter
-                    FJSubSorter ls = new FJSubSorter(new Sorter(a, w, l, q,   g),
-                                                     new Sorter(a, w, l+q, h-q, g),
-                                                     new Merger(a, w, l,   q,
-                                                                l+q, h-q, l, g, null));
-                    FJSubSorter rs = new FJSubSorter(new Sorter(a, w, l + h, q,   g),
-                                                     new Sorter(a, w, l+u, n-u, g),
-                                                     new Merger(a, w, l+h, q,
-                                                                l+u, n-u, l+h, g, null));
-                    rs.fork();
-                    ls.compute();
-                    if (rs.tryUnfork()) rs.compute(); else rs.join();
-                    new Merger(w, a, l, h, l + h, n - h, l, g, null).compute();
-                } else {
-                    DualPivotQuicksort.sort(a, l, l+n-1);   // skip rangeCheck
+            public final void compute() {
+                CountedCompleter<?> s = this;
+                int[] a = this.a, w = this.w; // localize all params
+                int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
+                while (n > g) {
+                    int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
+                    Relay fc = new Relay(new Merger(s, w, a, wb, h,
+                                                    wb+h, n-h, b, g));
+                    Relay rc = new Relay(new Merger(fc, a, w, b+h, q,
+                                                    b+u, n-u, wb+h, g));
+                    new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();
+                    new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;
+                    Relay bc = new Relay(new Merger(fc, a, w, b, q,
+                                                    b+q, h-q, wb, g));
+                    new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();
+                    s = new EmptyCompleter(bc);
+                    n = q;
                 }
+                DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);
+                s.tryComplete();
             }
         }
 
-        static final class Merger extends RecursiveAction {
-            static final long serialVersionUID = -8727507284219982792L;
-            final int[] a;
-            final int[] w;
-            final int lo;
-            final int ln;
-            final int ro;
-            final int rn;
-            final int wo;
-            final int gran;
-            final Merger next;
-
-            Merger(int[] a, int[] w, int lo, int ln, int ro, int rn, int wo,
-                   int gran, Merger next) {
-                this.a = a;
-                this.w = w;
-                this.lo = lo;
-                this.ln = ln;
-                this.ro = ro;
-                this.rn = rn;
-                this.wo = wo;
-                this.gran = gran;
-                this.next = next;
+        static final class Merger extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final int[] a, w; // main and workspace arrays
+            final int lbase, lsize, rbase, rsize, wbase, gran;
+            Merger(CountedCompleter<?> par, int[] a, int[] w,
+                   int lbase, int lsize, int rbase,
+                   int rsize, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w;
+                this.lbase = lbase; this.lsize = lsize;
+                this.rbase = rbase; this.rsize = rsize;
+                this.wbase = wbase; this.gran = gran;
             }
 
-            public void compute() {
-                final int[] a = this.a;
-                final int[] w = this.w;
-                Merger rights = null;
-                int nleft = ln;
-                int nright = rn;
-                while (nleft > gran) {
-                    int lh = nleft >>> 1;
-                    int splitIndex = lo + lh;
-                    int split = a[splitIndex];
-                    int rl = 0;
-                    int rh = nright;
-                    while (rl < rh) {
-                        int mid = (rl + rh) >>> 1;
-                        if (split <= a[ro + mid])
-                            rh = mid;
-                        else
-                            rl = mid + 1;
+            public final void compute() {
+                int[] a = this.a, w = this.w; // localize all params
+                int lb = this.lbase, ln = this.lsize, rb = this.rbase,
+                    rn = this.rsize, k = this.wbase, g = this.gran;
+                if (a == null || w == null || lb < 0 || rb < 0 || k < 0)
+                    throw new IllegalStateException(); // hoist checks
+                for (int lh, rh;;) {  // split larger, find point in smaller
+                    if (ln >= rn) {
+                        if (ln <= g)
+                            break;
+                        rh = rn;
+                        int split = a[(lh = ln >>> 1) + lb];
+                        for (int lo = 0; lo < rh; ) {
+                            int rm = (lo + rh) >>> 1;
+                            if (split <= a[rm + rb])
+                                rh = rm;
+                            else
+                                lo = rm + 1;
+                        }
                     }
-                    (rights = new Merger(a, w, splitIndex, nleft-lh, ro+rh,
-                                         nright-rh, wo+lh+rh, gran, rights)).fork();
-                    nleft = lh;
-                    nright = rh;
+                    else {
+                        if (rn <= g)
+                            break;
+                        lh = ln;
+                        int split = a[(rh = rn >>> 1) + rb];
+                        for (int lo = 0; lo < lh; ) {
+                            int lm = (lo + lh) >>> 1;
+                            if (split <= a[lm + lb])
+                                lh = lm;
+                            else
+                                lo = lm + 1;
+                        }
+                    }
+                    Merger m = new Merger(this, a, w, lb + lh, ln - lh,
+                                          rb + rh, rn - rh,
+                                          k + lh + rh, g);
+                    rn = rh;
+                    ln = lh;
+                    addToPendingCount(1);
+                    m.fork();
                 }
 
-                int l = lo;
-                int lFence = l + nleft;
-                int r = ro;
-                int rFence = r + nright;
-                int k = wo;
-                while (l < lFence && r < rFence) {
-                    int al = a[l];
-                    int ar = a[r];
-                    int t;
-                    if (al <= ar) {++l; t=al;} else {++r; t = ar;}
+                int lf = lb + ln, rf = rb + rn; // index bounds
+                while (lb < lf && rb < rf) {
+                    int t, al, ar;
+                    if ((al = a[lb]) <= (ar = a[rb])) {
+                        lb++; t = al;
+                    }
+                    else {
+                        rb++; t = ar;
+                    }
                     w[k++] = t;
                 }
-                while (l < lFence)
-                    w[k++] = a[l++];
-                while (r < rFence)
-                    w[k++] = a[r++];
-                while (rights != null) {
-                    if (rights.tryUnfork())
-                        rights.compute();
-                    else
-                        rights.join();
-                    rights = rights.next;
-                }
+                if (rb < rf)
+                    System.arraycopy(a, rb, w, k, rf - rb);
+                else if (lb < lf)
+                    System.arraycopy(a, lb, w, k, lf - lb);
+                tryComplete();
             }
         }
     } // FJInt
 
     /** long support class */
     static final class FJLong {
-        static final class Sorter extends RecursiveAction {
-            static final long serialVersionUID = 6553695007444392455L;
-            final long[] a;     // array to be sorted.
-            final long[] w;     // workspace for merge
-            final int origin;   // origin of the part of array we deal with
-            final int n;        // Number of elements in (sub)arrays.
-            final int gran;     // split control
-
-            Sorter(long[] a, long[] w, int origin, int n, int gran) {
-                this.a = a;
-                this.w = w;
-                this.origin = origin;
-                this.n = n;
-                this.gran = gran;
+        static final class Sorter extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final long[] a, w;
+            final int base, size, wbase, gran;
+            Sorter(CountedCompleter<?> par, long[] a, long[] w, int base,
+                   int size, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w; this.base = base; this.size = size;
+                this.wbase = wbase; this.gran = gran;
             }
-
-            public void compute() {
-                final int l = origin;
-                final int g = gran;
-                final int n = this.n;
-                final long[] a = this.a;
-                final long[] w = this.w;
-                if (n > g) {
-                    int h = n >>> 1; // half
-                    int q = n >>> 2; // lower quarter index
-                    int u = h + q;   // upper quarter
-                    FJSubSorter ls = new FJSubSorter(new Sorter(a, w, l, q,   g),
-                                                     new Sorter(a, w, l+q, h-q, g),
-                                                     new Merger(a, w, l,   q,
-                                                                l+q, h-q, l, g, null));
-                    FJSubSorter rs = new FJSubSorter(new Sorter(a, w, l + h, q,   g),
-                                                     new Sorter(a, w, l+u, n-u, g),
-                                                     new Merger(a, w, l+h, q,
-                                                                l+u, n-u, l+h, g, null));
-                    rs.fork();
-                    ls.compute();
-                    if (rs.tryUnfork()) rs.compute(); else rs.join();
-                    new Merger(w, a, l, h, l + h, n - h, l, g, null).compute();
-                } else {
-                    DualPivotQuicksort.sort(a, l, l+n-1);   // skip rangeCheck
+            public final void compute() {
+                CountedCompleter<?> s = this;
+                long[] a = this.a, w = this.w; // localize all params
+                int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
+                while (n > g) {
+                    int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
+                    Relay fc = new Relay(new Merger(s, w, a, wb, h,
+                                                    wb+h, n-h, b, g));
+                    Relay rc = new Relay(new Merger(fc, a, w, b+h, q,
+                                                    b+u, n-u, wb+h, g));
+                    new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();
+                    new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;
+                    Relay bc = new Relay(new Merger(fc, a, w, b, q,
+                                                    b+q, h-q, wb, g));
+                    new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();
+                    s = new EmptyCompleter(bc);
+                    n = q;
                 }
+                DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);
+                s.tryComplete();
             }
         }
 
-        static final class Merger extends RecursiveAction {
-            static final long serialVersionUID = 8843567516333283861L;
-            final long[] a;
-            final long[] w;
-            final int lo;
-            final int ln;
-            final int ro;
-            final int rn;
-            final int wo;
-            final int gran;
-            final Merger next;
-
-            Merger(long[] a, long[] w, int lo, int ln, int ro, int rn, int wo,
-                   int gran, Merger next) {
-                this.a = a;
-                this.w = w;
-                this.lo = lo;
-                this.ln = ln;
-                this.ro = ro;
-                this.rn = rn;
-                this.wo = wo;
-                this.gran = gran;
-                this.next = next;
+        static final class Merger extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final long[] a, w; // main and workspace arrays
+            final int lbase, lsize, rbase, rsize, wbase, gran;
+            Merger(CountedCompleter<?> par, long[] a, long[] w,
+                   int lbase, int lsize, int rbase,
+                   int rsize, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w;
+                this.lbase = lbase; this.lsize = lsize;
+                this.rbase = rbase; this.rsize = rsize;
+                this.wbase = wbase; this.gran = gran;
             }
 
-            public void compute() {
-                final long[] a = this.a;
-                final long[] w = this.w;
-                Merger rights = null;
-                int nleft = ln;
-                int nright = rn;
-                while (nleft > gran) {
-                    int lh = nleft >>> 1;
-                    int splitIndex = lo + lh;
-                    long split = a[splitIndex];
-                    int rl = 0;
-                    int rh = nright;
-                    while (rl < rh) {
-                        int mid = (rl + rh) >>> 1;
-                        if (split <= a[ro + mid])
-                            rh = mid;
-                        else
-                            rl = mid + 1;
+            public final void compute() {
+                long[] a = this.a, w = this.w; // localize all params
+                int lb = this.lbase, ln = this.lsize, rb = this.rbase,
+                    rn = this.rsize, k = this.wbase, g = this.gran;
+                if (a == null || w == null || lb < 0 || rb < 0 || k < 0)
+                    throw new IllegalStateException(); // hoist checks
+                for (int lh, rh;;) {  // split larger, find point in smaller
+                    if (ln >= rn) {
+                        if (ln <= g)
+                            break;
+                        rh = rn;
+                        long split = a[(lh = ln >>> 1) + lb];
+                        for (int lo = 0; lo < rh; ) {
+                            int rm = (lo + rh) >>> 1;
+                            if (split <= a[rm + rb])
+                                rh = rm;
+                            else
+                                lo = rm + 1;
+                        }
                     }
-                    (rights = new Merger(a, w, splitIndex, nleft-lh, ro+rh,
-                      nright-rh, wo+lh+rh, gran, rights)).fork();
-                    nleft = lh;
-                    nright = rh;
+                    else {
+                        if (rn <= g)
+                            break;
+                        lh = ln;
+                        long split = a[(rh = rn >>> 1) + rb];
+                        for (int lo = 0; lo < lh; ) {
+                            int lm = (lo + lh) >>> 1;
+                            if (split <= a[lm + lb])
+                                lh = lm;
+                            else
+                                lo = lm + 1;
+                        }
+                    }
+                    Merger m = new Merger(this, a, w, lb + lh, ln - lh,
+                                          rb + rh, rn - rh,
+                                          k + lh + rh, g);
+                    rn = rh;
+                    ln = lh;
+                    addToPendingCount(1);
+                    m.fork();
                 }
 
-                int l = lo;
-                int lFence = l + nleft;
-                int r = ro;
-                int rFence = r + nright;
-                int k = wo;
-                while (l < lFence && r < rFence) {
-                    long al = a[l];
-                    long ar = a[r];
-                    long t;
-                    if (al <= ar) {++l; t=al;} else {++r; t = ar;}
+                int lf = lb + ln, rf = rb + rn; // index bounds
+                while (lb < lf && rb < rf) {
+                    long t, al, ar;
+                    if ((al = a[lb]) <= (ar = a[rb])) {
+                        lb++; t = al;
+                    }
+                    else {
+                        rb++; t = ar;
+                    }
                     w[k++] = t;
                 }
-                while (l < lFence)
-                    w[k++] = a[l++];
-                while (r < rFence)
-                    w[k++] = a[r++];
-                while (rights != null) {
-                    if (rights.tryUnfork())
-                        rights.compute();
-                    else
-                        rights.join();
-                    rights = rights.next;
-                }
+                if (rb < rf)
+                    System.arraycopy(a, rb, w, k, rf - rb);
+                else if (lb < lf)
+                    System.arraycopy(a, lb, w, k, lf - lb);
+                tryComplete();
             }
         }
     } // FJLong
 
     /** float support class */
     static final class FJFloat {
-        static final class Sorter extends RecursiveAction {
-            static final long serialVersionUID = 1602600178202763377L;
-            final float[] a;    // array to be sorted.
-            final float[] w;    // workspace for merge
-            final int origin;   // origin of the part of array we deal with
-            final int n;        // Number of elements in (sub)arrays.
-            final int gran;     // split control
-
-            Sorter(float[] a, float[] w, int origin, int n, int gran) {
-                this.a = a;
-                this.w = w;
-                this.origin = origin;
-                this.n = n;
-                this.gran = gran;
+        static final class Sorter extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final float[] a, w;
+            final int base, size, wbase, gran;
+            Sorter(CountedCompleter<?> par, float[] a, float[] w, int base,
+                   int size, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w; this.base = base; this.size = size;
+                this.wbase = wbase; this.gran = gran;
             }
-
-            public void compute() {
-                final int l = origin;
-                final int g = gran;
-                final int n = this.n;
-                final float[] a = this.a;
-                final float[] w = this.w;
-                if (n > g) {
-                    int h = n >>> 1; // half
-                    int q = n >>> 2; // lower quarter index
-                    int u = h + q;   // upper quarter
-                    FJSubSorter ls = new FJSubSorter(new Sorter(a, w, l, q,   g),
-                                                     new Sorter(a, w, l+q, h-q, g),
-                                                     new Merger(a, w, l,   q,
-                                                                l+q, h-q, l, g, null));
-                    FJSubSorter rs = new FJSubSorter(new Sorter(a, w, l + h, q,   g),
-                                                     new Sorter(a, w, l+u, n-u, g),
-                                                     new Merger(a, w, l+h, q,
-                                                                l+u, n-u, l+h, g, null));
-                    rs.fork();
-                    ls.compute();
-                    if (rs.tryUnfork()) rs.compute(); else rs.join();
-                    new Merger(w, a, l, h, l + h, n - h, l, g, null).compute();
-                } else {
-                    DualPivotQuicksort.sort(a, l, l+n-1);   // skip rangeCheck
+            public final void compute() {
+                CountedCompleter<?> s = this;
+                float[] a = this.a, w = this.w; // localize all params
+                int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
+                while (n > g) {
+                    int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
+                    Relay fc = new Relay(new Merger(s, w, a, wb, h,
+                                                    wb+h, n-h, b, g));
+                    Relay rc = new Relay(new Merger(fc, a, w, b+h, q,
+                                                    b+u, n-u, wb+h, g));
+                    new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();
+                    new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;
+                    Relay bc = new Relay(new Merger(fc, a, w, b, q,
+                                                    b+q, h-q, wb, g));
+                    new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();
+                    s = new EmptyCompleter(bc);
+                    n = q;
                 }
+                DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);
+                s.tryComplete();
             }
         }
 
-        static final class Merger extends RecursiveAction {
-            static final long serialVersionUID = 1518176433845397426L;
-            final float[] a;
-            final float[] w;
-            final int lo;
-            final int ln;
-            final int ro;
-            final int rn;
-            final int wo;
-            final int gran;
-            final Merger next;
-
-            Merger(float[] a, float[] w, int lo, int ln, int ro, int rn, int wo,
-                   int gran, Merger next) {
-                this.a = a;
-                this.w = w;
-                this.lo = lo;
-                this.ln = ln;
-                this.ro = ro;
-                this.rn = rn;
-                this.wo = wo;
-                this.gran = gran;
-                this.next = next;
+        static final class Merger extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final float[] a, w; // main and workspace arrays
+            final int lbase, lsize, rbase, rsize, wbase, gran;
+            Merger(CountedCompleter<?> par, float[] a, float[] w,
+                   int lbase, int lsize, int rbase,
+                   int rsize, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w;
+                this.lbase = lbase; this.lsize = lsize;
+                this.rbase = rbase; this.rsize = rsize;
+                this.wbase = wbase; this.gran = gran;
             }
 
-            public void compute() {
-                final float[] a = this.a;
-                final float[] w = this.w;
-                Merger rights = null;
-                int nleft = ln;
-                int nright = rn;
-                while (nleft > gran) {
-                    int lh = nleft >>> 1;
-                    int splitIndex = lo + lh;
-                    float split = a[splitIndex];
-                    int rl = 0;
-                    int rh = nright;
-                    while (rl < rh) {
-                        int mid = (rl + rh) >>> 1;
-                        if (Float.compare(split, a[ro+mid]) <= 0)
-                            rh = mid;
-                        else
-                            rl = mid + 1;
+            public final void compute() {
+                float[] a = this.a, w = this.w; // localize all params
+                int lb = this.lbase, ln = this.lsize, rb = this.rbase,
+                    rn = this.rsize, k = this.wbase, g = this.gran;
+                if (a == null || w == null || lb < 0 || rb < 0 || k < 0)
+                    throw new IllegalStateException(); // hoist checks
+                for (int lh, rh;;) {  // split larger, find point in smaller
+                    if (ln >= rn) {
+                        if (ln <= g)
+                            break;
+                        rh = rn;
+                        float split = a[(lh = ln >>> 1) + lb];
+                        for (int lo = 0; lo < rh; ) {
+                            int rm = (lo + rh) >>> 1;
+                            if (split <= a[rm + rb])
+                                rh = rm;
+                            else
+                                lo = rm + 1;
+                        }
                     }
-                    (rights = new Merger(a, w, splitIndex, nleft-lh, ro+rh,
-                                         nright-rh, wo+lh+rh, gran, rights)).fork();
-                    nleft = lh;
-                    nright = rh;
+                    else {
+                        if (rn <= g)
+                            break;
+                        lh = ln;
+                        float split = a[(rh = rn >>> 1) + rb];
+                        for (int lo = 0; lo < lh; ) {
+                            int lm = (lo + lh) >>> 1;
+                            if (split <= a[lm + lb])
+                                lh = lm;
+                            else
+                                lo = lm + 1;
+                        }
+                    }
+                    Merger m = new Merger(this, a, w, lb + lh, ln - lh,
+                                          rb + rh, rn - rh,
+                                          k + lh + rh, g);
+                    rn = rh;
+                    ln = lh;
+                    addToPendingCount(1);
+                    m.fork();
                 }
 
-                int l = lo;
-                int lFence = l + nleft;
-                int r = ro;
-                int rFence = r + nright;
-                int k = wo;
-                while (l < lFence && r < rFence) {
-                    float al = a[l];
-                    float ar = a[r];
-                    float t;
-                    if (Float.compare(al, ar) <= 0) {
-                        ++l;
-                        t = al;
-                    } else {
-                        ++r;
-                        t = ar;
+                int lf = lb + ln, rf = rb + rn; // index bounds
+                while (lb < lf && rb < rf) {
+                    float t, al, ar;
+                    if ((al = a[lb]) <= (ar = a[rb])) {
+                        lb++; t = al;
+                    }
+                    else {
+                        rb++; t = ar;
                     }
                     w[k++] = t;
                 }
-                while (l < lFence)
-                    w[k++] = a[l++];
-                while (r < rFence)
-                    w[k++] = a[r++];
-                while (rights != null) {
-                    if (rights.tryUnfork())
-                        rights.compute();
-                    else
-                        rights.join();
-                    rights = rights.next;
-                }
+                if (rb < rf)
+                    System.arraycopy(a, rb, w, k, rf - rb);
+                else if (lb < lf)
+                    System.arraycopy(a, lb, w, k, lf - lb);
+                tryComplete();
             }
         }
     } // FJFloat
 
     /** double support class */
     static final class FJDouble {
-        static final class Sorter extends RecursiveAction {
+        static final class Sorter extends CountedCompleter<Void> {
             static final long serialVersionUID = 2446542900576103244L;
-            final double[] a;    // array to be sorted.
-            final double[] w;    // workspace for merge
-            final int origin;    // origin of the part of array we deal with
-            final int n;         // Number of elements in (sub)arrays.
-            final int gran;      // split control
-
-            Sorter(double[] a, double[] w, int origin, int n, int gran) {
-                this.a = a;
-                this.w = w;
-                this.origin = origin;
-                this.n = n;
-                this.gran = gran;
+            final double[] a, w;
+            final int base, size, wbase, gran;
+            Sorter(CountedCompleter<?> par, double[] a, double[] w, int base,
+                   int size, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w; this.base = base; this.size = size;
+                this.wbase = wbase; this.gran = gran;
             }
-
-            public void compute() {
-                final int l = origin;
-                final int g = gran;
-                final int n = this.n;
-                final double[] a = this.a;
-                final double[] w = this.w;
-                if (n > g) {
-                    int h = n >>> 1; // half
-                    int q = n >>> 2; // lower quarter index
-                    int u = h + q;   // upper quarter
-                    FJSubSorter ls = new FJSubSorter(new Sorter(a, w, l, q,   g),
-                                                     new Sorter(a, w, l+q, h-q, g),
-                                                     new Merger(a, w, l,   q,
-                                                                l+q, h-q, l, g, null));
-                    FJSubSorter rs = new FJSubSorter(new Sorter(a, w, l + h, q,   g),
-                                                     new Sorter(a, w, l+u, n-u, g),
-                                                     new Merger(a, w, l+h, q,
-                                                                l+u, n-u, l+h, g, null));
-                    rs.fork();
-                    ls.compute();
-                    if (rs.tryUnfork()) rs.compute(); else rs.join();
-                    new Merger(w, a, l, h, l + h, n - h, l, g, null).compute();
-                } else {
-                    DualPivotQuicksort.sort(a, l, l+n-1);   // skip rangeCheck
+            public final void compute() {
+                CountedCompleter<?> s = this;
+                double[] a = this.a, w = this.w; // localize all params
+                int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
+                while (n > g) {
+                    int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
+                    Relay fc = new Relay(new Merger(s, w, a, wb, h,
+                                                    wb+h, n-h, b, g));
+                    Relay rc = new Relay(new Merger(fc, a, w, b+h, q,
+                                                    b+u, n-u, wb+h, g));
+                    new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();
+                    new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;
+                    Relay bc = new Relay(new Merger(fc, a, w, b, q,
+                                                    b+q, h-q, wb, g));
+                    new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();
+                    s = new EmptyCompleter(bc);
+                    n = q;
                 }
+                DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);
+                s.tryComplete();
             }
         }
 
-        static final class Merger extends RecursiveAction {
-            static final long serialVersionUID = 8076242187166127592L;
-            final double[] a;
-            final double[] w;
-            final int lo;
-            final int ln;
-            final int ro;
-            final int rn;
-            final int wo;
-            final int gran;
-            final Merger next;
-
-            Merger(double[] a, double[] w, int lo, int ln, int ro, int rn, int wo,
-                   int gran, Merger next) {
-                this.a = a;
-                this.w = w;
-                this.lo = lo;
-                this.ln = ln;
-                this.ro = ro;
-                this.rn = rn;
-                this.wo = wo;
-                this.gran = gran;
-                this.next = next;
+        static final class Merger extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final double[] a, w; // main and workspace arrays
+            final int lbase, lsize, rbase, rsize, wbase, gran;
+            Merger(CountedCompleter<?> par, double[] a, double[] w,
+                   int lbase, int lsize, int rbase,
+                   int rsize, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w;
+                this.lbase = lbase; this.lsize = lsize;
+                this.rbase = rbase; this.rsize = rsize;
+                this.wbase = wbase; this.gran = gran;
             }
 
-            public void compute() {
-                final double[] a = this.a;
-                final double[] w = this.w;
-                Merger rights = null;
-                int nleft = ln;
-                int nright = rn;
-                while (nleft > gran) {
-                    int lh = nleft >>> 1;
-                    int splitIndex = lo + lh;
-                    double split = a[splitIndex];
-                    int rl = 0;
-                    int rh = nright;
-                    while (rl < rh) {
-                        int mid = (rl + rh) >>> 1;
-                        if (Double.compare(split, a[ro+mid]) <= 0)
-                            rh = mid;
-                        else
-                            rl = mid + 1;
+            public final void compute() {
+                double[] a = this.a, w = this.w; // localize all params
+                int lb = this.lbase, ln = this.lsize, rb = this.rbase,
+                    rn = this.rsize, k = this.wbase, g = this.gran;
+                if (a == null || w == null || lb < 0 || rb < 0 || k < 0)
+                    throw new IllegalStateException(); // hoist checks
+                for (int lh, rh;;) {  // split larger, find point in smaller
+                    if (ln >= rn) {
+                        if (ln <= g)
+                            break;
+                        rh = rn;
+                        double split = a[(lh = ln >>> 1) + lb];
+                        for (int lo = 0; lo < rh; ) {
+                            int rm = (lo + rh) >>> 1;
+                            if (split <= a[rm + rb])
+                                rh = rm;
+                            else
+                                lo = rm + 1;
+                        }
                     }
-                    (rights = new Merger(a, w, splitIndex, nleft-lh, ro+rh,
-                                         nright-rh, wo+lh+rh, gran, rights)).fork();
-                    nleft = lh;
-                    nright = rh;
+                    else {
+                        if (rn <= g)
+                            break;
+                        lh = ln;
+                        double split = a[(rh = rn >>> 1) + rb];
+                        for (int lo = 0; lo < lh; ) {
+                            int lm = (lo + lh) >>> 1;
+                            if (split <= a[lm + lb])
+                                lh = lm;
+                            else
+                                lo = lm + 1;
+                        }
+                    }
+                    Merger m = new Merger(this, a, w, lb + lh, ln - lh,
+                                          rb + rh, rn - rh,
+                                          k + lh + rh, g);
+                    rn = rh;
+                    ln = lh;
+                    addToPendingCount(1);
+                    m.fork();
                 }
 
-                int l = lo;
-                int lFence = l + nleft;
-                int r = ro;
-                int rFence = r + nright;
-                int k = wo;
-                while (l < lFence && r < rFence) {
-                    double al = a[l];
-                    double ar = a[r];
-                    double t;
-                    if (Double.compare(al, ar) <= 0) {
-                        ++l;
-                        t = al;
-                    } else {
-                        ++r;
-                        t = ar;
+                int lf = lb + ln, rf = rb + rn; // index bounds
+                while (lb < lf && rb < rf) {
+                    double t, al, ar;
+                    if ((al = a[lb]) <= (ar = a[rb])) {
+                        lb++; t = al;
+                    }
+                    else {
+                        rb++; t = ar;
                     }
                     w[k++] = t;
                 }
-                while (l < lFence)
-                    w[k++] = a[l++];
-                while (r < rFence)
-                    w[k++] = a[r++];
-                while (rights != null) {
-                    if (rights.tryUnfork())
-                        rights.compute();
-                    else
-                        rights.join();
-                    rights = rights.next;
-                }
+                if (rb < rf)
+                    System.arraycopy(a, rb, w, k, rf - rb);
+                else if (lb < lf)
+                    System.arraycopy(a, lb, w, k, lf - lb);
+                tryComplete();
             }
         }
     } // FJDouble
 
-    /** Comparable support class */
-    static final class FJComparable {
-        static final class Sorter<T extends Comparable<? super T>> extends RecursiveAction {
-            static final long serialVersionUID = -1024003289463302522L;
-            final T[] a;
-            final T[] w;
-            final int origin;
-            final int n;
-            final int gran;
-
-            Sorter(T[] a, T[] w, int origin, int n, int gran) {
-                this.a = a;
-                this.w = w;
-                this.origin = origin;
-                this.n = n;
-                this.gran = gran;
-            }
-
-            public void compute() {
-                final int l = origin;
-                final int g = gran;
-                final int n = this.n;
-                final T[] a = this.a;
-                final T[] w = this.w;
-                if (n > g) {
-                    int h = n >>> 1;
-                    int q = n >>> 2;
-                    int u = h + q;
-                    FJSubSorter ls = new FJSubSorter(new Sorter<>(a, w, l, q,   g),
-                                                     new Sorter<>(a, w, l+q, h-q, g),
-                                                     new Merger<>(a, w, l,   q,
-                                                                  l+q, h-q, l, g, null));
-                    FJSubSorter rs = new FJSubSorter(new Sorter<>(a, w, l+h, q,   g),
-                                                     new Sorter<>(a, w, l+u, n-u, g),
-                                                     new Merger<>(a, w, l+h, q,
-                                                                  l+u, n-u, l+h, g, null));
-                    rs.fork();
-                    ls.compute();
-                    if (rs.tryUnfork()) rs.compute(); else rs.join();
-                    new Merger<>(w, a, l, h, l + h, n - h, l, g, null).compute();
-                } else {
-                    Arrays.sort(a, l, l+n);
-                }
-            }
-        }
-
-        static final class Merger<T extends Comparable<? super T>> extends RecursiveAction {
-            static final long serialVersionUID = -3989771675258379302L;
-            final T[] a;
-            final T[] w;
-            final int lo;
-            final int ln;
-            final int ro;
-            final int rn;
-            final int wo;
-            final int gran;
-            final Merger<T> next;
-
-            Merger(T[] a, T[] w, int lo, int ln, int ro, int rn, int wo,
-                   int gran, Merger<T> next) {
-                this.a = a;
-                this.w = w;
-                this.lo = lo;
-                this.ln = ln;
-                this.ro = ro;
-                this.rn = rn;
-                this.wo = wo;
-                this.gran = gran;
-                this.next = next;
-            }
-
-            public void compute() {
-                final T[] a = this.a;
-                final T[] w = this.w;
-                Merger<T> rights = null;
-                int nleft = ln;
-                int nright = rn;
-                while (nleft > gran) {
-                    int lh = nleft >>> 1;
-                    int splitIndex = lo + lh;
-                    T split = a[splitIndex];
-                    int rl = 0;
-                    int rh = nright;
-                    while (rl < rh) {
-                        int mid = (rl + rh) >>> 1;
-                        if (split.compareTo(a[ro + mid]) <= 0)
-                            rh = mid;
-                        else
-                            rl = mid + 1;
-                    }
-                    (rights = new Merger<>(a, w, splitIndex, nleft-lh, ro+rh,
-                                           nright-rh, wo+lh+rh, gran, rights)).fork();
-                    nleft = lh;
-                    nright = rh;
-                }
-
-                int l = lo;
-                int lFence = l + nleft;
-                int r = ro;
-                int rFence = r + nright;
-                int k = wo;
-                while (l < lFence && r < rFence) {
-                    T al = a[l];
-                    T ar = a[r];
-                    T t;
-                    if (al.compareTo(ar) <= 0) {++l; t=al;} else {++r; t=ar; }
-                    w[k++] = t;
-                }
-                while (l < lFence)
-                    w[k++] = a[l++];
-                while (r < rFence)
-                    w[k++] = a[r++];
-                while (rights != null) {
-                    if (rights.tryUnfork())
-                        rights.compute();
-                    else
-                        rights.join();
-                    rights = rights.next;
-                }
-            }
-        }
-    } // FJComparable
-
-    /** Object + Comparator support class */
-    static final class FJComparator {
-        static final class Sorter<T> extends RecursiveAction {
-            static final long serialVersionUID = 9191600840025808581L;
-            final T[] a;       // array to be sorted.
-            final T[] w;       // workspace for merge
-            final int origin;  // origin of the part of array we deal with
-            final int n;       // Number of elements in (sub)arrays.
-            final int gran;    // split control
-            final Comparator<? super T> cmp; // Comparator to use
-
-            Sorter(T[] a, T[] w, int origin, int n, int gran, Comparator<? super T> cmp) {
-                this.a = a;
-                this.w = w;
-                this.origin = origin;
-                this.n = n;
-                this.cmp = cmp;
-                this.gran = gran;
-            }
-
-            public void compute() {
-                final int l = origin;
-                final int g = gran;
-                final int n = this.n;
-                final T[] a = this.a;
-                final T[] w = this.w;
-                if (n > g) {
-                    int h = n >>> 1; // half
-                    int q = n >>> 2; // lower quarter index
-                    int u = h + q;   // upper quarter
-                    FJSubSorter ls = new FJSubSorter(new Sorter<>(a, w, l, q,   g, cmp),
-                                                     new Sorter<>(a, w, l+q, h-q, g, cmp),
-                                                     new Merger<>(a, w, l,   q,
-                                                                  l+q, h-q, l, g, null, cmp));
-                    FJSubSorter rs = new FJSubSorter(new Sorter<>(a, w, l + h, q,   g, cmp),
-                                                     new Sorter<>(a, w, l+u, n-u, g, cmp),
-                                                     new Merger<>(a, w, l+h, q,
-                                                                  l+u, n-u, l+h, g, null, cmp));
-                    rs.fork();
-                    ls.compute();
-                    if (rs.tryUnfork()) rs.compute(); else rs.join();
-                    new Merger<>(w, a, l, h, l + h, n - h, l, g, null, cmp).compute();
-                } else {
-                    Arrays.sort(a, l, l+n, cmp);
-                }
-            }
-        }
-
-        static final class Merger<T> extends RecursiveAction {
-            static final long serialVersionUID = -2679539040379156203L;
-            final T[] a;
-            final T[] w;
-            final int lo;
-            final int ln;
-            final int ro;
-            final int rn;
-            final int wo;
-            final int gran;
-            final Merger<T> next;
-            final Comparator<? super T> cmp;
-
-            Merger(T[] a, T[] w, int lo, int ln, int ro, int rn, int wo,
-                   int gran, Merger<T> next, Comparator<? super T> cmp) {
-                this.a = a;
-                this.w = w;
-                this.lo = lo;
-                this.ln = ln;
-                this.ro = ro;
-                this.rn = rn;
-                this.wo = wo;
-                this.gran = gran;
-                this.next = next;
-                this.cmp = cmp;
-            }
-
-            public void compute() {
-                final T[] a = this.a;
-                final T[] w = this.w;
-                Merger<T> rights = null;
-                int nleft = ln;
-                int nright = rn;
-                while (nleft > gran) {
-                    int lh = nleft >>> 1;
-                    int splitIndex = lo + lh;
-                    T split = a[splitIndex];
-                    int rl = 0;
-                    int rh = nright;
-                    while (rl < rh) {
-                        int mid = (rl + rh) >>> 1;
-                        if (cmp.compare(split, a[ro+mid]) <= 0)
-                            rh = mid;
-                        else
-                            rl = mid + 1;
-                    }
-                    (rights = new Merger<>(a, w, splitIndex, nleft-lh, ro+rh,
-                                           nright-rh, wo+lh+rh, gran, rights, cmp)).fork();
-                    nleft = lh;
-                    nright = rh;
-                }
-
-                int l = lo;
-                int lFence = l + nleft;
-                int r = ro;
-                int rFence = r + nright;
-                int k = wo;
-                while (l < lFence && r < rFence) {
-                    T al = a[l];
-                    T ar = a[r];
-                    T t;
-                    if (cmp.compare(al, ar) <= 0) {
-                        ++l;
-                        t = al;
-                    } else {
-                        ++r;
-                        t = ar;
-                    }
-                    w[k++] = t;
-                }
-                while (l < lFence)
-                    w[k++] = a[l++];
-                while (r < rFence)
-                    w[k++] = a[r++];
-                while (rights != null) {
-                    if (rights.tryUnfork())
-                        rights.compute();
-                    else
-                        rights.join();
-                    rights = rights.next;
-                }
-            }
-        }
-    } // FJComparator
-
-    /** Utility class to sort half a partitioned array */
-    private static final class FJSubSorter extends RecursiveAction {
-        static final long serialVersionUID = 9159249695527935512L;
-        final RecursiveAction left;
-        final RecursiveAction right;
-        final RecursiveAction merger;
-
-        FJSubSorter(RecursiveAction left, RecursiveAction right,
-                    RecursiveAction merger) {
-            this.left = left;
-            this.right = right;
-            this.merger = merger;
-        }
-
-        public void compute() {
-            right.fork();
-            left.invoke();
-            right.join();
-            merger.invoke();
-        }
-    }
 }
--- a/jdk/src/share/classes/java/util/ComparableTimSort.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/ComparableTimSort.java	Mon Jun 10 10:38:33 2013 +0100
@@ -86,9 +86,13 @@
     private static final int INITIAL_TMP_STORAGE_LENGTH = 256;
 
     /**
-     * Temp storage for merges.
+     * Temp storage for merges. A workspace array may optionally be
+     * provided in constructor, and if so will be used as long as it
+     * is big enough.
      */
     private Object[] tmp;
+    private int tmpBase; // base of tmp array slice
+    private int tmpLen;  // length of tmp array slice
 
     /**
      * A stack of pending runs yet to be merged.  Run i starts at
@@ -108,15 +112,27 @@
      * Creates a TimSort instance to maintain the state of an ongoing sort.
      *
      * @param a the array to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
      */
-    private ComparableTimSort(Object[] a) {
+    private ComparableTimSort(Object[] a, Object[] work, int workBase, int workLen) {
         this.a = a;
 
         // Allocate temp storage (which may be increased later if necessary)
         int len = a.length;
-        Object[] newArray = new Object[len < 2 * INITIAL_TMP_STORAGE_LENGTH ?
-                                       len >>> 1 : INITIAL_TMP_STORAGE_LENGTH];
-        tmp = newArray;
+        int tlen = (len < 2 * INITIAL_TMP_STORAGE_LENGTH) ?
+            len >>> 1 : INITIAL_TMP_STORAGE_LENGTH;
+        if (work == null || workLen < tlen || workBase + tlen > work.length) {
+            tmp = new Object[tlen];
+            tmpBase = 0;
+            tmpLen = tlen;
+        }
+        else {
+            tmp = work;
+            tmpBase = workBase;
+            tmpLen = workLen;
+        }
 
         /*
          * Allocate runs-to-be-merged stack (which cannot be expanded).  The
@@ -136,17 +152,28 @@
     }
 
     /*
-     * The next two methods (which are package private and static) constitute
-     * the entire API of this class.  Each of these methods obeys the contract
-     * of the public method with the same signature in java.util.Arrays.
+     * The next method (package private and static) constitutes the
+     * entire API of this class.
      */
 
-    static void sort(Object[] a) {
-          sort(a, 0, a.length);
-    }
+    /**
+     * Sorts the given range, using the given workspace array slice
+     * for temp storage when possible. This method is designed to be
+     * invoked from public methods (in class Arrays) after performing
+     * any necessary array bounds checks and expanding parameters into
+     * the required forms.
+     *
+     * @param a the array to be sorted
+     * @param lo the index of the first element, inclusive, to be sorted
+     * @param hi the index of the last element, exclusive, to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
+     * @since 1.8
+     */
+    static void sort(Object[] a, int lo, int hi, Object[] work, int workBase, int workLen) {
+        assert a != null && lo >= 0 && lo <= hi && hi <= a.length;
 
-    static void sort(Object[] a, int lo, int hi) {
-        rangeCheck(a.length, lo, hi);
         int nRemaining  = hi - lo;
         if (nRemaining < 2)
             return;  // Arrays of size 0 and 1 are always sorted
@@ -163,7 +190,7 @@
          * extending short natural runs to minRun elements, and merging runs
          * to maintain stack invariant.
          */
-        ComparableTimSort ts = new ComparableTimSort(a);
+        ComparableTimSort ts = new ComparableTimSort(a, work, workBase, workLen);
         int minRun = minRunLength(nRemaining);
         do {
             // Identify next run
@@ -619,11 +646,11 @@
         // Copy first run into temp array
         Object[] a = this.a; // For performance
         Object[] tmp = ensureCapacity(len1);
-        System.arraycopy(a, base1, tmp, 0, len1);
 
-        int cursor1 = 0;       // Indexes into tmp array
+        int cursor1 = tmpBase; // Indexes into tmp array
         int cursor2 = base2;   // Indexes int a
         int dest = base1;      // Indexes int a
+        System.arraycopy(a, base1, tmp, cursor1, len1);
 
         // Move first element of second run and deal with degenerate cases
         a[dest++] = a[cursor2++];
@@ -736,16 +763,17 @@
         // Copy second run into temp array
         Object[] a = this.a; // For performance
         Object[] tmp = ensureCapacity(len2);
-        System.arraycopy(a, base2, tmp, 0, len2);
+        int tmpBase = this.tmpBase;
+        System.arraycopy(a, base2, tmp, tmpBase, len2);
 
         int cursor1 = base1 + len1 - 1;  // Indexes into a
-        int cursor2 = len2 - 1;          // Indexes into tmp array
+        int cursor2 = tmpBase + len2 - 1; // Indexes into tmp array
         int dest = base2 + len2 - 1;     // Indexes into a
 
         // Move last element of first run and deal with degenerate cases
         a[dest--] = a[cursor1--];
         if (--len1 == 0) {
-            System.arraycopy(tmp, 0, a, dest - (len2 - 1), len2);
+            System.arraycopy(tmp, tmpBase, a, dest - (len2 - 1), len2);
             return;
         }
         if (len2 == 1) {
@@ -803,7 +831,7 @@
                 if (--len2 == 1)
                     break outer;
 
-                count2 = len2 - gallopLeft((Comparable) a[cursor1], tmp, 0, len2, len2 - 1);
+                count2 = len2 - gallopLeft((Comparable) a[cursor1], tmp, tmpBase, len2, len2 - 1);
                 if (count2 != 0) {
                     dest -= count2;
                     cursor2 -= count2;
@@ -835,7 +863,7 @@
         } else {
             assert len1 == 0;
             assert len2 > 0;
-            System.arraycopy(tmp, 0, a, dest - (len2 - 1), len2);
+            System.arraycopy(tmp, tmpBase, a, dest - (len2 - 1), len2);
         }
     }
 
@@ -848,7 +876,7 @@
      * @return tmp, whether or not it grew
      */
     private Object[]  ensureCapacity(int minCapacity) {
-        if (tmp.length < minCapacity) {
+        if (tmpLen < minCapacity) {
             // Compute smallest power of 2 > minCapacity
             int newSize = minCapacity;
             newSize |= newSize >> 1;
@@ -863,30 +891,13 @@
             else
                 newSize = Math.min(newSize, a.length >>> 1);
 
+            @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"})
             Object[] newArray = new Object[newSize];
             tmp = newArray;
+            tmpLen = newSize;
+            tmpBase = 0;
         }
         return tmp;
     }
 
-    /**
-     * Checks that fromIndex and toIndex are in range, and throws an
-     * appropriate exception if they aren't.
-     *
-     * @param arrayLen the length of the array
-     * @param fromIndex the index of the first element of the range
-     * @param toIndex the index after the last element of the range
-     * @throws IllegalArgumentException if fromIndex > toIndex
-     * @throws ArrayIndexOutOfBoundsException if fromIndex < 0
-     *         or toIndex > arrayLen
-     */
-    private static void rangeCheck(int arrayLen, int fromIndex, int toIndex) {
-        if (fromIndex > toIndex)
-            throw new IllegalArgumentException("fromIndex(" + fromIndex +
-                       ") > toIndex(" + toIndex+")");
-        if (fromIndex < 0)
-            throw new ArrayIndexOutOfBoundsException(fromIndex);
-        if (toIndex > arrayLen)
-            throw new ArrayIndexOutOfBoundsException(toIndex);
-    }
 }
--- a/jdk/src/share/classes/java/util/DualPivotQuicksort.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/DualPivotQuicksort.java	Mon Jun 10 10:38:33 2013 +0100
@@ -32,6 +32,11 @@
  * quicksorts to degrade to quadratic performance, and is typically
  * faster than traditional (one-pivot) Quicksort implementations.
  *
+ * All exposed methods are package-private, designed to be invoked
+ * from public methods (in class Arrays) after performing any
+ * necessary array bounds checks and expanding parameters into the
+ * required forms.
+ *
  * @author Vladimir Yaroslavskiy
  * @author Jon Bentley
  * @author Josh Bloch
@@ -89,22 +94,18 @@
      */
 
     /**
-     * Sorts the specified array.
-     *
-     * @param a the array to be sorted
-     */
-    public static void sort(int[] a) {
-        sort(a, 0, a.length - 1);
-    }
-
-    /**
-     * Sorts the specified range of the array.
+     * Sorts the specified range of the array using the given
+     * workspace array slice if possible for merging
      *
      * @param a the array to be sorted
      * @param left the index of the first element, inclusive, to be sorted
      * @param right the index of the last element, inclusive, to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
      */
-    public static void sort(int[] a, int left, int right) {
+    static void sort(int[] a, int left, int right,
+                     int[] work, int workBase, int workLen) {
         // Use Quicksort on small arrays
         if (right - left < QUICKSORT_THRESHOLD) {
             sort(a, left, right, true);
@@ -147,24 +148,35 @@
         }
 
         // Check special cases
+        // Implementation note: variable "right" is increased by 1.
         if (run[count] == right++) { // The last run contains one element
             run[++count] = right;
         } else if (count == 1) { // The array is already sorted
             return;
         }
 
-        /*
-         * Create temporary array, which is used for merging.
-         * Implementation note: variable "right" is increased by 1.
-         */
-        int[] b; byte odd = 0;
+        // Determine alternation base for merge
+        byte odd = 0;
         for (int n = 1; (n <<= 1) < count; odd ^= 1);
 
+        // Use or create temporary array b for merging
+        int[] b;                 // temp array; alternates with a
+        int ao, bo;              // array offsets from 'left'
+        int blen = right - left; // space needed for b
+        if (work == null || workLen < blen || workBase + blen > work.length) {
+            work = new int[blen];
+            workBase = 0;
+        }
         if (odd == 0) {
-            b = a; a = new int[b.length];
-            for (int i = left - 1; ++i < right; a[i] = b[i]);
+            System.arraycopy(a, left, work, workBase, blen);
+            b = a;
+            bo = 0;
+            a = work;
+            ao = workBase - left;
         } else {
-            b = new int[a.length];
+            b = work;
+            ao = 0;
+            bo = workBase - left;
         }
 
         // Merging
@@ -172,21 +184,22 @@
             for (int k = (last = 0) + 2; k <= count; k += 2) {
                 int hi = run[k], mi = run[k - 1];
                 for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
-                    if (q >= hi || p < mi && a[p] <= a[q]) {
-                        b[i] = a[p++];
+                    if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) {
+                        b[i + bo] = a[p++ + ao];
                     } else {
-                        b[i] = a[q++];
+                        b[i + bo] = a[q++ + ao];
                     }
                 }
                 run[++last] = hi;
             }
             if ((count & 1) != 0) {
                 for (int i = right, lo = run[count - 1]; --i >= lo;
-                    b[i] = a[i]
+                    b[i + bo] = a[i + ao]
                 );
                 run[++last] = right;
             }
             int[] t = a; a = b; b = t;
+            int o = ao; ao = bo; bo = o;
         }
     }
 
@@ -529,22 +542,18 @@
     }
 
     /**
-     * Sorts the specified array.
-     *
-     * @param a the array to be sorted
-     */
-    public static void sort(long[] a) {
-        sort(a, 0, a.length - 1);
-    }
-
-    /**
-     * Sorts the specified range of the array.
+     * Sorts the specified range of the array using the given
+     * workspace array slice if possible for merging
      *
      * @param a the array to be sorted
      * @param left the index of the first element, inclusive, to be sorted
      * @param right the index of the last element, inclusive, to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
      */
-    public static void sort(long[] a, int left, int right) {
+    static void sort(long[] a, int left, int right,
+                     long[] work, int workBase, int workLen) {
         // Use Quicksort on small arrays
         if (right - left < QUICKSORT_THRESHOLD) {
             sort(a, left, right, true);
@@ -587,24 +596,35 @@
         }
 
         // Check special cases
+        // Implementation note: variable "right" is increased by 1.
         if (run[count] == right++) { // The last run contains one element
             run[++count] = right;
         } else if (count == 1) { // The array is already sorted
             return;
         }
 
-        /*
-         * Create temporary array, which is used for merging.
-         * Implementation note: variable "right" is increased by 1.
-         */
-        long[] b; byte odd = 0;
+        // Determine alternation base for merge
+        byte odd = 0;
         for (int n = 1; (n <<= 1) < count; odd ^= 1);
 
+        // Use or create temporary array b for merging
+        long[] b;                 // temp array; alternates with a
+        int ao, bo;              // array offsets from 'left'
+        int blen = right - left; // space needed for b
+        if (work == null || workLen < blen || workBase + blen > work.length) {
+            work = new long[blen];
+            workBase = 0;
+        }
         if (odd == 0) {
-            b = a; a = new long[b.length];
-            for (int i = left - 1; ++i < right; a[i] = b[i]);
+            System.arraycopy(a, left, work, workBase, blen);
+            b = a;
+            bo = 0;
+            a = work;
+            ao = workBase - left;
         } else {
-            b = new long[a.length];
+            b = work;
+            ao = 0;
+            bo = workBase - left;
         }
 
         // Merging
@@ -612,21 +632,22 @@
             for (int k = (last = 0) + 2; k <= count; k += 2) {
                 int hi = run[k], mi = run[k - 1];
                 for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
-                    if (q >= hi || p < mi && a[p] <= a[q]) {
-                        b[i] = a[p++];
+                    if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) {
+                        b[i + bo] = a[p++ + ao];
                     } else {
-                        b[i] = a[q++];
+                        b[i + bo] = a[q++ + ao];
                     }
                 }
                 run[++last] = hi;
             }
             if ((count & 1) != 0) {
                 for (int i = right, lo = run[count - 1]; --i >= lo;
-                    b[i] = a[i]
+                    b[i + bo] = a[i + ao]
                 );
                 run[++last] = right;
             }
             long[] t = a; a = b; b = t;
+            int o = ao; ao = bo; bo = o;
         }
     }
 
@@ -969,22 +990,18 @@
     }
 
     /**
-     * Sorts the specified array.
-     *
-     * @param a the array to be sorted
-     */
-    public static void sort(short[] a) {
-        sort(a, 0, a.length - 1);
-    }
-
-    /**
-     * Sorts the specified range of the array.
+     * Sorts the specified range of the array using the given
+     * workspace array slice if possible for merging
      *
      * @param a the array to be sorted
      * @param left the index of the first element, inclusive, to be sorted
      * @param right the index of the last element, inclusive, to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
      */
-    public static void sort(short[] a, int left, int right) {
+    static void sort(short[] a, int left, int right,
+                     short[] work, int workBase, int workLen) {
         // Use counting sort on large arrays
         if (right - left > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) {
             int[] count = new int[NUM_SHORT_VALUES];
@@ -1002,7 +1019,7 @@
                 } while (--s > 0);
             }
         } else { // Use Dual-Pivot Quicksort on small arrays
-            doSort(a, left, right);
+            doSort(a, left, right, work, workBase, workLen);
         }
     }
 
@@ -1015,8 +1032,12 @@
      * @param a the array to be sorted
      * @param left the index of the first element, inclusive, to be sorted
      * @param right the index of the last element, inclusive, to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
      */
-    private static void doSort(short[] a, int left, int right) {
+    private static void doSort(short[] a, int left, int right,
+                               short[] work, int workBase, int workLen) {
         // Use Quicksort on small arrays
         if (right - left < QUICKSORT_THRESHOLD) {
             sort(a, left, right, true);
@@ -1059,24 +1080,35 @@
         }
 
         // Check special cases
+        // Implementation note: variable "right" is increased by 1.
         if (run[count] == right++) { // The last run contains one element
             run[++count] = right;
         } else if (count == 1) { // The array is already sorted
             return;
         }
 
-        /*
-         * Create temporary array, which is used for merging.
-         * Implementation note: variable "right" is increased by 1.
-         */
-        short[] b; byte odd = 0;
+        // Determine alternation base for merge
+        byte odd = 0;
         for (int n = 1; (n <<= 1) < count; odd ^= 1);
 
+        // Use or create temporary array b for merging
+        short[] b;                 // temp array; alternates with a
+        int ao, bo;              // array offsets from 'left'
+        int blen = right - left; // space needed for b
+        if (work == null || workLen < blen || workBase + blen > work.length) {
+            work = new short[blen];
+            workBase = 0;
+        }
         if (odd == 0) {
-            b = a; a = new short[b.length];
-            for (int i = left - 1; ++i < right; a[i] = b[i]);
+            System.arraycopy(a, left, work, workBase, blen);
+            b = a;
+            bo = 0;
+            a = work;
+            ao = workBase - left;
         } else {
-            b = new short[a.length];
+            b = work;
+            ao = 0;
+            bo = workBase - left;
         }
 
         // Merging
@@ -1084,21 +1116,22 @@
             for (int k = (last = 0) + 2; k <= count; k += 2) {
                 int hi = run[k], mi = run[k - 1];
                 for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
-                    if (q >= hi || p < mi && a[p] <= a[q]) {
-                        b[i] = a[p++];
+                    if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) {
+                        b[i + bo] = a[p++ + ao];
                     } else {
-                        b[i] = a[q++];
+                        b[i + bo] = a[q++ + ao];
                     }
                 }
                 run[++last] = hi;
             }
             if ((count & 1) != 0) {
                 for (int i = right, lo = run[count - 1]; --i >= lo;
-                    b[i] = a[i]
+                    b[i + bo] = a[i + ao]
                 );
                 run[++last] = right;
             }
             short[] t = a; a = b; b = t;
+            int o = ao; ao = bo; bo = o;
         }
     }
 
@@ -1441,22 +1474,18 @@
     }
 
     /**
-     * Sorts the specified array.
-     *
-     * @param a the array to be sorted
-     */
-    public static void sort(char[] a) {
-        sort(a, 0, a.length - 1);
-    }
-
-    /**
-     * Sorts the specified range of the array.
+     * Sorts the specified range of the array using the given
+     * workspace array slice if possible for merging
      *
      * @param a the array to be sorted
      * @param left the index of the first element, inclusive, to be sorted
      * @param right the index of the last element, inclusive, to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
      */
-    public static void sort(char[] a, int left, int right) {
+    static void sort(char[] a, int left, int right,
+                     char[] work, int workBase, int workLen) {
         // Use counting sort on large arrays
         if (right - left > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) {
             int[] count = new int[NUM_CHAR_VALUES];
@@ -1474,7 +1503,7 @@
                 } while (--s > 0);
             }
         } else { // Use Dual-Pivot Quicksort on small arrays
-            doSort(a, left, right);
+            doSort(a, left, right, work, workBase, workLen);
         }
     }
 
@@ -1487,8 +1516,12 @@
      * @param a the array to be sorted
      * @param left the index of the first element, inclusive, to be sorted
      * @param right the index of the last element, inclusive, to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
      */
-    private static void doSort(char[] a, int left, int right) {
+    private static void doSort(char[] a, int left, int right,
+                               char[] work, int workBase, int workLen) {
         // Use Quicksort on small arrays
         if (right - left < QUICKSORT_THRESHOLD) {
             sort(a, left, right, true);
@@ -1531,24 +1564,35 @@
         }
 
         // Check special cases
+        // Implementation note: variable "right" is increased by 1.
         if (run[count] == right++) { // The last run contains one element
             run[++count] = right;
         } else if (count == 1) { // The array is already sorted
             return;
         }
 
-        /*
-         * Create temporary array, which is used for merging.
-         * Implementation note: variable "right" is increased by 1.
-         */
-        char[] b; byte odd = 0;
+        // Determine alternation base for merge
+        byte odd = 0;
         for (int n = 1; (n <<= 1) < count; odd ^= 1);
 
+        // Use or create temporary array b for merging
+        char[] b;                 // temp array; alternates with a
+        int ao, bo;              // array offsets from 'left'
+        int blen = right - left; // space needed for b
+        if (work == null || workLen < blen || workBase + blen > work.length) {
+            work = new char[blen];
+            workBase = 0;
+        }
         if (odd == 0) {
-            b = a; a = new char[b.length];
-            for (int i = left - 1; ++i < right; a[i] = b[i]);
+            System.arraycopy(a, left, work, workBase, blen);
+            b = a;
+            bo = 0;
+            a = work;
+            ao = workBase - left;
         } else {
-            b = new char[a.length];
+            b = work;
+            ao = 0;
+            bo = workBase - left;
         }
 
         // Merging
@@ -1556,21 +1600,22 @@
             for (int k = (last = 0) + 2; k <= count; k += 2) {
                 int hi = run[k], mi = run[k - 1];
                 for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
-                    if (q >= hi || p < mi && a[p] <= a[q]) {
-                        b[i] = a[p++];
+                    if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) {
+                        b[i + bo] = a[p++ + ao];
                     } else {
-                        b[i] = a[q++];
+                        b[i + bo] = a[q++ + ao];
                     }
                 }
                 run[++last] = hi;
             }
             if ((count & 1) != 0) {
                 for (int i = right, lo = run[count - 1]; --i >= lo;
-                    b[i] = a[i]
+                    b[i + bo] = a[i + ao]
                 );
                 run[++last] = right;
             }
             char[] t = a; a = b; b = t;
+            int o = ao; ao = bo; bo = o;
         }
     }
 
@@ -1916,22 +1961,13 @@
     private static final int NUM_BYTE_VALUES = 1 << 8;
 
     /**
-     * Sorts the specified array.
-     *
-     * @param a the array to be sorted
-     */
-    public static void sort(byte[] a) {
-        sort(a, 0, a.length - 1);
-    }
-
-    /**
      * Sorts the specified range of the array.
      *
      * @param a the array to be sorted
      * @param left the index of the first element, inclusive, to be sorted
      * @param right the index of the last element, inclusive, to be sorted
      */
-    public static void sort(byte[] a, int left, int right) {
+    static void sort(byte[] a, int left, int right) {
         // Use counting sort on large arrays
         if (right - left > COUNTING_SORT_THRESHOLD_FOR_BYTE) {
             int[] count = new int[NUM_BYTE_VALUES];
@@ -1963,22 +1999,18 @@
     }
 
     /**
-     * Sorts the specified array.
-     *
-     * @param a the array to be sorted
-     */
-    public static void sort(float[] a) {
-        sort(a, 0, a.length - 1);
-    }
-
-    /**
-     * Sorts the specified range of the array.
+     * Sorts the specified range of the array using the given
+     * workspace array slice if possible for merging
      *
      * @param a the array to be sorted
      * @param left the index of the first element, inclusive, to be sorted
      * @param right the index of the last element, inclusive, to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
      */
-    public static void sort(float[] a, int left, int right) {
+    static void sort(float[] a, int left, int right,
+                     float[] work, int workBase, int workLen) {
         /*
          * Phase 1: Move NaNs to the end of the array.
          */
@@ -1997,7 +2029,7 @@
         /*
          * Phase 2: Sort everything except NaNs (which are already in place).
          */
-        doSort(a, left, right);
+        doSort(a, left, right, work, workBase, workLen);
 
         /*
          * Phase 3: Place negative zeros before positive zeros.
@@ -2064,8 +2096,12 @@
      * @param a the array to be sorted
      * @param left the index of the first element, inclusive, to be sorted
      * @param right the index of the last element, inclusive, to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
      */
-    private static void doSort(float[] a, int left, int right) {
+    private static void doSort(float[] a, int left, int right,
+                               float[] work, int workBase, int workLen) {
         // Use Quicksort on small arrays
         if (right - left < QUICKSORT_THRESHOLD) {
             sort(a, left, right, true);
@@ -2108,24 +2144,35 @@
         }
 
         // Check special cases
+        // Implementation note: variable "right" is increased by 1.
         if (run[count] == right++) { // The last run contains one element
             run[++count] = right;
         } else if (count == 1) { // The array is already sorted
             return;
         }
 
-        /*
-         * Create temporary array, which is used for merging.
-         * Implementation note: variable "right" is increased by 1.
-         */
-        float[] b; byte odd = 0;
+        // Determine alternation base for merge
+        byte odd = 0;
         for (int n = 1; (n <<= 1) < count; odd ^= 1);
 
+        // Use or create temporary array b for merging
+        float[] b;                 // temp array; alternates with a
+        int ao, bo;              // array offsets from 'left'
+        int blen = right - left; // space needed for b
+        if (work == null || workLen < blen || workBase + blen > work.length) {
+            work = new float[blen];
+            workBase = 0;
+        }
         if (odd == 0) {
-            b = a; a = new float[b.length];
-            for (int i = left - 1; ++i < right; a[i] = b[i]);
+            System.arraycopy(a, left, work, workBase, blen);
+            b = a;
+            bo = 0;
+            a = work;
+            ao = workBase - left;
         } else {
-            b = new float[a.length];
+            b = work;
+            ao = 0;
+            bo = workBase - left;
         }
 
         // Merging
@@ -2133,21 +2180,22 @@
             for (int k = (last = 0) + 2; k <= count; k += 2) {
                 int hi = run[k], mi = run[k - 1];
                 for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
-                    if (q >= hi || p < mi && a[p] <= a[q]) {
-                        b[i] = a[p++];
+                    if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) {
+                        b[i + bo] = a[p++ + ao];
                     } else {
-                        b[i] = a[q++];
+                        b[i + bo] = a[q++ + ao];
                     }
                 }
                 run[++last] = hi;
             }
             if ((count & 1) != 0) {
                 for (int i = right, lo = run[count - 1]; --i >= lo;
-                    b[i] = a[i]
+                    b[i + bo] = a[i + ao]
                 );
                 run[++last] = right;
             }
             float[] t = a; a = b; b = t;
+            int o = ao; ao = bo; bo = o;
         }
     }
 
@@ -2490,22 +2538,18 @@
     }
 
     /**
-     * Sorts the specified array.
-     *
-     * @param a the array to be sorted
-     */
-    public static void sort(double[] a) {
-        sort(a, 0, a.length - 1);
-    }
-
-    /**
-     * Sorts the specified range of the array.
+     * Sorts the specified range of the array using the given
+     * workspace array slice if possible for merging
      *
      * @param a the array to be sorted
      * @param left the index of the first element, inclusive, to be sorted
      * @param right the index of the last element, inclusive, to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
      */
-    public static void sort(double[] a, int left, int right) {
+    static void sort(double[] a, int left, int right,
+                     double[] work, int workBase, int workLen) {
         /*
          * Phase 1: Move NaNs to the end of the array.
          */
@@ -2524,7 +2568,7 @@
         /*
          * Phase 2: Sort everything except NaNs (which are already in place).
          */
-        doSort(a, left, right);
+        doSort(a, left, right, work, workBase, workLen);
 
         /*
          * Phase 3: Place negative zeros before positive zeros.
@@ -2591,8 +2635,12 @@
      * @param a the array to be sorted
      * @param left the index of the first element, inclusive, to be sorted
      * @param right the index of the last element, inclusive, to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
      */
-    private static void doSort(double[] a, int left, int right) {
+    private static void doSort(double[] a, int left, int right,
+                               double[] work, int workBase, int workLen) {
         // Use Quicksort on small arrays
         if (right - left < QUICKSORT_THRESHOLD) {
             sort(a, left, right, true);
@@ -2635,24 +2683,35 @@
         }
 
         // Check special cases
+        // Implementation note: variable "right" is increased by 1.
         if (run[count] == right++) { // The last run contains one element
             run[++count] = right;
         } else if (count == 1) { // The array is already sorted
             return;
         }
 
-        /*
-         * Create temporary array, which is used for merging.
-         * Implementation note: variable "right" is increased by 1.
-         */
-        double[] b; byte odd = 0;
+        // Determine alternation base for merge
+        byte odd = 0;
         for (int n = 1; (n <<= 1) < count; odd ^= 1);
 
+        // Use or create temporary array b for merging
+        double[] b;                 // temp array; alternates with a
+        int ao, bo;              // array offsets from 'left'
+        int blen = right - left; // space needed for b
+        if (work == null || workLen < blen || workBase + blen > work.length) {
+            work = new double[blen];
+            workBase = 0;
+        }
         if (odd == 0) {
-            b = a; a = new double[b.length];
-            for (int i = left - 1; ++i < right; a[i] = b[i]);
+            System.arraycopy(a, left, work, workBase, blen);
+            b = a;
+            bo = 0;
+            a = work;
+            ao = workBase - left;
         } else {
-            b = new double[a.length];
+            b = work;
+            ao = 0;
+            bo = workBase - left;
         }
 
         // Merging
@@ -2660,21 +2719,22 @@
             for (int k = (last = 0) + 2; k <= count; k += 2) {
                 int hi = run[k], mi = run[k - 1];
                 for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
-                    if (q >= hi || p < mi && a[p] <= a[q]) {
-                        b[i] = a[p++];
+                    if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) {
+                        b[i + bo] = a[p++ + ao];
                     } else {
-                        b[i] = a[q++];
+                        b[i + bo] = a[q++ + ao];
                     }
                 }
                 run[++last] = hi;
             }
             if ((count & 1) != 0) {
                 for (int i = right, lo = run[count - 1]; --i >= lo;
-                    b[i] = a[i]
+                    b[i + bo] = a[i + ao]
                 );
                 run[++last] = right;
             }
             double[] t = a; a = b; b = t;
+            int o = ao; ao = bo; bo = o;
         }
     }
 
--- a/jdk/src/share/classes/java/util/Formatter.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/Formatter.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -2807,10 +2807,10 @@
                 cal = Calendar.getInstance(l == null ? Locale.US : l);
                 cal.setTime((Date)arg);
             } else if (arg instanceof Calendar) {
-                cal = (Calendar) ((Calendar)arg).clone();
+                cal = (Calendar) ((Calendar) arg).clone();
                 cal.setLenient(true);
             } else if (arg instanceof TemporalAccessor) {
-                print((TemporalAccessor)arg, c, l);
+                print((TemporalAccessor) arg, c, l);
                 return;
             } else {
                 failConversion(c, arg);
@@ -3242,13 +3242,10 @@
                 int prec = (precision == -1 ? 6 : precision);
 
                 FormattedFloatingDecimal fd
-                    = new FormattedFloatingDecimal(value, prec,
-                        FormattedFloatingDecimal.Form.SCIENTIFIC);
-
-                char[] v = new char[MAX_FD_CHARS];
-                int len = fd.getChars(v);
-
-                char[] mant = addZeros(mantissa(v, len), prec);
+                        = FormattedFloatingDecimal.valueOf(value, prec,
+                          FormattedFloatingDecimal.Form.SCIENTIFIC);
+
+                char[] mant = addZeros(fd.getMantissa(), prec);
 
                 // If the precision is zero and the '#' flag is set, add the
                 // requested decimal point.
@@ -3256,7 +3253,7 @@
                     mant = addDot(mant);
 
                 char[] exp = (value == 0.0)
-                    ? new char[] {'+','0','0'} : exponent(v, len);
+                    ? new char[] {'+','0','0'} : fd.getExponent();
 
                 int newW = width;
                 if (width != -1)
@@ -3279,15 +3276,10 @@
                 int prec = (precision == -1 ? 6 : precision);
 
                 FormattedFloatingDecimal fd
-                    = new FormattedFloatingDecimal(value, prec,
-                        FormattedFloatingDecimal.Form.DECIMAL_FLOAT);
-
-                // MAX_FD_CHARS + 1 (round?)
-                char[] v = new char[MAX_FD_CHARS + 1
-                                   + Math.abs(fd.getExponent())];
-                int len = fd.getChars(v);
-
-                char[] mant = addZeros(mantissa(v, len), prec);
+                        = FormattedFloatingDecimal.valueOf(value, prec,
+                          FormattedFloatingDecimal.Form.DECIMAL_FLOAT);
+
+                char[] mant = addZeros(fd.getMantissa(), prec);
 
                 // If the precision is zero and the '#' flag is set, add the
                 // requested decimal point.
@@ -3306,22 +3298,17 @@
                     prec = 1;
 
                 FormattedFloatingDecimal fd
-                    = new FormattedFloatingDecimal(value, prec,
-                        FormattedFloatingDecimal.Form.GENERAL);
-
-                // MAX_FD_CHARS + 1 (round?)
-                char[] v = new char[MAX_FD_CHARS + 1
-                                   + Math.abs(fd.getExponent())];
-                int len = fd.getChars(v);
-
-                char[] exp = exponent(v, len);
+                        = FormattedFloatingDecimal.valueOf(value, prec,
+                          FormattedFloatingDecimal.Form.GENERAL);
+
+                char[] exp = fd.getExponent();
                 if (exp != null) {
                     prec -= 1;
                 } else {
                     prec = prec - (value == 0 ? 0 : fd.getExponentRounded()) - 1;
                 }
 
-                char[] mant = addZeros(mantissa(v, len), prec);
+                char[] mant = addZeros(fd.getMantissa(), prec);
                 // If the precision is zero and the '#' flag is set, add the
                 // requested decimal point.
                 if (f.contains(Flags.ALTERNATE) && (prec == 0))
@@ -3380,30 +3367,6 @@
             }
         }
 
-        private char[] mantissa(char[] v, int len) {
-            int i;
-            for (i = 0; i < len; i++) {
-                if (v[i] == 'e')
-                    break;
-            }
-            char[] tmp = new char[i];
-            System.arraycopy(v, 0, tmp, 0, i);
-            return tmp;
-        }
-
-        private char[] exponent(char[] v, int len) {
-            int i;
-            for (i = len - 1; i >= 0; i--) {
-                if (v[i] == 'e')
-                    break;
-            }
-            if (i == -1)
-                return null;
-            char[] tmp = new char[len - i - 1];
-            System.arraycopy(v, i + 1, tmp, 0, len - i - 1);
-            return tmp;
-        }
-
         // Add zeros to the requested precision.
         private char[] addZeros(char[] v, int prec) {
             // Look for the dot.  If we don't find one, the we'll need to add
--- a/jdk/src/share/classes/java/util/HashMap.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/HashMap.java	Mon Jun 10 10:38:33 2013 +0100
@@ -26,6 +26,8 @@
 package java.util;
 
 import java.io.*;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
 import java.util.function.Consumer;
 import java.util.function.BiFunction;
 import java.util.function.Function;
@@ -126,7 +128,7 @@
  */
 
 public class HashMap<K,V>
-    extends AbstractMap<K,V>
+        extends AbstractMap<K,V>
     implements Map<K,V>, Cloneable, Serializable
 {
 
@@ -150,12 +152,12 @@
     /**
      * An empty table instance to share when the table is not inflated.
      */
-    static final Entry<?,?>[] EMPTY_TABLE = {};
+    static final Object[] EMPTY_TABLE = {};
 
     /**
      * The table, resized as necessary. Length MUST Always be a power of two.
      */
-    transient Entry<?,?>[] table = EMPTY_TABLE;
+    transient Object[] table = EMPTY_TABLE;
 
     /**
      * The number of key-value mappings contained in this map.
@@ -186,10 +188,10 @@
      */
     transient int modCount;
 
+    /**
+     * Holds values which can't be initialized until after VM is booted.
+     */
     private static class Holder {
-         /**
-         *
-         */
         static final sun.misc.Unsafe UNSAFE;
 
         /**
@@ -198,22 +200,616 @@
          */
         static final long HASHSEED_OFFSET;
 
+        static final boolean USE_HASHSEED;
+
         static {
-            try {
-                UNSAFE = sun.misc.Unsafe.getUnsafe();
-                HASHSEED_OFFSET = UNSAFE.objectFieldOffset(
-                    HashMap.class.getDeclaredField("hashSeed"));
-            } catch (NoSuchFieldException | SecurityException e) {
-                throw new InternalError("Failed to record hashSeed offset", e);
+            String hashSeedProp = java.security.AccessController.doPrivileged(
+                    new sun.security.action.GetPropertyAction(
+                        "jdk.map.useRandomSeed"));
+            boolean localBool = (null != hashSeedProp)
+                    ? Boolean.parseBoolean(hashSeedProp) : false;
+            USE_HASHSEED = localBool;
+
+            if (USE_HASHSEED) {
+                try {
+                    UNSAFE = sun.misc.Unsafe.getUnsafe();
+                    HASHSEED_OFFSET = UNSAFE.objectFieldOffset(
+                        HashMap.class.getDeclaredField("hashSeed"));
+                } catch (NoSuchFieldException | SecurityException e) {
+                    throw new InternalError("Failed to record hashSeed offset", e);
+                }
+            } else {
+                UNSAFE = null;
+                HASHSEED_OFFSET = 0;
             }
         }
     }
 
-    /**
+    /*
      * A randomizing value associated with this instance that is applied to
      * hash code of keys to make hash collisions harder to find.
+     *
+     * Non-final so it can be set lazily, but be sure not to set more than once.
      */
-    transient final int hashSeed = sun.misc.Hashing.randomHashSeed(this);
+    transient final int hashSeed;
+
+    /*
+     * TreeBin/TreeNode code from CHM doesn't handle the null key.  Store the
+     * null key entry here.
+     */
+    transient Entry<K,V> nullKeyEntry = null;
+
+    /*
+     * In order to improve performance under high hash-collision conditions,
+     * HashMap will switch to storing a bin's entries in a balanced tree
+     * (TreeBin) instead of a linked-list once the number of entries in the bin
+     * passes a certain threshold (TreeBin.TREE_THRESHOLD), if at least one of
+     * the keys in the bin implements Comparable.  This technique is borrowed
+     * from ConcurrentHashMap.
+     */
+
+    /*
+     * Code based on CHMv8
+     *
+     * Node type for TreeBin
+     */
+    final static class TreeNode<K,V> {
+        TreeNode parent;  // red-black tree links
+        TreeNode left;
+        TreeNode right;
+        TreeNode prev;    // needed to unlink next upon deletion
+        boolean red;
+        final HashMap.Entry<K,V> entry;
+
+        TreeNode(HashMap.Entry<K,V> entry, Object next, TreeNode parent) {
+            this.entry = entry;
+            this.entry.next = next;
+            this.parent = parent;
+        }
+    }
+
+    /**
+     * Returns a Class for the given object of the form "class C
+     * implements Comparable<C>", if one exists, else null.  See the TreeBin
+     * docs, below, for explanation.
+     */
+    static Class<?> comparableClassFor(Object x) {
+        Class<?> c, s, cmpc; Type[] ts, as; Type t; ParameterizedType p;
+        if ((c = x.getClass()) == String.class) // bypass checks
+            return c;
+        if ((cmpc = Comparable.class).isAssignableFrom(c)) {
+            while (cmpc.isAssignableFrom(s = c.getSuperclass()))
+                c = s; // find topmost comparable class
+            if ((ts  = c.getGenericInterfaces()) != null) {
+                for (int i = 0; i < ts.length; ++i) {
+                    if (((t = ts[i]) instanceof ParameterizedType) &&
+                        ((p = (ParameterizedType)t).getRawType() == cmpc) &&
+                        (as = p.getActualTypeArguments()) != null &&
+                        as.length == 1 && as[0] == c) // type arg is c
+                        return c;
+                }
+            }
+        }
+        return null;
+    }
+
+    /*
+     * Code based on CHMv8
+     *
+     * A specialized form of red-black tree for use in bins
+     * whose size exceeds a threshold.
+     *
+     * TreeBins use a special form of comparison for search and
+     * related operations (which is the main reason we cannot use
+     * existing collections such as TreeMaps). TreeBins contain
+     * Comparable elements, but may contain others, as well as
+     * elements that are Comparable but not necessarily Comparable<T>
+     * for the same T, so we cannot invoke compareTo among them. To
+     * handle this, the tree is ordered primarily by hash value, then
+     * by Comparable.compareTo order if applicable.  On lookup at a
+     * node, if elements are not comparable or compare as 0 then both
+     * left and right children may need to be searched in the case of
+     * tied hash values. (This corresponds to the full list search
+     * that would be necessary if all elements were non-Comparable and
+     * had tied hashes.)  The red-black balancing code is updated from
+     * pre-jdk-collections
+     * (http://gee.cs.oswego.edu/dl/classes/collections/RBCell.java)
+     * based in turn on Cormen, Leiserson, and Rivest "Introduction to
+     * Algorithms" (CLR).
+     */
+    final class TreeBin {
+        /*
+         * The bin count threshold for using a tree rather than list for a bin. The
+         * value reflects the approximate break-even point for using tree-based
+         * operations.
+         */
+        static final int TREE_THRESHOLD = 16;
+
+        TreeNode<K,V> root;  // root of tree
+        TreeNode<K,V> first; // head of next-pointer list
+
+        /*
+         * Split a TreeBin into lo and hi parts and install in given table.
+         *
+         * Existing Entrys are re-used, which maintains the before/after links for
+         * LinkedHashMap.Entry.
+         *
+         * No check for Comparable, though this is the same as CHM.
+         */
+        final void splitTreeBin(Object[] newTable, int i, TreeBin loTree, TreeBin hiTree) {
+            TreeBin oldTree = this;
+            int bit = newTable.length >>> 1;
+            int loCount = 0, hiCount = 0;
+            TreeNode<K,V> e = oldTree.first;
+            TreeNode<K,V> next;
+
+            // This method is called when the table has just increased capacity,
+            // so indexFor() is now taking one additional bit of hash into
+            // account ("bit").  Entries in this TreeBin now belong in one of
+            // two bins, "i" or "i+bit", depending on if the new top bit of the
+            // hash is set.  The trees for the two bins are loTree and hiTree.
+            // If either tree ends up containing fewer than TREE_THRESHOLD
+            // entries, it is converted back to a linked list.
+            while (e != null) {
+                // Save entry.next - it will get overwritten in putTreeNode()
+                next = (TreeNode<K,V>)e.entry.next;
+
+                int h = e.entry.hash;
+                K k = (K) e.entry.key;
+                V v = e.entry.value;
+                if ((h & bit) == 0) {
+                    ++loCount;
+                    // Re-using e.entry
+                    loTree.putTreeNode(h, k, v, e.entry);
+                } else {
+                    ++hiCount;
+                    hiTree.putTreeNode(h, k, v, e.entry);
+                }
+                // Iterate using the saved 'next'
+                e = next;
+            }
+            if (loCount < TREE_THRESHOLD) { // too small, convert back to list
+                HashMap.Entry loEntry = null;
+                TreeNode<K,V> p = loTree.first;
+                while (p != null) {
+                    @SuppressWarnings("unchecked")
+                    TreeNode<K,V> savedNext = (TreeNode<K,V>) p.entry.next;
+                    p.entry.next = loEntry;
+                    loEntry = p.entry;
+                    p = savedNext;
+                }
+                // assert newTable[i] == null;
+                newTable[i] = loEntry;
+            } else {
+                // assert newTable[i] == null;
+                newTable[i] = loTree;
+            }
+            if (hiCount < TREE_THRESHOLD) { // too small, convert back to list
+                HashMap.Entry hiEntry = null;
+                TreeNode<K,V> p = hiTree.first;
+                while (p != null) {
+                    @SuppressWarnings("unchecked")
+                    TreeNode<K,V> savedNext = (TreeNode<K,V>) p.entry.next;
+                    p.entry.next = hiEntry;
+                    hiEntry = p.entry;
+                    p = savedNext;
+                }
+                // assert newTable[i + bit] == null;
+                newTable[i + bit] = hiEntry;
+            } else {
+                // assert newTable[i + bit] == null;
+                newTable[i + bit] = hiTree;
+            }
+        }
+
+        /*
+         * Popuplate the TreeBin with entries from the linked list e
+         *
+         * Assumes 'this' is a new/empty TreeBin
+         *
+         * Note: no check for Comparable
+         * Note: I believe this changes iteration order
+         */
+        @SuppressWarnings("unchecked")
+        void populate(HashMap.Entry e) {
+            // assert root == null;
+            // assert first == null;
+            HashMap.Entry next;
+            while (e != null) {
+                // Save entry.next - it will get overwritten in putTreeNode()
+                next = (HashMap.Entry)e.next;
+                // Re-using Entry e will maintain before/after in LinkedHM
+                putTreeNode(e.hash, (K)e.key, (V)e.value, e);
+                // Iterate using the saved 'next'
+                e = next;
+            }
+        }
+
+        /**
+         * Copied from CHMv8
+         * From CLR
+         */
+        private void rotateLeft(TreeNode p) {
+            if (p != null) {
+                TreeNode r = p.right, pp, rl;
+                if ((rl = p.right = r.left) != null) {
+                    rl.parent = p;
+                }
+                if ((pp = r.parent = p.parent) == null) {
+                    root = r;
+                } else if (pp.left == p) {
+                    pp.left = r;
+                } else {
+                    pp.right = r;
+                }
+                r.left = p;
+                p.parent = r;
+            }
+        }
+
+        /**
+         * Copied from CHMv8
+         * From CLR
+         */
+        private void rotateRight(TreeNode p) {
+            if (p != null) {
+                TreeNode l = p.left, pp, lr;
+                if ((lr = p.left = l.right) != null) {
+                    lr.parent = p;
+                }
+                if ((pp = l.parent = p.parent) == null) {
+                    root = l;
+                } else if (pp.right == p) {
+                    pp.right = l;
+                } else {
+                    pp.left = l;
+                }
+                l.right = p;
+                p.parent = l;
+            }
+        }
+
+        /**
+         * Returns the TreeNode (or null if not found) for the given
+         * key.  A front-end for recursive version.
+         */
+        final TreeNode getTreeNode(int h, K k) {
+            return getTreeNode(h, k, root, comparableClassFor(k));
+        }
+
+        /**
+         * Returns the TreeNode (or null if not found) for the given key
+         * starting at given root.
+         */
+        @SuppressWarnings("unchecked")
+        final TreeNode getTreeNode (int h, K k, TreeNode p, Class<?> cc) {
+            // assert k != null;
+            while (p != null) {
+                int dir, ph;  Object pk;
+                if ((ph = p.entry.hash) != h)
+                    dir = (h < ph) ? -1 : 1;
+                else if ((pk = p.entry.key) == k || k.equals(pk))
+                    return p;
+                else if (cc == null || comparableClassFor(pk) != cc ||
+                         (dir = ((Comparable<Object>)k).compareTo(pk)) == 0) {
+                    // assert pk != null;
+                    TreeNode r, pl, pr; // check both sides
+                    if ((pr = p.right) != null &&
+                        (r = getTreeNode(h, k, pr, cc)) != null)
+                        return r;
+                    else if ((pl = p.left) != null)
+                        dir = -1;
+                    else // nothing there
+                        break;
+                }
+                p = (dir > 0) ? p.right : p.left;
+            }
+            return null;
+        }
+
+        /*
+         * Finds or adds a node.
+         *
+         * 'entry' should be used to recycle an existing Entry (e.g. in the case
+         * of converting a linked-list bin to a TreeBin).
+         * If entry is null, a new Entry will be created for the new TreeNode
+         *
+         * @return the TreeNode containing the mapping, or null if a new
+         * TreeNode was added
+         */
+        @SuppressWarnings("unchecked")
+        TreeNode putTreeNode(int h, K k, V v, HashMap.Entry<K,V> entry) {
+            // assert k != null;
+            //if (entry != null) {
+                // assert h == entry.hash;
+                // assert k == entry.key;
+                // assert v == entry.value;
+            // }
+            Class<?> cc = comparableClassFor(k);
+            TreeNode pp = root, p = null;
+            int dir = 0;
+            while (pp != null) { // find existing node or leaf to insert at
+                int ph;  Object pk;
+                p = pp;
+                if ((ph = p.entry.hash) != h)
+                    dir = (h < ph) ? -1 : 1;
+                else if ((pk = p.entry.key) == k || k.equals(pk))
+                    return p;
+                else if (cc == null || comparableClassFor(pk) != cc ||
+                         (dir = ((Comparable<Object>)k).compareTo(pk)) == 0) {
+                    TreeNode r, pr;
+                    if ((pr = p.right) != null &&
+                        (r = getTreeNode(h, k, pr, cc)) != null)
+                        return r;
+                    else // continue left
+                        dir = -1;
+                }
+                pp = (dir > 0) ? p.right : p.left;
+            }
+
+            // Didn't find the mapping in the tree, so add it
+            TreeNode f = first;
+            TreeNode x;
+            if (entry != null) {
+                x = new TreeNode(entry, f, p);
+            } else {
+                x = new TreeNode(newEntry(h, k, v, null), f, p);
+            }
+            first = x;
+
+            if (p == null) {
+                root = x;
+            } else { // attach and rebalance; adapted from CLR
+                TreeNode xp, xpp;
+                if (f != null) {
+                    f.prev = x;
+                }
+                if (dir <= 0) {
+                    p.left = x;
+                } else {
+                    p.right = x;
+                }
+                x.red = true;
+                while (x != null && (xp = x.parent) != null && xp.red
+                        && (xpp = xp.parent) != null) {
+                    TreeNode xppl = xpp.left;
+                    if (xp == xppl) {
+                        TreeNode y = xpp.right;
+                        if (y != null && y.red) {
+                            y.red = false;
+                            xp.red = false;
+                            xpp.red = true;
+                            x = xpp;
+                        } else {
+                            if (x == xp.right) {
+                                rotateLeft(x = xp);
+                                xpp = (xp = x.parent) == null ? null : xp.parent;
+                            }
+                            if (xp != null) {
+                                xp.red = false;
+                                if (xpp != null) {
+                                    xpp.red = true;
+                                    rotateRight(xpp);
+                                }
+                            }
+                        }
+                    } else {
+                        TreeNode y = xppl;
+                        if (y != null && y.red) {
+                            y.red = false;
+                            xp.red = false;
+                            xpp.red = true;
+                            x = xpp;
+                        } else {
+                            if (x == xp.left) {
+                                rotateRight(x = xp);
+                                xpp = (xp = x.parent) == null ? null : xp.parent;
+                            }
+                            if (xp != null) {
+                                xp.red = false;
+                                if (xpp != null) {
+                                    xpp.red = true;
+                                    rotateLeft(xpp);
+                                }
+                            }
+                        }
+                    }
+                }
+                TreeNode r = root;
+                if (r != null && r.red) {
+                    r.red = false;
+                }
+            }
+            return null;
+        }
+
+        /*
+         * From CHMv8
+         *
+         * Removes the given node, that must be present before this
+         * call.  This is messier than typical red-black deletion code
+         * because we cannot swap the contents of an interior node
+         * with a leaf successor that is pinned by "next" pointers
+         * that are accessible independently of lock. So instead we
+         * swap the tree linkages.
+         */
+        final void deleteTreeNode(TreeNode p) {
+            TreeNode next = (TreeNode) p.entry.next; // unlink traversal pointers
+            TreeNode pred = p.prev;
+            if (pred == null) {
+                first = next;
+            } else {
+                pred.entry.next = next;
+            }
+            if (next != null) {
+                next.prev = pred;
+            }
+            TreeNode replacement;
+            TreeNode pl = p.left;
+            TreeNode pr = p.right;
+            if (pl != null && pr != null) {
+                TreeNode s = pr, sl;
+                while ((sl = s.left) != null) // find successor
+                {
+                    s = sl;
+                }
+                boolean c = s.red;
+                s.red = p.red;
+                p.red = c; // swap colors
+                TreeNode sr = s.right;
+                TreeNode pp = p.parent;
+                if (s == pr) { // p was s's direct parent
+                    p.parent = s;
+                    s.right = p;
+                } else {
+                    TreeNode sp = s.parent;
+                    if ((p.parent = sp) != null) {
+                        if (s == sp.left) {
+                            sp.left = p;
+                        } else {
+                            sp.right = p;
+                        }
+                    }
+                    if ((s.right = pr) != null) {
+                        pr.parent = s;
+                    }
+                }
+                p.left = null;
+                if ((p.right = sr) != null) {
+                    sr.parent = p;
+                }
+                if ((s.left = pl) != null) {
+                    pl.parent = s;
+                }
+                if ((s.parent = pp) == null) {
+                    root = s;
+                } else if (p == pp.left) {
+                    pp.left = s;
+                } else {
+                    pp.right = s;
+                }
+                replacement = sr;
+            } else {
+                replacement = (pl != null) ? pl : pr;
+            }
+            TreeNode pp = p.parent;
+            if (replacement == null) {
+                if (pp == null) {
+                    root = null;
+                    return;
+                }
+                replacement = p;
+            } else {
+                replacement.parent = pp;
+                if (pp == null) {
+                    root = replacement;
+                } else if (p == pp.left) {
+                    pp.left = replacement;
+                } else {
+                    pp.right = replacement;
+                }
+                p.left = p.right = p.parent = null;
+            }
+            if (!p.red) { // rebalance, from CLR
+                TreeNode x = replacement;
+                while (x != null) {
+                    TreeNode xp, xpl;
+                    if (x.red || (xp = x.parent) == null) {
+                        x.red = false;
+                        break;
+                    }
+                    if (x == (xpl = xp.left)) {
+                        TreeNode sib = xp.right;
+                        if (sib != null && sib.red) {
+                            sib.red = false;
+                            xp.red = true;
+                            rotateLeft(xp);
+                            sib = (xp = x.parent) == null ? null : xp.right;
+                        }
+                        if (sib == null) {
+                            x = xp;
+                        } else {
+                            TreeNode sl = sib.left, sr = sib.right;
+                            if ((sr == null || !sr.red)
+                                    && (sl == null || !sl.red)) {
+                                sib.red = true;
+                                x = xp;
+                            } else {
+                                if (sr == null || !sr.red) {
+                                    if (sl != null) {
+                                        sl.red = false;
+                                    }
+                                    sib.red = true;
+                                    rotateRight(sib);
+                                    sib = (xp = x.parent) == null ?
+                                        null : xp.right;
+                                }
+                                if (sib != null) {
+                                    sib.red = (xp == null) ? false : xp.red;
+                                    if ((sr = sib.right) != null) {
+                                        sr.red = false;
+                                    }
+                                }
+                                if (xp != null) {
+                                    xp.red = false;
+                                    rotateLeft(xp);
+                                }
+                                x = root;
+                            }
+                        }
+                    } else { // symmetric
+                        TreeNode sib = xpl;
+                        if (sib != null && sib.red) {
+                            sib.red = false;
+                            xp.red = true;
+                            rotateRight(xp);
+                            sib = (xp = x.parent) == null ? null : xp.left;
+                        }
+                        if (sib == null) {
+                            x = xp;
+                        } else {
+                            TreeNode sl = sib.left, sr = sib.right;
+                            if ((sl == null || !sl.red)
+                                    && (sr == null || !sr.red)) {
+                                sib.red = true;
+                                x = xp;
+                            } else {
+                                if (sl == null || !sl.red) {
+                                    if (sr != null) {
+                                        sr.red = false;
+                                    }
+                                    sib.red = true;
+                                    rotateLeft(sib);
+                                    sib = (xp = x.parent) == null ?
+                                        null : xp.left;
+                                }
+                                if (sib != null) {
+                                    sib.red = (xp == null) ? false : xp.red;
+                                    if ((sl = sib.left) != null) {
+                                        sl.red = false;
+                                    }
+                                }
+                                if (xp != null) {
+                                    xp.red = false;
+                                    rotateRight(xp);
+                                }
+                                x = root;
+                            }
+                        }
+                    }
+                }
+            }
+            if (p == replacement && (pp = p.parent) != null) {
+                if (p == pp.left) // detach pointers
+                {
+                    pp.left = null;
+                } else if (p == pp.right) {
+                    pp.right = null;
+                }
+                p.parent = null;
+            }
+        }
+    }
 
     /**
      * Constructs an empty <tt>HashMap</tt> with the specified initial
@@ -233,9 +829,9 @@
         if (loadFactor <= 0 || Float.isNaN(loadFactor))
             throw new IllegalArgumentException("Illegal load factor: " +
                                                loadFactor);
-
         this.loadFactor = loadFactor;
         threshold = initialCapacity;
+        hashSeed = initHashSeed();
         init();
     }
 
@@ -269,10 +865,11 @@
      */
     public HashMap(Map<? extends K, ? extends V> m) {
         this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
-                      DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);
+                DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);
         inflateTable(threshold);
 
         putAllForCreate(m);
+        // assert size == m.size();
     }
 
     private static int roundUpToPowerOf2(int number) {
@@ -294,7 +891,7 @@
         int capacity = roundUpToPowerOf2(toSize);
 
         threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);
-        table = new Entry[capacity];
+        table = new Object[capacity];
     }
 
     // internal utilities
@@ -310,17 +907,24 @@
     }
 
     /**
+     * Return an initial value for the hashSeed, or 0 if the random seed is not
+     * enabled.
+     */
+    final int initHashSeed() {
+        if (sun.misc.VM.isBooted() && Holder.USE_HASHSEED) {
+            return sun.misc.Hashing.randomHashSeed(this);
+        }
+        return 0;
+    }
+
+    /**
      * Retrieve object hash code and applies a supplemental hash function to the
-     * result hash, which defends against poor quality hash functions.  This is
+     * result hash, which defends against poor quality hash functions. This is
      * critical because HashMap uses power-of-two length hash tables, that
      * otherwise encounter collisions for hashCodes that do not differ
      * in lower bits.
      */
     final int hash(Object k) {
-        if (k instanceof String) {
-            return ((String) k).hash32();
-        }
-
         int  h = hashSeed ^ k.hashCode();
 
         // This function ensures that hashCodes that differ only by
@@ -409,19 +1013,35 @@
         if (isEmpty()) {
             return null;
         }
+        if (key == null) {
+            return nullKeyEntry;
+        }
+        int hash = hash(key);
+        int bin = indexFor(hash, table.length);
 
-        int hash = (key == null) ? 0 : hash(key);
-        for (Entry<?,?> e = table[indexFor(hash, table.length)];
-             e != null;
-             e = e.next) {
-            Object k;
-            if (e.hash == hash &&
-                ((k = e.key) == key || (key != null && key.equals(k))))
-                return (Entry<K,V>)e;
+        if (table[bin] instanceof Entry) {
+            Entry<K,V> e = (Entry<K,V>) table[bin];
+            for (; e != null; e = (Entry<K,V>)e.next) {
+                Object k;
+                if (e.hash == hash &&
+                    ((k = e.key) == key || key.equals(k))) {
+                    return e;
+                }
+            }
+        } else if (table[bin] != null) {
+            TreeBin e = (TreeBin)table[bin];
+            TreeNode p = e.getTreeNode(hash, (K)key);
+            if (p != null) {
+                // assert p.entry.hash == hash && p.entry.key.equals(key);
+                return (Entry<K,V>)p.entry;
+            } else {
+                return null;
+            }
         }
         return null;
     }
 
+
     /**
      * Associates the specified value with the specified key in this map.
      * If the map previously contained a mapping for the key, the old
@@ -434,28 +1054,57 @@
      *         (A <tt>null</tt> return can also indicate that the map
      *         previously associated <tt>null</tt> with <tt>key</tt>.)
      */
+    @SuppressWarnings("unchecked")
     public V put(K key, V value) {
         if (table == EMPTY_TABLE) {
             inflateTable(threshold);
         }
-        if (key == null)
+       if (key == null)
             return putForNullKey(value);
         int hash = hash(key);
         int i = indexFor(hash, table.length);
-        @SuppressWarnings("unchecked")
-        Entry<K,V> e = (Entry<K,V>)table[i];
-        for(; e != null; e = e.next) {
-            Object k;
-            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
-                V oldValue = e.value;
-                e.value = value;
-                e.recordAccess(this);
-                return oldValue;
+        boolean checkIfNeedTree = false; // Might we convert bin to a TreeBin?
+
+        if (table[i] instanceof Entry) {
+            // Bin contains ordinary Entries.  Search for key in the linked list
+            // of entries, counting the number of entries.  Only check for
+            // TreeBin conversion if the list size is >= TREE_THRESHOLD.
+            // (The conversion still may not happen if the table gets resized.)
+            int listSize = 0;
+            Entry<K,V> e = (Entry<K,V>) table[i];
+            for (; e != null; e = (Entry<K,V>)e.next) {
+                Object k;
+                if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
+                    V oldValue = e.value;
+                    e.value = value;
+                    e.recordAccess(this);
+                    return oldValue;
+                }
+                listSize++;
+            }
+            // Didn't find, so fall through and call addEntry() to add the
+            // Entry and check for TreeBin conversion.
+            checkIfNeedTree = listSize >= TreeBin.TREE_THRESHOLD;
+        } else if (table[i] != null) {
+            TreeBin e = (TreeBin)table[i];
+            TreeNode p = e.putTreeNode(hash, key, value, null);
+            if (p == null) { // putTreeNode() added a new node
+                modCount++;
+                size++;
+                if (size >= threshold) {
+                    resize(2 * table.length);
+                }
+                return null;
+            } else { // putTreeNode() found an existing node
+                Entry<K,V> pEntry = (Entry<K,V>)p.entry;
+                V oldVal = pEntry.value;
+                pEntry.value = value;
+                pEntry.recordAccess(this);
+                return oldVal;
             }
         }
-
         modCount++;
-        addEntry(hash, key, value, i);
+        addEntry(hash, key, value, i, checkIfNeedTree);
         return null;
     }
 
@@ -463,47 +1112,79 @@
      * Offloaded version of put for null keys
      */
     private V putForNullKey(V value) {
-        @SuppressWarnings("unchecked")
-        Entry<K,V> e = (Entry<K,V>)table[0];
-        for(; e != null; e = e.next) {
-            if (e.key == null) {
-                V oldValue = e.value;
-                e.value = value;
-                e.recordAccess(this);
-                return oldValue;
-            }
+        if (nullKeyEntry != null) {
+            V oldValue = nullKeyEntry.value;
+            nullKeyEntry.value = value;
+            nullKeyEntry.recordAccess(this);
+            return oldValue;
         }
         modCount++;
-        addEntry(0, null, value, 0);
+        size++; // newEntry() skips size++
+        nullKeyEntry = newEntry(0, null, value, null);
         return null;
     }
 
+    private void putForCreateNullKey(V value) {
+        // Look for preexisting entry for key.  This will never happen for
+        // clone or deserialize.  It will only happen for construction if the
+        // input Map is a sorted map whose ordering is inconsistent w/ equals.
+        if (nullKeyEntry != null) {
+            nullKeyEntry.value = value;
+        } else {
+            nullKeyEntry = newEntry(0, null, value, null);
+            size++;
+        }
+    }
+
+
     /**
      * This method is used instead of put by constructors and
      * pseudoconstructors (clone, readObject).  It does not resize the table,
-     * check for comodification, etc.  It calls createEntry rather than
-     * addEntry.
+     * check for comodification, etc, though it will convert bins to TreeBins
+     * as needed.  It calls createEntry rather than addEntry.
      */
+    @SuppressWarnings("unchecked")
     private void putForCreate(K key, V value) {
-        int hash = null == key ? 0 : hash(key);
+        if (null == key) {
+            putForCreateNullKey(value);
+            return;
+        }
+        int hash = hash(key);
         int i = indexFor(hash, table.length);
+        boolean checkIfNeedTree = false; // Might we convert bin to a TreeBin?
 
         /**
          * Look for preexisting entry for key.  This will never happen for
          * clone or deserialize.  It will only happen for construction if the
          * input Map is a sorted map whose ordering is inconsistent w/ equals.
          */
-        for (@SuppressWarnings("unchecked")
-             Entry<?,V> e = (Entry<?,V>)table[i]; e != null; e = e.next) {
-            Object k;
-            if (e.hash == hash &&
-                ((k = e.key) == key || (key != null && key.equals(k)))) {
-                e.value = value;
-                return;
+        if (table[i] instanceof Entry) {
+            int listSize = 0;
+            Entry<K,V> e = (Entry<K,V>) table[i];
+            for (; e != null; e = (Entry<K,V>)e.next) {
+                Object k;
+                if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
+                    e.value = value;
+                    return;
+                }
+                listSize++;
             }
+            // Didn't find, fall through to createEntry().
+            // Check for conversion to TreeBin done via createEntry().
+            checkIfNeedTree = listSize >= TreeBin.TREE_THRESHOLD;
+        } else if (table[i] != null) {
+            TreeBin e = (TreeBin)table[i];
+            TreeNode p = e.putTreeNode(hash, key, value, null);
+            if (p != null) {
+                p.entry.setValue(value); // Found an existing node, set value
+            } else {
+                size++; // Added a new TreeNode, so update size
+            }
+            // don't need modCount++/check for resize - just return
+            return;
         }
 
-        createEntry(hash, key, value, i);
+        createEntry(hash, key, value, i, checkIfNeedTree);
     }
 
     private void putAllForCreate(Map<? extends K, ? extends V> m) {
@@ -526,14 +1207,14 @@
      *        is irrelevant).
      */
     void resize(int newCapacity) {
-        Entry<?,?>[] oldTable = table;
+        Object[] oldTable = table;
         int oldCapacity = oldTable.length;
         if (oldCapacity == MAXIMUM_CAPACITY) {
             threshold = Integer.MAX_VALUE;
             return;
         }
 
-        Entry<?,?>[] newTable = new Entry<?,?>[newCapacity];
+        Object[] newTable = new Object[newCapacity];
         transfer(newTable);
         table = newTable;
         threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
@@ -541,19 +1222,31 @@
 
     /**
      * Transfers all entries from current table to newTable.
+     *
+     * Assumes newTable is larger than table
      */
     @SuppressWarnings("unchecked")
-    void transfer(Entry<?,?>[] newTable) {
-        Entry<?,?>[] src = table;
+    void transfer(Object[] newTable) {
+        Object[] src = table;
+        // assert newTable.length > src.length : "newTable.length(" +
+        //   newTable.length + ") expected to be > src.length("+src.length+")";
         int newCapacity = newTable.length;
-        for (int j = 0; j < src.length; j++ ) {
-            Entry<K,V> e = (Entry<K,V>) src[j];
-            while(null != e) {
-                Entry<K,V> next = e.next;
-                int i = indexFor(e.hash, newCapacity);
-                e.next = (Entry<K,V>) newTable[i];
-                newTable[i] = e;
-                e = next;
+        for (int j = 0; j < src.length; j++) {
+             if (src[j] instanceof Entry) {
+                // Assume: since wasn't TreeBin before, won't need TreeBin now
+                Entry<K,V> e = (Entry<K,V>) src[j];
+                while (null != e) {
+                    Entry<K,V> next = (Entry<K,V>)e.next;
+                    int i = indexFor(e.hash, newCapacity);
+                    e.next = (Entry<K,V>) newTable[i];
+                    newTable[i] = e;
+                    e = next;
+                }
+            } else if (src[j] != null) {
+                TreeBin e = (TreeBin) src[j];
+                TreeBin loTree = new TreeBin();
+                TreeBin hiTree = new TreeBin();
+                e.splitTreeBin(newTable, j, loTree, hiTree);
             }
         }
         Arrays.fill(table, null);
@@ -585,20 +1278,13 @@
          * By using the conservative calculation, we subject ourself
          * to at most one extra resize.
          */
-        if (numKeysToBeAdded > threshold) {
-            int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1);
-            if (targetCapacity > MAXIMUM_CAPACITY)
-                targetCapacity = MAXIMUM_CAPACITY;
-            int newCapacity = table.length;
-            while (newCapacity < targetCapacity)
-                newCapacity <<= 1;
-            if (newCapacity > table.length)
-                resize(newCapacity);
+        if (numKeysToBeAdded > threshold && table.length < MAXIMUM_CAPACITY) {
+            resize(table.length * 2);
         }
 
         for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
             put(e.getKey(), e.getValue());
-    }
+        }
 
     /**
      * Removes the mapping for the specified key from this map if present.
@@ -621,24 +1307,57 @@
         if (table == EMPTY_TABLE) {
             inflateTable(threshold);
         }
-        int hash = (key == null) ? 0 : hash(key);
-        int i = indexFor(hash, table.length);
-        @SuppressWarnings("unchecked")
-        Entry<K,V> e = (Entry<K,V>)table[i];
-        for(; e != null; e = e.next) {
-            if (e.hash == hash && Objects.equals(e.key, key)) {
-                if(e.value != null) {
-                    return e.value;
-                }
-                e.value = value;
-                modCount++;
-                e.recordAccess(this);
+        if (key == null) {
+            if (nullKeyEntry == null || nullKeyEntry.value == null) {
+                putForNullKey(value);
                 return null;
+            } else {
+                return nullKeyEntry.value;
             }
         }
+        int hash = hash(key);
+        int i = indexFor(hash, table.length);
+        boolean checkIfNeedTree = false; // Might we convert bin to a TreeBin?
 
+        if (table[i] instanceof Entry) {
+            int listSize = 0;
+            Entry<K,V> e = (Entry<K,V>) table[i];
+            for (; e != null; e = (Entry<K,V>)e.next) {
+                if (e.hash == hash && Objects.equals(e.key, key)) {
+                    if (e.value != null) {
+                        return e.value;
+                    }
+                    e.value = value;
+                    e.recordAccess(this);
+                    return null;
+                }
+                listSize++;
+            }
+            // Didn't find, so fall through and call addEntry() to add the
+            // Entry and check for TreeBin conversion.
+            checkIfNeedTree = listSize >= TreeBin.TREE_THRESHOLD;
+        } else if (table[i] != null) {
+            TreeBin e = (TreeBin)table[i];
+            TreeNode p = e.putTreeNode(hash, key, value, null);
+            if (p == null) { // not found, putTreeNode() added a new node
+                modCount++;
+                size++;
+                if (size >= threshold) {
+                    resize(2 * table.length);
+                }
+                return null;
+            } else { // putTreeNode() found an existing node
+                Entry<K,V> pEntry = (Entry<K,V>)p.entry;
+                V oldVal = pEntry.value;
+                if (oldVal == null) { // only replace if maps to null
+                    pEntry.value = value;
+                    pEntry.recordAccess(this);
+                }
+                return oldVal;
+            }
+        }
         modCount++;
-        addEntry(hash, key, value, i);
+        addEntry(hash, key, value, i, checkIfNeedTree);
         return null;
     }
 
@@ -647,31 +1366,61 @@
         if (isEmpty()) {
             return false;
         }
-        int hash = (key == null) ? 0 : hash(key);
-        int i = indexFor(hash, table.length);
-        @SuppressWarnings("unchecked")
-        Entry<K,V> prev = (Entry<K,V>)table[i];
-        Entry<K,V> e = prev;
-
-        while (e != null) {
-            Entry<K,V> next = e.next;
-            if (e.hash == hash && Objects.equals(e.key, key)) {
-                if (!Objects.equals(e.value, value)) {
-                    return false;
-                }
-                modCount++;
-                size--;
-                if (prev == e)
-                    table[i] = next;
-                else
-                    prev.next = next;
-                e.recordRemoval(this);
+        if (key == null) {
+            if (nullKeyEntry != null &&
+                 Objects.equals(nullKeyEntry.value, value)) {
+                removeNullKey();
                 return true;
             }
-            prev = e;
-            e = next;
+            return false;
         }
+        int hash = hash(key);
+        int i = indexFor(hash, table.length);
 
+        if (table[i] instanceof Entry) {
+            @SuppressWarnings("unchecked")
+            Entry<K,V> prev = (Entry<K,V>) table[i];
+            Entry<K,V> e = prev;
+            while (e != null) {
+                @SuppressWarnings("unchecked")
+                Entry<K,V> next = (Entry<K,V>) e.next;
+                if (e.hash == hash && Objects.equals(e.key, key)) {
+                    if (!Objects.equals(e.value, value)) {
+                        return false;
+                    }
+                    modCount++;
+                    size--;
+                    if (prev == e)
+                        table[i] = next;
+                    else
+                        prev.next = next;
+                    e.recordRemoval(this);
+                    return true;
+                }
+                prev = e;
+                e = next;
+            }
+        } else if (table[i] != null) {
+            TreeBin tb = ((TreeBin) table[i]);
+            TreeNode p = tb.getTreeNode(hash, (K)key);
+            if (p != null) {
+                Entry<K,V> pEntry = (Entry<K,V>)p.entry;
+                // assert pEntry.key.equals(key);
+                if (Objects.equals(pEntry.value, value)) {
+                    modCount++;
+                    size--;
+                    tb.deleteTreeNode(p);
+                    pEntry.recordRemoval(this);
+                    if (tb.root == null || tb.first == null) {
+                        // assert tb.root == null && tb.first == null :
+                        //         "TreeBin.first and root should both be null";
+                        // TreeBin is now empty, we should blank this bin
+                        table[i] = null;
+                    }
+                    return true;
+                }
+            }
+        }
         return false;
     }
 
@@ -680,39 +1429,82 @@
         if (isEmpty()) {
             return false;
         }
-        int hash = (key == null) ? 0 : hash(key);
-        int i = indexFor(hash, table.length);
-        @SuppressWarnings("unchecked")
-        Entry<K,V> e = (Entry<K,V>)table[i];
-        for (; e != null; e = e.next) {
-            if (e.hash == hash && Objects.equals(e.key, key) && Objects.equals(e.value, oldValue)) {
-                e.value = newValue;
-                e.recordAccess(this);
+        if (key == null) {
+            if (nullKeyEntry != null &&
+                 Objects.equals(nullKeyEntry.value, oldValue)) {
+                putForNullKey(newValue);
                 return true;
             }
+            return false;
         }
+        int hash = hash(key);
+        int i = indexFor(hash, table.length);
 
+        if (table[i] instanceof Entry) {
+            @SuppressWarnings("unchecked")
+            Entry<K,V> e = (Entry<K,V>) table[i];
+            for (; e != null; e = (Entry<K,V>)e.next) {
+                if (e.hash == hash && Objects.equals(e.key, key) && Objects.equals(e.value, oldValue)) {
+                    e.value = newValue;
+                    e.recordAccess(this);
+                    return true;
+                }
+            }
+            return false;
+        } else if (table[i] != null) {
+            TreeBin tb = ((TreeBin) table[i]);
+            TreeNode p = tb.getTreeNode(hash, key);
+            if (p != null) {
+                Entry<K,V> pEntry = (Entry<K,V>)p.entry;
+                // assert pEntry.key.equals(key);
+                if (Objects.equals(pEntry.value, oldValue)) {
+                    pEntry.value = newValue;
+                    pEntry.recordAccess(this);
+                    return true;
+                }
+            }
+        }
         return false;
     }
 
-    @Override
+   @Override
     public V replace(K key, V value) {
         if (isEmpty()) {
             return null;
         }
-        int hash = (key == null) ? 0 : hash(key);
+        if (key == null) {
+            if (nullKeyEntry != null) {
+                return putForNullKey(value);
+            }
+            return null;
+        }
+        int hash = hash(key);
         int i = indexFor(hash, table.length);
-        @SuppressWarnings("unchecked")
-        Entry<K,V> e = (Entry<K,V>)table[i];
-        for (; e != null; e = e.next) {
-            if (e.hash == hash && Objects.equals(e.key, key)) {
-                V oldValue = e.value;
-                e.value = value;
-                e.recordAccess(this);
+        if (table[i] instanceof Entry) {
+            @SuppressWarnings("unchecked")
+            Entry<K,V> e = (Entry<K,V>)table[i];
+            for (; e != null; e = (Entry<K,V>)e.next) {
+                if (e.hash == hash && Objects.equals(e.key, key)) {
+                    V oldValue = e.value;
+                    e.value = value;
+                    e.recordAccess(this);
+                    return oldValue;
+                }
+            }
+
+            return null;
+        } else if (table[i] != null) {
+            TreeBin tb = ((TreeBin) table[i]);
+            TreeNode p = tb.getTreeNode(hash, key);
+            if (p != null) {
+                Entry<K,V> pEntry = (Entry<K,V>)p.entry;
+                // assert pEntry.key.equals(key);
+                V oldValue = pEntry.value;
+                pEntry.value = value;
+                pEntry.recordAccess(this);
                 return oldValue;
             }
         }
-
         return null;
     }
 
@@ -721,21 +1513,75 @@
         if (table == EMPTY_TABLE) {
             inflateTable(threshold);
         }
-        int hash = (key == null) ? 0 : hash(key);
+        if (key == null) {
+            if (nullKeyEntry == null || nullKeyEntry.value == null) {
+                V newValue = mappingFunction.apply(key);
+                if (newValue != null) {
+                    putForNullKey(newValue);
+                }
+                return newValue;
+            }
+            return nullKeyEntry.value;
+        }
+        int hash = hash(key);
         int i = indexFor(hash, table.length);
-        @SuppressWarnings("unchecked")
-        Entry<K,V> e = (Entry<K,V>)table[i];
-        for (; e != null; e = e.next) {
-            if (e.hash == hash && Objects.equals(e.key, key)) {
-                V oldValue = e.value;
-                return oldValue == null ? (e.value = mappingFunction.apply(key)) : oldValue;
+        boolean checkIfNeedTree = false; // Might we convert bin to a TreeBin?
+
+        if (table[i] instanceof Entry) {
+            int listSize = 0;
+            @SuppressWarnings("unchecked")
+            Entry<K,V> e = (Entry<K,V>)table[i];
+            for (; e != null; e = (Entry<K,V>)e.next) {
+                if (e.hash == hash && Objects.equals(e.key, key)) {
+                    V oldValue = e.value;
+                    if (oldValue == null) {
+                        V newValue = mappingFunction.apply(key);
+                        if (newValue != null) {
+                            e.value = newValue;
+                            e.recordAccess(this);
+                        }
+                        return newValue;
+                    }
+                    return oldValue;
+                }
+                listSize++;
+            }
+            // Didn't find, fall through to call the mapping function
+            checkIfNeedTree = listSize >= TreeBin.TREE_THRESHOLD;
+        } else if (table[i] != null) {
+            TreeBin e = (TreeBin)table[i];
+            V value = mappingFunction.apply(key);
+            if (value == null) { // Return the existing value, if any
+                TreeNode p = e.getTreeNode(hash, key);
+                if (p != null) {
+                    return (V) p.entry.value;
+                }
+                return null;
+            } else { // Put the new value into the Tree, if absent
+                TreeNode p = e.putTreeNode(hash, key, value, null);
+                if (p == null) { // not found, new node was added
+                    modCount++;
+                    size++;
+                    if (size >= threshold) {
+                        resize(2 * table.length);
+                    }
+                    return value;
+                } else { // putTreeNode() found an existing node
+                    Entry<K,V> pEntry = (Entry<K,V>)p.entry;
+                    V oldVal = pEntry.value;
+                    if (oldVal == null) { // only replace if maps to null
+                        pEntry.value = value;
+                        pEntry.recordAccess(this);
+                        return value;
+                    }
+                    return oldVal;
+                }
             }
         }
-
         V newValue = mappingFunction.apply(key);
-        if (newValue != null) {
+        if (newValue != null) { // add Entry and check for TreeBin conversion
             modCount++;
-            addEntry(hash, key, newValue, i);
+            addEntry(hash, key, newValue, i, checkIfNeedTree);
         }
 
         return newValue;
@@ -746,59 +1592,34 @@
         if (isEmpty()) {
             return null;
         }
-        int hash = (key == null) ? 0 : hash(key);
-        int i = indexFor(hash, table.length);
-        @SuppressWarnings("unchecked")
-        Entry<K,V> prev = (Entry<K,V>)table[i];
-        Entry<K,V> e = prev;
-
-        while (e != null) {
-            Entry<K,V> next = e.next;
-            if (e.hash == hash && Objects.equals(e.key, key)) {
-                V oldValue = e.value;
-                if (oldValue == null)
-                    break;
+        if (key == null) {
+            V oldValue;
+            if (nullKeyEntry != null && (oldValue = nullKeyEntry.value) != null) {
                 V newValue = remappingFunction.apply(key, oldValue);
-                modCount++;
-                if (newValue == null) {
-                    size--;
-                    if (prev == e)
-                        table[i] = next;
-                    else
-                        prev.next = next;
-                    e.recordRemoval(this);
+                if (newValue != null ) {
+                    putForNullKey(newValue);
+                    return newValue;
                 } else {
-                    e.value = newValue;
-                    e.recordAccess(this);
+                    removeNullKey();
                 }
-                return newValue;
             }
-            prev = e;
-            e = next;
-        }
-
-        return null;
-    }
-
-    @Override
-    public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
-        if (table == EMPTY_TABLE) {
-            inflateTable(threshold);
+            return null;
         }
-        int hash = (key == null) ? 0 : hash(key);
+        int hash = hash(key);
         int i = indexFor(hash, table.length);
-        @SuppressWarnings("unchecked")
-        Entry<K,V> prev = (Entry<K,V>)table[i];
-        Entry<K,V> e = prev;
-
-        while (e != null) {
-            Entry<K,V> next = e.next;
-            if (e.hash == hash && Objects.equals(e.key, key)) {
-                V oldValue = e.value;
-                V newValue = remappingFunction.apply(key, oldValue);
-                if (newValue != oldValue) {
-                    modCount++;
+        if (table[i] instanceof Entry) {
+            @SuppressWarnings("unchecked")
+            Entry<K,V> prev = (Entry<K,V>)table[i];
+            Entry<K,V> e = prev;
+            while (e != null) {
+                Entry<K,V> next = (Entry<K,V>)e.next;
+                if (e.hash == hash && Objects.equals(e.key, key)) {
+                    V oldValue = e.value;
+                    if (oldValue == null)
+                        break;
+                    V newValue = remappingFunction.apply(key, oldValue);
                     if (newValue == null) {
+                        modCount++;
                         size--;
                         if (prev == e)
                             table[i] = next;
@@ -809,17 +1630,136 @@
                         e.value = newValue;
                         e.recordAccess(this);
                     }
+                    return newValue;
                 }
-                return newValue;
+                prev = e;
+                e = next;
+            }
+        } else if (table[i] != null) {
+            TreeBin tb = (TreeBin)table[i];
+            TreeNode p = tb.getTreeNode(hash, key);
+            if (p != null) {
+                Entry<K,V> pEntry = (Entry<K,V>)p.entry;
+                // assert pEntry.key.equals(key);
+                V oldValue = pEntry.value;
+                if (oldValue != null) {
+                    V newValue = remappingFunction.apply(key, oldValue);
+                    if (newValue == null) { // remove mapping
+                        modCount++;
+                        size--;
+                        tb.deleteTreeNode(p);
+                        pEntry.recordRemoval(this);
+                        if (tb.root == null || tb.first == null) {
+                            // assert tb.root == null && tb.first == null :
+                            //     "TreeBin.first and root should both be null";
+                            // TreeBin is now empty, we should blank this bin
+                            table[i] = null;
+                        }
+                    } else {
+                        pEntry.value = newValue;
+                        pEntry.recordAccess(this);
+                    }
+                    return newValue;
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        if (table == EMPTY_TABLE) {
+            inflateTable(threshold);
+        }
+        if (key == null) {
+            V oldValue = nullKeyEntry == null ? null : nullKeyEntry.value;
+            V newValue = remappingFunction.apply(key, oldValue);
+            if (newValue != oldValue) {
+                if (newValue == null) {
+                    removeNullKey();
+                } else {
+                    putForNullKey(newValue);
+                }
             }
-            prev = e;
-            e = next;
+            return newValue;
+        }
+        int hash = hash(key);
+        int i = indexFor(hash, table.length);
+        boolean checkIfNeedTree = false; // Might we convert bin to a TreeBin?
+
+        if (table[i] instanceof Entry) {
+            int listSize = 0;
+            @SuppressWarnings("unchecked")
+            Entry<K,V> prev = (Entry<K,V>)table[i];
+            Entry<K,V> e = prev;
+
+            while (e != null) {
+                Entry<K,V> next = (Entry<K,V>)e.next;
+                if (e.hash == hash && Objects.equals(e.key, key)) {
+                    V oldValue = e.value;
+                    V newValue = remappingFunction.apply(key, oldValue);
+                    if (newValue != oldValue) {
+                        if (newValue == null) {
+                            modCount++;
+                            size--;
+                            if (prev == e)
+                                table[i] = next;
+                            else
+                                prev.next = next;
+                            e.recordRemoval(this);
+                        } else {
+                            e.value = newValue;
+                            e.recordAccess(this);
+                        }
+                    }
+                    return newValue;
+                }
+                prev = e;
+                e = next;
+                listSize++;
+            }
+            checkIfNeedTree = listSize >= TreeBin.TREE_THRESHOLD;
+        } else if (table[i] != null) {
+            TreeBin tb = (TreeBin)table[i];
+            TreeNode p = tb.getTreeNode(hash, key);
+            V oldValue = p == null ? null : (V)p.entry.value;
+            V newValue = remappingFunction.apply(key, oldValue);
+            if (newValue != oldValue) {
+                if (newValue == null) {
+                    Entry<K,V> pEntry = (Entry<K,V>)p.entry;
+                    modCount++;
+                    size--;
+                    tb.deleteTreeNode(p);
+                    pEntry.recordRemoval(this);
+                    if (tb.root == null || tb.first == null) {
+                        // assert tb.root == null && tb.first == null :
+                        //         "TreeBin.first and root should both be null";
+                        // TreeBin is now empty, we should blank this bin
+                        table[i] = null;
+                    }
+                } else {
+                    if (p != null) { // just update the value
+                        Entry<K,V> pEntry = (Entry<K,V>)p.entry;
+                        pEntry.value = newValue;
+                        pEntry.recordAccess(this);
+                    } else { // need to put new node
+                        p = tb.putTreeNode(hash, key, newValue, null);
+                        // assert p == null; // should have added a new node
+                        modCount++;
+                        size++;
+                        if (size >= threshold) {
+                            resize(2 * table.length);
+                        }
+                    }
+                }
+            }
+            return newValue;
         }
 
         V newValue = remappingFunction.apply(key, null);
         if (newValue != null) {
             modCount++;
-            addEntry(hash, key, newValue, i);
+            addEntry(hash, key, newValue, i, checkIfNeedTree);
         }
 
         return newValue;
@@ -830,40 +1770,96 @@
         if (table == EMPTY_TABLE) {
             inflateTable(threshold);
         }
-        int hash = (key == null) ? 0 : hash(key);
+        if (key == null) {
+            V oldValue = nullKeyEntry == null ? null : nullKeyEntry.value;
+            V newValue = oldValue == null ? value : remappingFunction.apply(oldValue, value);
+            if (newValue != null) {
+                putForNullKey(newValue);
+            } else if (nullKeyEntry != null) {
+                removeNullKey();
+            }
+            return newValue;
+        }
+        int hash = hash(key);
         int i = indexFor(hash, table.length);
-        @SuppressWarnings("unchecked")
-        Entry<K,V> prev = (Entry<K,V>)table[i];
-        Entry<K,V> e = prev;
+        boolean checkIfNeedTree = false; // Might we convert bin to a TreeBin?
+
+        if (table[i] instanceof Entry) {
+            int listSize = 0;
+            @SuppressWarnings("unchecked")
+            Entry<K,V> prev = (Entry<K,V>)table[i];
+            Entry<K,V> e = prev;
 
-        while (e != null) {
-            Entry<K,V> next = e.next;
-            if (e.hash == hash && Objects.equals(e.key, key)) {
-                V oldValue = e.value;
-                V newValue = remappingFunction.apply(oldValue, value);
-                modCount++;
-                if (newValue == null) {
+            while (e != null) {
+                Entry<K,V> next = (Entry<K,V>)e.next;
+                if (e.hash == hash && Objects.equals(e.key, key)) {
+                    V oldValue = e.value;
+                    V newValue = (oldValue == null) ? value :
+                                 remappingFunction.apply(oldValue, value);
+                    if (newValue == null) {
+                        modCount++;
+                        size--;
+                        if (prev == e)
+                            table[i] = next;
+                        else
+                            prev.next = next;
+                        e.recordRemoval(this);
+                    } else {
+                        e.value = newValue;
+                        e.recordAccess(this);
+                    }
+                    return newValue;
+                }
+                prev = e;
+                e = next;
+                listSize++;
+            }
+            // Didn't find, so fall through and (maybe) call addEntry() to add
+            // the Entry and check for TreeBin conversion.
+            checkIfNeedTree = listSize >= TreeBin.TREE_THRESHOLD;
+        } else if (table[i] != null) {
+            TreeBin tb = (TreeBin)table[i];
+            TreeNode p = tb.getTreeNode(hash, key);
+            V oldValue = p == null ? null : (V)p.entry.value;
+            V newValue = (oldValue == null) ? value :
+                         remappingFunction.apply(oldValue, value);
+            if (newValue == null) {
+                if (p != null) {
+                    Entry<K,V> pEntry = (Entry<K,V>)p.entry;
+                    modCount++;
                     size--;
-                    if (prev == e)
-                        table[i] = next;
-                    else
-                        prev.next = next;
-                    e.recordRemoval(this);
-                } else {
-                    e.value = newValue;
-                    e.recordAccess(this);
+                    tb.deleteTreeNode(p);
+                    pEntry.recordRemoval(this);
+
+                    if (tb.root == null || tb.first == null) {
+                        // assert tb.root == null && tb.first == null :
+                        //         "TreeBin.first and root should both be null";
+                        // TreeBin is now empty, we should blank this bin
+                        table[i] = null;
+                    }
                 }
-                return newValue;
+                return null;
+            } else if (newValue != oldValue) {
+                if (p != null) { // just update the value
+                    Entry<K,V> pEntry = (Entry<K,V>)p.entry;
+                    pEntry.value = newValue;
+                    pEntry.recordAccess(this);
+                } else { // need to put new node
+                    p = tb.putTreeNode(hash, key, newValue, null);
+                    // assert p == null; // should have added a new node
+                    modCount++;
+                    size++;
+                    if (size >= threshold) {
+                        resize(2 * table.length);
+                    }
+                }
             }
-            prev = e;
-            e = next;
+            return newValue;
         }
-
         if (value != null) {
             modCount++;
-            addEntry(hash, key, value, i);
+            addEntry(hash, key, value, i, checkIfNeedTree);
         }
-
         return value;
     }
 
@@ -873,36 +1869,65 @@
      * Removes and returns the entry associated with the specified key
      * in the HashMap.  Returns null if the HashMap contains no mapping
      * for this key.
+     *
+     * We don't bother converting TreeBins back to Entry lists if the bin falls
+     * back below TREE_THRESHOLD, but we do clear bins when removing the last
+     * TreeNode in a TreeBin.
      */
     final Entry<K,V> removeEntryForKey(Object key) {
         if (isEmpty()) {
             return null;
         }
-        int hash = (key == null) ? 0 : hash(key);
+        if (key == null) {
+            if (nullKeyEntry != null) {
+                return removeNullKey();
+            }
+            return null;
+        }
+        int hash = hash(key);
         int i = indexFor(hash, table.length);
-        @SuppressWarnings("unchecked")
+
+        if (table[i] instanceof Entry) {
+            @SuppressWarnings("unchecked")
             Entry<K,V> prev = (Entry<K,V>)table[i];
-        Entry<K,V> e = prev;
+            Entry<K,V> e = prev;
 
-        while (e != null) {
-            Entry<K,V> next = e.next;
-            Object k;
-            if (e.hash == hash &&
-                ((k = e.key) == key || (key != null && key.equals(k)))) {
+            while (e != null) {
+                @SuppressWarnings("unchecked")
+                Entry<K,V> next = (Entry<K,V>) e.next;
+                if (e.hash == hash && Objects.equals(e.key, key)) {
+                    modCount++;
+                    size--;
+                    if (prev == e)
+                        table[i] = next;
+                    else
+                        prev.next = next;
+                    e.recordRemoval(this);
+                    return e;
+                }
+                prev = e;
+                e = next;
+            }
+        } else if (table[i] != null) {
+            TreeBin tb = ((TreeBin) table[i]);
+            TreeNode p = tb.getTreeNode(hash, (K)key);
+            if (p != null) {
+                Entry<K,V> pEntry = (Entry<K,V>)p.entry;
+                // assert pEntry.key.equals(key);
                 modCount++;
                 size--;
-                if (prev == e)
-                    table[i] = next;
-                else
-                    prev.next = next;
-                e.recordRemoval(this);
-                return e;
+                tb.deleteTreeNode(p);
+                pEntry.recordRemoval(this);
+                if (tb.root == null || tb.first == null) {
+                    // assert tb.root == null && tb.first == null :
+                    //             "TreeBin.first and root should both be null";
+                    // TreeBin is now empty, we should blank this bin
+                    table[i] = null;
+                }
+                return pEntry;
             }
-            prev = e;
-            e = next;
         }
-
-        return e;
+        return null;
     }
 
     /**
@@ -915,29 +1940,75 @@
 
         Map.Entry<?,?> entry = (Map.Entry<?,?>) o;
         Object key = entry.getKey();
-        int hash = (key == null) ? 0 : hash(key);
+
+        if (key == null) {
+            if (entry.equals(nullKeyEntry)) {
+                return removeNullKey();
+            }
+            return null;
+        }
+
+        int hash = hash(key);
         int i = indexFor(hash, table.length);
-        @SuppressWarnings("unchecked")
-            Entry<K,V> prev = (Entry<K,V>)table[i];
-        Entry<K,V> e = prev;
+
+        if (table[i] instanceof Entry) {
+            @SuppressWarnings("unchecked")
+                Entry<K,V> prev = (Entry<K,V>)table[i];
+            Entry<K,V> e = prev;
 
-        while (e != null) {
-            Entry<K,V> next = e.next;
-            if (e.hash == hash && e.equals(entry)) {
+            while (e != null) {
+                @SuppressWarnings("unchecked")
+                Entry<K,V> next = (Entry<K,V>)e.next;
+                if (e.hash == hash && e.equals(entry)) {
+                    modCount++;
+                    size--;
+                    if (prev == e)
+                        table[i] = next;
+                    else
+                        prev.next = next;
+                    e.recordRemoval(this);
+                    return e;
+                }
+                prev = e;
+                e = next;
+            }
+        } else if (table[i] != null) {
+            TreeBin tb = ((TreeBin) table[i]);
+            TreeNode p = tb.getTreeNode(hash, (K)key);
+            if (p != null && p.entry.equals(entry)) {
+                @SuppressWarnings("unchecked")
+                Entry<K,V> pEntry = (Entry<K,V>)p.entry;
+                // assert pEntry.key.equals(key);
                 modCount++;
                 size--;
-                if (prev == e)
-                    table[i] = next;
-                else
-                    prev.next = next;
-                e.recordRemoval(this);
-                return e;
+                tb.deleteTreeNode(p);
+                pEntry.recordRemoval(this);
+                if (tb.root == null || tb.first == null) {
+                    // assert tb.root == null && tb.first == null :
+                    //             "TreeBin.first and root should both be null";
+                    // TreeBin is now empty, we should blank this bin
+                    table[i] = null;
+                }
+                return pEntry;
             }
-            prev = e;
-            e = next;
         }
+        return null;
+    }
 
-        return e;
+    /*
+     * Remove the mapping for the null key, and update internal accounting
+     * (size, modcount, recordRemoval, etc).
+     *
+     * Assumes nullKeyEntry is non-null.
+     */
+    private Entry<K,V> removeNullKey() {
+        // assert nullKeyEntry != null;
+        Entry<K,V> retVal = nullKeyEntry;
+        modCount++;
+        size--;
+        retVal.recordRemoval(this);
+        nullKeyEntry = null;
+        return retVal;
     }
 
     /**
@@ -946,6 +2017,9 @@
      */
     public void clear() {
         modCount++;
+        if (nullKeyEntry != null) {
+            nullKeyEntry = null;
+        }
         Arrays.fill(table, null);
         size = 0;
     }
@@ -959,27 +2033,58 @@
      *         specified value
      */
     public boolean containsValue(Object value) {
-        if (value == null)
+        if (value == null) {
             return containsNullValue();
-
-        Entry<?,?>[] tab = table;
-        for (int i = 0; i < tab.length; i++)
-            for (Entry<?,?> e = tab[i]; e != null; e = e.next)
-                if (value.equals(e.value))
-                    return true;
-        return false;
+        }
+        Object[] tab = table;
+        for (int i = 0; i < tab.length; i++) {
+            if (tab[i] instanceof Entry) {
+                Entry<?,?> e = (Entry<?,?>)tab[i];
+                for (; e != null; e = (Entry<?,?>)e.next) {
+                    if (value.equals(e.value)) {
+                        return true;
+                    }
+                }
+            } else if (tab[i] != null) {
+                TreeBin e = (TreeBin)tab[i];
+                TreeNode p = e.first;
+                for (; p != null; p = (TreeNode) p.entry.next) {
+                    if (value == p.entry.value || value.equals(p.entry.value)) {
+                        return true;
+                    }
+                }
+            }
+        }
+        // Didn't find value in table - could be in nullKeyEntry
+        return (nullKeyEntry != null && (value == nullKeyEntry.value ||
+                                         value.equals(nullKeyEntry.value)));
     }
 
     /**
      * Special-case code for containsValue with null argument
      */
     private boolean containsNullValue() {
-        Entry<?,?>[] tab = table;
-        for (int i = 0; i < tab.length; i++)
-            for (Entry<?,?> e = tab[i]; e != null; e = e.next)
-                if (e.value == null)
-                    return true;
-        return false;
+        Object[] tab = table;
+        for (int i = 0; i < tab.length; i++) {
+            if (tab[i] instanceof Entry) {
+                Entry<K,V> e = (Entry<K,V>)tab[i];
+                for (; e != null; e = (Entry<K,V>)e.next) {
+                    if (e.value == null) {
+                        return true;
+                    }
+                }
+            } else if (tab[i] != null) {
+                TreeBin e = (TreeBin)tab[i];
+                TreeNode p = e.first;
+                for (; p != null; p = (TreeNode) p.entry.next) {
+                    if (p.entry.value == null) {
+                        return true;
+                    }
+                }
+            }
+        }
+        // Didn't find value in table - could be in nullKeyEntry
+        return (nullKeyEntry != null && nullKeyEntry.value == null);
     }
 
     /**
@@ -1007,6 +2112,7 @@
         result.entrySet = null;
         result.modCount = 0;
         result.size = 0;
+        result.nullKeyEntry = null;
         result.init();
         result.putAllForCreate(this);
 
@@ -1016,13 +2122,13 @@
     static class Entry<K,V> implements Map.Entry<K,V> {
         final K key;
         V value;
-        Entry<K,V> next;
+        Object next; // an Entry, or a TreeNode
         final int hash;
 
         /**
          * Creates new entry.
          */
-        Entry(int h, K k, V v, Entry<K,V> n) {
+        Entry(int h, K k, V v, Object n) {
             value = v;
             next = n;
             key = k;
@@ -1054,7 +2160,7 @@
                 Object v2 = e.getValue();
                 if (v1 == v2 || (v1 != null && v1.equals(v2)))
                     return true;
-            }
+                }
             return false;
         }
 
@@ -1068,8 +2174,7 @@
 
         /**
          * This method is invoked whenever the value in an entry is
-         * overwritten by an invocation of put(k,v) for a key k that's already
-         * in the HashMap.
+         * overwritten for a key that's already in the HashMap.
          */
         void recordAccess(HashMap<K,V> m) {
         }
@@ -1082,50 +2187,96 @@
         }
     }
 
+    void addEntry(int hash, K key, V value, int bucketIndex) {
+        addEntry(hash, key, value, bucketIndex, true);
+    }
+
     /**
      * Adds a new entry with the specified key, value and hash code to
      * the specified bucket.  It is the responsibility of this
-     * method to resize the table if appropriate.
+     * method to resize the table if appropriate.  The new entry is then
+     * created by calling createEntry().
      *
      * Subclass overrides this to alter the behavior of put method.
+     *
+     * If checkIfNeedTree is false, it is known that this bucket will not need
+     * to be converted to a TreeBin, so don't bothering checking.
+     *
+     * Assumes key is not null.
      */
-    void addEntry(int hash, K key, V value, int bucketIndex) {
+    void addEntry(int hash, K key, V value, int bucketIndex, boolean checkIfNeedTree) {
+        // assert key != null;
         if ((size >= threshold) && (null != table[bucketIndex])) {
             resize(2 * table.length);
-            hash = (null != key) ? hash(key) : 0;
+            hash = hash(key);
             bucketIndex = indexFor(hash, table.length);
         }
-
-        createEntry(hash, key, value, bucketIndex);
+        createEntry(hash, key, value, bucketIndex, checkIfNeedTree);
     }
 
     /**
-     * Like addEntry except that this version is used when creating entries
+     * Called by addEntry(), and also used when creating entries
      * as part of Map construction or "pseudo-construction" (cloning,
-     * deserialization).  This version needn't worry about resizing the table.
+     * deserialization).  This version does not check for resizing of the table.
      *
-     * Subclass overrides this to alter the behavior of HashMap(Map),
-     * clone, and readObject.
+     * This method is responsible for converting a bucket to a TreeBin once
+     * TREE_THRESHOLD is reached. However if checkIfNeedTree is false, it is known
+     * that this bucket will not need to be converted to a TreeBin, so don't
+     * bother checking.  The new entry is constructed by calling newEntry().
+     *
+     * Assumes key is not null.
+     *
+     * Note: buckets already converted to a TreeBin don't call this method, but
+     * instead call TreeBin.putTreeNode() to create new entries.
      */
-    void createEntry(int hash, K key, V value, int bucketIndex) {
+    void createEntry(int hash, K key, V value, int bucketIndex, boolean checkIfNeedTree) {
+        // assert key != null;
         @SuppressWarnings("unchecked")
             Entry<K,V> e = (Entry<K,V>)table[bucketIndex];
-        table[bucketIndex] = new Entry<>(hash, key, value, e);
+        table[bucketIndex] = newEntry(hash, key, value, e);
         size++;
+
+        if (checkIfNeedTree) {
+            int listSize = 0;
+            for (e = (Entry<K,V>) table[bucketIndex]; e != null; e = (Entry<K,V>)e.next) {
+                listSize++;
+                if (listSize >= TreeBin.TREE_THRESHOLD) { // Convert to TreeBin
+                    if (comparableClassFor(key) != null) {
+                        TreeBin t = new TreeBin();
+                        t.populate((Entry)table[bucketIndex]);
+                        table[bucketIndex] = t;
+                    }
+                    break;
+                }
+            }
+        }
     }
 
+    /*
+     * Factory method to create a new Entry object.
+     */
+    Entry<K,V> newEntry(int hash, K key, V value, Object next) {
+        return new HashMap.Entry<>(hash, key, value, next);
+    }
+
+
     private abstract class HashIterator<E> implements Iterator<E> {
-        Entry<?,?> next;        // next entry to return
+        Object next;            // next entry to return, an Entry or a TreeNode
         int expectedModCount;   // For fast-fail
         int index;              // current slot
-        Entry<?,?> current;     // current entry
+        Object current;         // current entry, an Entry or a TreeNode
 
         HashIterator() {
             expectedModCount = modCount;
             if (size > 0) { // advance to first entry
-                Entry<?,?>[] t = table;
-                while (index < t.length && (next = t[index++]) == null)
-                    ;
+                if (nullKeyEntry != null) {
+                    // assert nullKeyEntry.next == null;
+                    // This works with nextEntry(): nullKeyEntry isa Entry, and
+                    // e.next will be null, so we'll hit the findNextBin() call.
+                    next = nullKeyEntry;
+                } else {
+                    findNextBin();
+                }
             }
         }
 
@@ -1135,19 +2286,28 @@
 
         @SuppressWarnings("unchecked")
         final Entry<K,V> nextEntry() {
-            if (modCount != expectedModCount)
+            if (modCount != expectedModCount) {
                 throw new ConcurrentModificationException();
-            Entry<?,?> e = next;
+            }
+            Object e = next;
+            Entry<K,V> retVal;
+
             if (e == null)
                 throw new NoSuchElementException();
 
-            if ((next = e.next) == null) {
-                Entry<?,?>[] t = table;
-                while (index < t.length && (next = t[index++]) == null)
-                    ;
+            if (e instanceof Entry) {
+                retVal = (Entry<K,V>)e;
+                next = ((Entry<K,V>)e).next;
+            } else { // TreeBin
+                retVal = (Entry<K,V>)((TreeNode)e).entry;
+                next = retVal.next;
+            }
+
+            if (next == null) { // Move to next bin
+                findNextBin();
             }
             current = e;
-            return (Entry<K,V>)e;
+            return retVal;
         }
 
         public void remove() {
@@ -1155,11 +2315,33 @@
                 throw new IllegalStateException();
             if (modCount != expectedModCount)
                 throw new ConcurrentModificationException();
-            Object k = current.key;
+            K k;
+
+            if (current instanceof Entry) {
+                k = ((Entry<K,V>)current).key;
+            } else {
+                k = ((Entry<K,V>)((TreeNode)current).entry).key;
+
+            }
             current = null;
             HashMap.this.removeEntryForKey(k);
             expectedModCount = modCount;
         }
+
+        /*
+         * Set 'next' to the first entry of the next non-empty bin in the table
+         */
+        private void findNextBin() {
+            // assert next == null;
+            Object[] t = table;
+
+            while (index < t.length && (next = t[index++]) == null)
+                ;
+            if (next instanceof HashMap.TreeBin) { // Point to the first TreeNode
+                next = ((TreeBin) next).first;
+                // assert next != null; // There should be no empty TreeBins
+            }
+        }
     }
 
     private final class ValueIterator extends HashIterator<V> {
@@ -1357,7 +2539,7 @@
         if (table==EMPTY_TABLE) {
             s.writeInt(roundUpToPowerOf2(threshold));
         } else {
-           s.writeInt(table.length);
+            s.writeInt(table.length);
         }
 
         // Write out size (number of Mappings)
@@ -1389,8 +2571,10 @@
         }
 
         // set other fields that need values
-        Holder.UNSAFE.putIntVolatile(this, Holder.HASHSEED_OFFSET,
-                sun.misc.Hashing.randomHashSeed(this));
+        if (Holder.USE_HASHSEED) {
+            Holder.UNSAFE.putIntVolatile(this, Holder.HASHSEED_OFFSET,
+                    sun.misc.Hashing.randomHashSeed(this));
+        }
         table = EMPTY_TABLE;
 
         // Read in number of buckets
@@ -1404,9 +2588,9 @@
 
         // capacity chosen by number of mappings and desired load (if >= 0.25)
         int capacity = (int) Math.min(
-                    mappings * Math.min(1 / loadFactor, 4.0f),
-                    // we have limits...
-                    HashMap.MAXIMUM_CAPACITY);
+                mappings * Math.min(1 / loadFactor, 4.0f),
+                // we have limits...
+                HashMap.MAXIMUM_CAPACITY);
 
         // allocate the bucket array;
         if (mappings > 0) {
@@ -1420,9 +2604,9 @@
         // Read the keys and values, and put the mappings in the HashMap
         for (int i=0; i<mappings; i++) {
             @SuppressWarnings("unchecked")
-                K key = (K) s.readObject();
+            K key = (K) s.readObject();
             @SuppressWarnings("unchecked")
-                V value = (V) s.readObject();
+            V value = (V) s.readObject();
             putForCreate(key, value);
         }
     }
@@ -1436,11 +2620,17 @@
      */
     static class HashMapSpliterator<K,V> {
         final HashMap<K,V> map;
-        HashMap.Entry<K,V> current; // current node
+        Object current;             // current node, can be Entry or TreeNode
         int index;                  // current index, modified on advance/split
         int fence;                  // one past last index
         int est;                    // size estimate
         int expectedModCount;       // for comodification checks
+        boolean acceptedNull;       // Have we accepted the null key?
+                                    // Without this, we can't distinguish
+                                    // between being at the very beginning (and
+                                    // needing to accept null), or being at the
+                                    // end of the list in bin 0.  In both cases,
+                                    // current == null && index == 0.
 
         HashMapSpliterator(HashMap<K,V> m, int origin,
                                int fence, int est,
@@ -1450,6 +2640,7 @@
             this.fence = fence;
             this.est = est;
             this.expectedModCount = expectedModCount;
+            this.acceptedNull = false;
         }
 
         final int getFence() { // initialize fence and size on first use
@@ -1479,9 +2670,15 @@
 
         public KeySpliterator<K,V> trySplit() {
             int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
-            return (lo >= mid || current != null) ? null :
-                new KeySpliterator<K,V>(map, lo, index = mid, est >>>= 1,
-                                        expectedModCount);
+            if (lo >= mid || current != null) {
+                return null;
+            } else {
+                KeySpliterator<K,V> retVal = new KeySpliterator<K,V>(map, lo,
+                                     index = mid, est >>>= 1, expectedModCount);
+                // Only 'this' Spliterator chould check for null.
+                retVal.acceptedNull = true;
+                return retVal;
+            }
         }
 
         @SuppressWarnings("unchecked")
@@ -1490,21 +2687,39 @@
             if (action == null)
                 throw new NullPointerException();
             HashMap<K,V> m = map;
-            HashMap.Entry<K,V>[] tab = (HashMap.Entry<K,V>[])m.table;
+            Object[] tab = m.table;
             if ((hi = fence) < 0) {
                 mc = expectedModCount = m.modCount;
                 hi = fence = tab.length;
             }
             else
                 mc = expectedModCount;
-            if (tab.length >= hi && (i = index) >= 0 && i < (index = hi)) {
-                HashMap.Entry<K,V> p = current;
+
+            if (!acceptedNull) {
+                acceptedNull = true;
+                if (m.nullKeyEntry != null) {
+                    action.accept(m.nullKeyEntry.key);
+                }
+            }
+            if (tab.length >= hi && (i = index) >= 0 &&
+                (i < (index = hi) || current != null)) {
+                Object p = current;
+                current = null;
                 do {
-                    if (p == null)
+                    if (p == null) {
                         p = tab[i++];
-                    else {
-                        action.accept(p.getKey());
-                        p = p.next;
+                        if (p instanceof HashMap.TreeBin) {
+                            p = ((HashMap.TreeBin)p).first;
+                        }
+                    } else {
+                        HashMap.Entry<K,V> entry;
+                        if (p instanceof HashMap.Entry) {
+                            entry = (HashMap.Entry<K,V>)p;
+                        } else {
+                            entry = (HashMap.Entry<K,V>)((TreeNode)p).entry;
+                        }
+                        action.accept(entry.key);
+                        p = entry.next;
                     }
                 } while (p != null || i < hi);
                 if (m.modCount != mc)
@@ -1517,14 +2732,34 @@
             int hi;
             if (action == null)
                 throw new NullPointerException();
-            HashMap.Entry<K,V>[] tab = (HashMap.Entry<K,V>[])map.table;
-            if (tab.length >= (hi = getFence()) && index >= 0) {
+            Object[] tab = map.table;
+            hi = getFence();
+
+            if (!acceptedNull) {
+                acceptedNull = true;
+                if (map.nullKeyEntry != null) {
+                    action.accept(map.nullKeyEntry.key);
+                    if (map.modCount != expectedModCount)
+                        throw new ConcurrentModificationException();
+                    return true;
+                }
+            }
+            if (tab.length >= hi && index >= 0) {
                 while (current != null || index < hi) {
-                    if (current == null)
+                    if (current == null) {
                         current = tab[index++];
-                    else {
-                        K k = current.getKey();
-                        current = current.next;
+                        if (current instanceof HashMap.TreeBin) {
+                            current = ((HashMap.TreeBin)current).first;
+                        }
+                    } else {
+                        HashMap.Entry<K,V> entry;
+                        if (current instanceof HashMap.Entry) {
+                            entry = (HashMap.Entry<K,V>)current;
+                        } else {
+                            entry = (HashMap.Entry<K,V>)((TreeNode)current).entry;
+                        }
+                        K k = entry.key;
+                        current = entry.next;
                         action.accept(k);
                         if (map.modCount != expectedModCount)
                             throw new ConcurrentModificationException();
@@ -1551,9 +2786,15 @@
 
         public ValueSpliterator<K,V> trySplit() {
             int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
-            return (lo >= mid || current != null) ? null :
-                new ValueSpliterator<K,V>(map, lo, index = mid, est >>>= 1,
-                                          expectedModCount);
+            if (lo >= mid || current != null) {
+                return null;
+            } else {
+                ValueSpliterator<K,V> retVal = new ValueSpliterator<K,V>(map,
+                                 lo, index = mid, est >>>= 1, expectedModCount);
+                // Only 'this' Spliterator chould check for null.
+                retVal.acceptedNull = true;
+                return retVal;
+            }
         }
 
         @SuppressWarnings("unchecked")
@@ -1562,21 +2803,39 @@
             if (action == null)
                 throw new NullPointerException();
             HashMap<K,V> m = map;
-            HashMap.Entry<K,V>[] tab = (HashMap.Entry<K,V>[])m.table;
+            Object[] tab = m.table;
             if ((hi = fence) < 0) {
                 mc = expectedModCount = m.modCount;
                 hi = fence = tab.length;
             }
             else
                 mc = expectedModCount;
-            if (tab.length >= hi && (i = index) >= 0 && i < (index = hi)) {
-                HashMap.Entry<K,V> p = current;
+
+            if (!acceptedNull) {
+                acceptedNull = true;
+                if (m.nullKeyEntry != null) {
+                    action.accept(m.nullKeyEntry.value);
+                }
+            }
+            if (tab.length >= hi && (i = index) >= 0 &&
+                (i < (index = hi) || current != null)) {
+                Object p = current;
+                current = null;
                 do {
-                    if (p == null)
+                    if (p == null) {
                         p = tab[i++];
-                    else {
-                        action.accept(p.getValue());
-                        p = p.next;
+                        if (p instanceof HashMap.TreeBin) {
+                            p = ((HashMap.TreeBin)p).first;
+                        }
+                    } else {
+                        HashMap.Entry<K,V> entry;
+                        if (p instanceof HashMap.Entry) {
+                            entry = (HashMap.Entry<K,V>)p;
+                        } else {
+                            entry = (HashMap.Entry<K,V>)((TreeNode)p).entry;
+                        }
+                        action.accept(entry.value);
+                        p = entry.next;
                     }
                 } while (p != null || i < hi);
                 if (m.modCount != mc)
@@ -1589,14 +2848,34 @@
             int hi;
             if (action == null)
                 throw new NullPointerException();
-            HashMap.Entry<K,V>[] tab = (HashMap.Entry<K,V>[])map.table;
-            if (tab.length >= (hi = getFence()) && index >= 0) {
+            Object[] tab = map.table;
+            hi = getFence();
+
+            if (!acceptedNull) {
+                acceptedNull = true;
+                if (map.nullKeyEntry != null) {
+                    action.accept(map.nullKeyEntry.value);
+                    if (map.modCount != expectedModCount)
+                        throw new ConcurrentModificationException();
+                    return true;
+                }
+            }
+            if (tab.length >= hi && index >= 0) {
                 while (current != null || index < hi) {
-                    if (current == null)
+                    if (current == null) {
                         current = tab[index++];
-                    else {
-                        V v = current.getValue();
-                        current = current.next;
+                        if (current instanceof HashMap.TreeBin) {
+                            current = ((HashMap.TreeBin)current).first;
+                        }
+                    } else {
+                        HashMap.Entry<K,V> entry;
+                        if (current instanceof HashMap.Entry) {
+                            entry = (Entry<K,V>)current;
+                        } else {
+                            entry = (Entry<K,V>)((TreeNode)current).entry;
+                        }
+                        V v = entry.value;
+                        current = entry.next;
                         action.accept(v);
                         if (map.modCount != expectedModCount)
                             throw new ConcurrentModificationException();
@@ -1622,9 +2901,15 @@
 
         public EntrySpliterator<K,V> trySplit() {
             int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
-            return (lo >= mid || current != null) ? null :
-                new EntrySpliterator<K,V>(map, lo, index = mid, est >>>= 1,
-                                          expectedModCount);
+            if (lo >= mid || current != null) {
+                return null;
+            } else {
+                EntrySpliterator<K,V> retVal = new EntrySpliterator<K,V>(map,
+                                 lo, index = mid, est >>>= 1, expectedModCount);
+                // Only 'this' Spliterator chould check for null.
+                retVal.acceptedNull = true;
+                return retVal;
+            }
         }
 
         @SuppressWarnings("unchecked")
@@ -1633,21 +2918,40 @@
             if (action == null)
                 throw new NullPointerException();
             HashMap<K,V> m = map;
-            HashMap.Entry<K,V>[] tab = (HashMap.Entry<K,V>[])m.table;
+            Object[] tab = m.table;
             if ((hi = fence) < 0) {
                 mc = expectedModCount = m.modCount;
                 hi = fence = tab.length;
             }
             else
                 mc = expectedModCount;
-            if (tab.length >= hi && (i = index) >= 0 && i < (index = hi)) {
-                HashMap.Entry<K,V> p = current;
+
+            if (!acceptedNull) {
+                acceptedNull = true;
+                if (m.nullKeyEntry != null) {
+                    action.accept(m.nullKeyEntry);
+                }
+            }
+            if (tab.length >= hi && (i = index) >= 0 &&
+                (i < (index = hi) || current != null)) {
+                Object p = current;
+                current = null;
                 do {
-                    if (p == null)
+                    if (p == null) {
                         p = tab[i++];
-                    else {
-                        action.accept(p);
-                        p = p.next;
+                        if (p instanceof HashMap.TreeBin) {
+                            p = ((HashMap.TreeBin)p).first;
+                        }
+                    } else {
+                        HashMap.Entry<K,V> entry;
+                        if (p instanceof HashMap.Entry) {
+                            entry = (HashMap.Entry<K,V>)p;
+                        } else {
+                            entry = (HashMap.Entry<K,V>)((TreeNode)p).entry;
+                        }
+                        action.accept(entry);
+                        p = entry.next;
+
                     }
                 } while (p != null || i < hi);
                 if (m.modCount != mc)
@@ -1660,14 +2964,33 @@
             int hi;
             if (action == null)
                 throw new NullPointerException();
-            HashMap.Entry<K,V>[] tab = (HashMap.Entry<K,V>[])map.table;
-            if (tab.length >= (hi = getFence()) && index >= 0) {
+            Object[] tab = map.table;
+            hi = getFence();
+
+            if (!acceptedNull) {
+                acceptedNull = true;
+                if (map.nullKeyEntry != null) {
+                    action.accept(map.nullKeyEntry);
+                    if (map.modCount != expectedModCount)
+                        throw new ConcurrentModificationException();
+                    return true;
+                }
+            }
+            if (tab.length >= hi && index >= 0) {
                 while (current != null || index < hi) {
-                    if (current == null)
+                    if (current == null) {
                         current = tab[index++];
-                    else {
-                        HashMap.Entry<K,V> e = current;
-                        current = current.next;
+                        if (current instanceof HashMap.TreeBin) {
+                            current = ((HashMap.TreeBin)current).first;
+                        }
+                    } else {
+                        HashMap.Entry<K,V> e;
+                        if (current instanceof HashMap.Entry) {
+                            e = (Entry<K,V>)current;
+                        } else {
+                            e = (Entry<K,V>)((TreeNode)current).entry;
+                        }
+                        current = e.next;
                         action.accept(e);
                         if (map.modCount != expectedModCount)
                             throw new ConcurrentModificationException();
--- a/jdk/src/share/classes/java/util/Hashtable.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/Hashtable.java	Mon Jun 10 10:38:33 2013 +0100
@@ -180,13 +180,27 @@
          */
         static final long HASHSEED_OFFSET;
 
+        static final boolean USE_HASHSEED;
+
         static {
-            try {
-                UNSAFE = sun.misc.Unsafe.getUnsafe();
-                HASHSEED_OFFSET = UNSAFE.objectFieldOffset(
-                    Hashtable.class.getDeclaredField("hashSeed"));
-            } catch (NoSuchFieldException | SecurityException e) {
-                throw new InternalError("Failed to record hashSeed offset", e);
+            String hashSeedProp = java.security.AccessController.doPrivileged(
+                    new sun.security.action.GetPropertyAction(
+                        "jdk.map.useRandomSeed"));
+            boolean localBool = (null != hashSeedProp)
+                    ? Boolean.parseBoolean(hashSeedProp) : false;
+            USE_HASHSEED = localBool;
+
+            if (USE_HASHSEED) {
+                try {
+                    UNSAFE = sun.misc.Unsafe.getUnsafe();
+                    HASHSEED_OFFSET = UNSAFE.objectFieldOffset(
+                        Hashtable.class.getDeclaredField("hashSeed"));
+                } catch (NoSuchFieldException | SecurityException e) {
+                    throw new InternalError("Failed to record hashSeed offset", e);
+                }
+            } else {
+                UNSAFE = null;
+                HASHSEED_OFFSET = 0;
             }
         }
     }
@@ -194,21 +208,24 @@
     /**
      * A randomizing value associated with this instance that is applied to
      * hash code of keys to make hash collisions harder to find.
+     *
+     * Non-final so it can be set lazily, but be sure not to set more than once.
      */
-    transient final int hashSeed = sun.misc.Hashing.randomHashSeed(this);
+    transient final int hashSeed;
+
+    /**
+     * Return an initial value for the hashSeed, or 0 if the random seed is not
+     * enabled.
+     */
+    final int initHashSeed() {
+        if (sun.misc.VM.isBooted() && Holder.USE_HASHSEED) {
+            return sun.misc.Hashing.randomHashSeed(this);
+        }
+        return 0;
+    }
 
     private int hash(Object k) {
-        if (k instanceof String) {
-            return ((String)k).hash32();
-        }
-
-        int h = hashSeed ^ k.hashCode();
-
-        // This function ensures that hashCodes that differ only by
-        // constant multiples at each bit position have a bounded
-        // number of collisions (approximately 8 at default load factor).
-        h ^= (h >>> 20) ^ (h >>> 12);
-        return h ^ (h >>> 7) ^ (h >>> 4);
+        return hashSeed ^ k.hashCode();
     }
 
     /**
@@ -232,6 +249,7 @@
         this.loadFactor = loadFactor;
         table = new Entry<?,?>[initialCapacity];
         threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
+        hashSeed = initHashSeed();
     }
 
     /**
@@ -1187,8 +1205,10 @@
         s.defaultReadObject();
 
         // set hashMask
-        Holder.UNSAFE.putIntVolatile(this, Holder.HASHSEED_OFFSET,
-                sun.misc.Hashing.randomHashSeed(this));
+        if (Holder.USE_HASHSEED) {
+            Holder.UNSAFE.putIntVolatile(this, Holder.HASHSEED_OFFSET,
+                    sun.misc.Hashing.randomHashSeed(this));
+        }
 
         // Read the original length of the array and number of elements
         int origlength = s.readInt();
--- a/jdk/src/share/classes/java/util/IntSummaryStatistics.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/IntSummaryStatistics.java	Mon Jun 10 10:38:33 2013 +0100
@@ -159,7 +159,7 @@
      */
     public String toString() {
         return String.format(
-            "%s{count=%d, sum=%d, min=%d, average=%d, max=%d}",
+            "%s{count=%d, sum=%d, min=%d, average=%f, max=%d}",
             this.getClass().getSimpleName(),
             getCount(),
             getSum(),
--- a/jdk/src/share/classes/java/util/LinkedHashMap.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/LinkedHashMap.java	Mon Jun 10 10:38:33 2013 +0100
@@ -55,9 +55,9 @@
  * order they were presented.)
  *
  * <p>A special {@link #LinkedHashMap(int,float,boolean) constructor} is
- * provided to create a linked hash map whose order of iteration is the order
- * in which its entries were last accessed, from least-recently accessed to
- * most-recently (<i>access-order</i>).  This kind of map is well-suited to
+ * provided to create a <tt>LinkedHashMap</tt> whose order of iteration is the
+ * order in which its entries were last accessed, from least-recently accessed
+ * to most-recently (<i>access-order</i>).  This kind of map is well-suited to
  * building LRU caches.  Invoking the <tt>put</tt> or <tt>get</tt> method
  * results in an access to the corresponding entry (assuming it exists after
  * the invocation completes).  The <tt>putAll</tt> method generates one entry
@@ -243,23 +243,6 @@
     }
 
     /**
-     * Transfers all entries to new table array.  This method is called
-     * by superclass resize.  It is overridden for performance, as it is
-     * faster to iterate using our linked list.
-     */
-    @Override
-    @SuppressWarnings("unchecked")
-    void transfer(HashMap.Entry[] newTable) {
-        int newCapacity = newTable.length;
-        for (Entry<K,V> e = header.after; e != header; e = e.after) {
-            int index = indexFor(e.hash, newCapacity);
-            e.next = (HashMap.Entry<K,V>)newTable[index];
-            newTable[index] = e;
-        }
-    }
-
-
-    /**
      * Returns <tt>true</tt> if this map maps one or more keys to the
      * specified value.
      *
@@ -320,7 +303,7 @@
         // These fields comprise the doubly linked list used for iteration.
         Entry<K,V> before, after;
 
-        Entry(int hash, K key, V value, HashMap.Entry<K,V> next) {
+        Entry(int hash, K key, V value, Object next) {
             super(hash, key, value, next);
         }
 
@@ -344,7 +327,7 @@
 
         /**
          * This method is invoked by the superclass whenever the value
-         * of a pre-existing entry is read by Map.get or modified by Map.set.
+         * of a pre-existing entry is read by Map.get or modified by Map.put.
          * If the enclosing Map is access-ordered, it moves the entry
          * to the end of the list; otherwise, it does nothing.
          */
@@ -422,8 +405,9 @@
      * allocated entry to get inserted at the end of the linked list and
      * removes the eldest entry if appropriate.
      */
-    void addEntry(int hash, K key, V value, int bucketIndex) {
-        super.addEntry(hash, key, value, bucketIndex);
+    @Override
+    void addEntry(int hash, K key, V value, int bucketIndex, boolean checkIfNeedTree) {
+        super.addEntry(hash, key, value, bucketIndex, checkIfNeedTree);
 
         // Remove eldest entry if instructed
         Entry<K,V> eldest = header.after;
@@ -432,17 +416,14 @@
         }
     }
 
-    /**
-     * This override differs from addEntry in that it doesn't resize the
-     * table or remove the eldest entry.
+    /*
+     * Create a new LinkedHashMap.Entry and setup the before/after pointers
      */
-    void createEntry(int hash, K key, V value, int bucketIndex) {
-        @SuppressWarnings("unchecked")
-            HashMap.Entry<K,V> old = (HashMap.Entry<K,V>)table[bucketIndex];
-        Entry<K,V> e = new Entry<>(hash, key, value, old);
-        table[bucketIndex] = e;
-        e.addBefore(header);
-        size++;
+    @Override
+    HashMap.Entry<K,V> newEntry(int hash, K key, V value, Object next) {
+        Entry<K,V> newEntry = new Entry<>(hash, key, value, next);
+        newEntry.addBefore(header);
+        return newEntry;
     }
 
     /**
--- a/jdk/src/share/classes/java/util/ListResourceBundle.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/ListResourceBundle.java	Mon Jun 10 10:38:33 2013 +0100
@@ -89,7 +89,7 @@
  *
  * public class MyResources_fr extends ListResourceBundle {
  *     protected Object[][] getContents() {
- *         return new Object[][] = {
+ *         return new Object[][] {
  *         // LOCALIZE THIS
  *             {"s1", "Le disque \"{1}\" {0}."},          // MessageFormat pattern
  *             {"s2", "1"},                               // location of {0} in pattern
--- a/jdk/src/share/classes/java/util/LongSummaryStatistics.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/LongSummaryStatistics.java	Mon Jun 10 10:38:33 2013 +0100
@@ -171,7 +171,7 @@
      */
     public String toString() {
         return String.format(
-            "%s{count=%d, sum=%d, min=%d, average=%d, max=%d}",
+            "%s{count=%d, sum=%d, min=%d, average=%f, max=%d}",
             this.getClass().getSimpleName(),
             getCount(),
             getSum(),
--- a/jdk/src/share/classes/java/util/PrimitiveIterator.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/PrimitiveIterator.java	Mon Jun 10 10:38:33 2013 +0100
@@ -91,6 +91,7 @@
          * @throws NullPointerException if the specified action is null
          */
         default void forEachRemaining(IntConsumer action) {
+            Objects.requireNonNull(action);
             while (hasNext())
                 action.accept(nextInt());
         }
@@ -123,6 +124,8 @@
                 forEachRemaining((IntConsumer) action);
             }
             else {
+                // The method reference action::accept is never null
+                Objects.requireNonNull(action);
                 if (Tripwire.ENABLED)
                     Tripwire.trip(getClass(), "{0} calling PrimitiveIterator.OfInt.forEachRemainingInt(action::accept)");
                 forEachRemaining((IntConsumer) action::accept);
@@ -162,6 +165,7 @@
          * @throws NullPointerException if the specified action is null
          */
         default void forEachRemaining(LongConsumer action) {
+            Objects.requireNonNull(action);
             while (hasNext())
                 action.accept(nextLong());
         }
@@ -194,6 +198,8 @@
                 forEachRemaining((LongConsumer) action);
             }
             else {
+                // The method reference action::accept is never null
+                Objects.requireNonNull(action);
                 if (Tripwire.ENABLED)
                     Tripwire.trip(getClass(), "{0} calling PrimitiveIterator.OfLong.forEachRemainingLong(action::accept)");
                 forEachRemaining((LongConsumer) action::accept);
@@ -232,6 +238,7 @@
          * @throws NullPointerException if the specified action is null
          */
         default void forEachRemaining(DoubleConsumer action) {
+            Objects.requireNonNull(action);
             while (hasNext())
                 action.accept(nextDouble());
         }
@@ -265,6 +272,8 @@
                 forEachRemaining((DoubleConsumer) action);
             }
             else {
+                // The method reference action::accept is never null
+                Objects.requireNonNull(action);
                 if (Tripwire.ENABLED)
                     Tripwire.trip(getClass(), "{0} calling PrimitiveIterator.OfDouble.forEachRemainingDouble(action::accept)");
                 forEachRemaining((DoubleConsumer) action::accept);
--- a/jdk/src/share/classes/java/util/PropertyResourceBundle.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/PropertyResourceBundle.java	Mon Jun 10 10:38:33 2013 +0100
@@ -124,6 +124,8 @@
      *        to read from.
      * @throws IOException if an I/O error occurs
      * @throws NullPointerException if <code>stream</code> is null
+     * @throws IllegalArgumentException if {@code stream} contains a
+     *     malformed Unicode escape sequence.
      */
     @SuppressWarnings({"unchecked", "rawtypes"})
     public PropertyResourceBundle (InputStream stream) throws IOException {
@@ -142,6 +144,8 @@
      *        read from.
      * @throws IOException if an I/O error occurs
      * @throws NullPointerException if <code>reader</code> is null
+     * @throws IllegalArgumentException if a malformed Unicode escape sequence appears
+     *     from {@code reader}.
      * @since 1.6
      */
     @SuppressWarnings({"unchecked", "rawtypes"})
--- a/jdk/src/share/classes/java/util/Spliterator.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/Spliterator.java	Mon Jun 10 10:38:33 2013 +0100
@@ -140,32 +140,32 @@
  * (in approximate order of decreasing desirability):
  * <ul>
  * <li>The source cannot be structurally interfered with.
- * </br>For example, an instance of
+ * <br>For example, an instance of
  * {@link java.util.concurrent.CopyOnWriteArrayList} is an immutable source.
  * A Spliterator created from the source reports a characteristic of
  * {@code IMMUTABLE}.</li>
  * <li>The source manages concurrent modifications.
- * </br>For example, a key set of a {@link java.util.concurrent.ConcurrentHashMap}
+ * <br>For example, a key set of a {@link java.util.concurrent.ConcurrentHashMap}
  * is a concurrent source.  A Spliterator created from the source reports a
  * characteristic of {@code CONCURRENT}.</li>
  * <li>The mutable source provides a late-binding and fail-fast Spliterator.
- * </br>Late binding narrows the window during which interference can affect
+ * <br>Late binding narrows the window during which interference can affect
  * the calculation; fail-fast detects, on a best-effort basis, that structural
  * interference has occurred after traversal has commenced and throws
  * {@link ConcurrentModificationException}.  For example, {@link ArrayList},
  * and many other non-concurrent {@code Collection} classes in the JDK, provide
  * a late-binding, fail-fast spliterator.</li>
  * <li>The mutable source provides a non-late-binding but fail-fast Spliterator.
- * </br>The source increases the likelihood of throwing
+ * <br>The source increases the likelihood of throwing
  * {@code ConcurrentModificationException} since the window of potential
  * interference is larger.</li>
  * <li>The mutable source provides a late-binding and non-fail-fast Spliterator.
- * </br>The source risks arbitrary, non-deterministic behavior after traversal
+ * <br>The source risks arbitrary, non-deterministic behavior after traversal
  * has commenced since interference is not detected.
  * </li>
  * <li>The mutable source provides a non-late-binding and non-fail-fast
  * Spliterator.
- * </br>The source increases the risk of arbitrary, non-deterministic behavior
+ * <br>The source increases the risk of arbitrary, non-deterministic behavior
  * since non-detected interference may occur after construction.
  * </li>
  * </ul>
@@ -284,6 +284,8 @@
  * is set to {@code true} then diagnostic warnings are reported if boxing of
  * primitive values occur when operating on primitive subtype specializations.
  *
+ * @param <T> the type of elements returned by this Spliterator
+ *
  * @see Collection
  * @since 1.8
  */
@@ -333,9 +335,8 @@
      * Upon non-null return:
      * <ul>
      * <li>the value reported for {@code estimateSize()} before splitting,
-     * if not already zero or {@code Long.MAX_VALUE}, must, after splitting, be
-     * greater than {@code estimateSize()} for this and the returned
-     * Spliterator; and</li>
+     * must, after splitting, be greater than or equal to {@code estimateSize()}
+     * for this and the returned Spliterator; and</li>
      * <li>if this Spliterator is {@code SUBSIZED}, then {@code estimateSize()}
      * for this spliterator before splitting must be equal to the sum of
      * {@code estimateSize()} for this and the returned Spliterator after
@@ -393,9 +394,9 @@
      * Convenience method that returns {@link #estimateSize()} if this
      * Spliterator is {@link #SIZED}, else {@code -1}.
      * @implSpec
-     * The default returns the result of {@code estimateSize()} if the
-     * Spliterator reports a characteristic of {@code SIZED}, and {@code -1}
-     * otherwise.
+     * The default implementation returns the result of {@code estimateSize()}
+     * if the Spliterator reports a characteristic of {@code SIZED}, and
+     * {@code -1} otherwise.
      *
      * @return the exact size, if known, else {@code -1}.
      */
@@ -566,13 +567,28 @@
     public static final int SUBSIZED = 0x00004000;
 
     /**
-     * A Spliterator specialized for {@code int} values.
+     * A Spliterator specialized for primitive values.
+     *
+     * @param <T> the type of elements returned by this Spliterator.  The
+     * type must be a wrapper type for a primitive type, such as {@code Integer}
+     * for the primitive {@code int} type.
+     * @param <T_CONS> the type of primitive consumer.  The type must be a
+     * primitive specialization of {@link java.util.function.Consumer} for
+     * {@code T}, such as {@link java.util.function.IntConsumer} for
+     * {@code Integer}.
+     * @param <T_SPLITR> the type of primitive Spliterator.  The type must be
+     * a primitive specialization of Spliterator for {@code T}, such as
+     * {@link Spliterator.OfInt} for {@code Integer}.
+     *
+     * @see Spliterator.OfInt
+     * @see Spliterator.OfLong
+     * @see Spliterator.OfDouble
      * @since 1.8
      */
-    public interface OfInt extends Spliterator<Integer> {
-
+    public interface OfPrimitive<T, T_CONS, T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>>
+            extends Spliterator<T> {
         @Override
-        OfInt trySplit();
+        T_SPLITR trySplit();
 
         /**
          * If a remaining element exists, performs the given action on it,
@@ -586,7 +602,7 @@
          * upon entry to this method, else {@code true}.
          * @throws NullPointerException if the specified action is null
          */
-        boolean tryAdvance(IntConsumer action);
+        boolean tryAdvance(T_CONS action);
 
         /**
          * Performs the given action for each remaining element, sequentially in
@@ -603,6 +619,24 @@
          * @param action The action
          * @throws NullPointerException if the specified action is null
          */
+        default void forEachRemaining(T_CONS action) {
+            do { } while (tryAdvance(action));
+        }
+    }
+
+    /**
+     * A Spliterator specialized for {@code int} values.
+     * @since 1.8
+     */
+    public interface OfInt extends OfPrimitive<Integer, IntConsumer, OfInt> {
+
+        @Override
+        OfInt trySplit();
+
+        @Override
+        boolean tryAdvance(IntConsumer action);
+
+        @Override
         default void forEachRemaining(IntConsumer action) {
             do { } while (tryAdvance(action));
         }
@@ -658,40 +692,15 @@
      * A Spliterator specialized for {@code long} values.
      * @since 1.8
      */
-    public interface OfLong extends Spliterator<Long> {
+    public interface OfLong extends OfPrimitive<Long, LongConsumer, OfLong> {
 
         @Override
         OfLong trySplit();
 
-        /**
-         * If a remaining element exists, performs the given action on it,
-         * returning {@code true}; else returns {@code false}.  If this
-         * Spliterator is {@link #ORDERED} the action is performed on the
-         * next element in encounter order.  Exceptions thrown by the
-         * action are relayed to the caller.
-         *
-         * @param action The action
-         * @return {@code false} if no remaining elements existed
-         * upon entry to this method, else {@code true}.
-         * @throws NullPointerException if the specified action is null
-         */
+        @Override
         boolean tryAdvance(LongConsumer action);
 
-        /**
-         * Performs the given action for each remaining element, sequentially in
-         * the current thread, until all elements have been processed or the
-         * action throws an exception.  If this Spliterator is {@link #ORDERED},
-         * actions are performed in encounter order.  Exceptions thrown by the
-         * action are relayed to the caller.
-         *
-         * @implSpec
-         * The default implementation repeatedly invokes {@link #tryAdvance}
-         * until it returns {@code false}.  It should be overridden whenever
-         * possible.
-         *
-         * @param action The action
-         * @throws NullPointerException if the specified action is null
-         */
+        @Override
         default void forEachRemaining(LongConsumer action) {
             do { } while (tryAdvance(action));
         }
@@ -747,40 +756,15 @@
      * A Spliterator specialized for {@code double} values.
      * @since 1.8
      */
-    public interface OfDouble extends Spliterator<Double> {
+    public interface OfDouble extends OfPrimitive<Double, DoubleConsumer, OfDouble> {
 
         @Override
         OfDouble trySplit();
 
-        /**
-         * If a remaining element exists, performs the given action on it,
-         * returning {@code true}; else returns {@code false}.  If this
-         * Spliterator is {@link #ORDERED} the action is performed on the
-         * next element in encounter order.  Exceptions thrown by the
-         * action are relayed to the caller.
-         *
-         * @param action The action
-         * @return {@code false} if no remaining elements existed
-         * upon entry to this method, else {@code true}.
-         * @throws NullPointerException if the specified action is null
-         */
+        @Override
         boolean tryAdvance(DoubleConsumer action);
 
-        /**
-         * Performs the given action for each remaining element, sequentially in
-         * the current thread, until all elements have been processed or the
-         * action throws an exception.  If this Spliterator is {@link #ORDERED},
-         * actions are performed in encounter order.  Exceptions thrown by the
-         * action are relayed to the caller.
-         *
-         * @implSpec
-         * The default implementation repeatedly invokes {@link #tryAdvance}
-         * until it returns {@code false}.  It should be overridden whenever
-         * possible.
-         *
-         * @param action The action
-         * @throws NullPointerException if the specified action is null
-         */
+        @Override
         default void forEachRemaining(DoubleConsumer action) {
             do { } while (tryAdvance(action));
         }
--- a/jdk/src/share/classes/java/util/StringJoiner.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/StringJoiner.java	Mon Jun 10 10:38:33 2013 +0100
@@ -29,14 +29,6 @@
  * by a delimiter and optionally starting with a supplied prefix
  * and ending with a supplied suffix.
  * <p>
- * For example, the String {@code "[George:Sally:Fred]"} may
- * be constructed as follows:
- * <pre> {@code
- *     StringJoiner sj = new StringJoiner(":", "[", "]");
- *     sj.add("George").add("Sally").add("Fred");
- *     String desiredString = sj.toString();
- * }</pre>
- * <p>
  * Prior to adding something to the {@code StringJoiner}, its
  * {@code sj.toString()} method will, by default, return {@code prefix + suffix}.
  * However, if the {@code setEmptyValue} method is called, the {@code emptyValue}
@@ -45,17 +37,28 @@
  * <code>"{}"</code>, where the {@code prefix} is <code>"{"</code>, the
  * {@code suffix} is <code>"}"</code> and nothing has been added to the
  * {@code StringJoiner}.
- * <p>
- * A {@code StringJoiner} may be employed to create formatted output from a
- * collection using lambda expressions as shown in the following example.
+ *
+ * @apiNote
+ * <p>The String {@code "[George:Sally:Fred]"} may be constructed as follows:
  *
  * <pre> {@code
- *     List<Person> people = ...
- *     String commaSeparatedNames =
- *         people.map(p -> p.getName()).into(new StringJoiner(", ")).toString();
+ * StringJoiner sj = new StringJoiner(":", "[", "]");
+ * sj.add("George").add("Sally").add("Fred");
+ * String desiredString = sj.toString();
+ * }</pre>
+ * <p>
+ * A {@code StringJoiner} may be employed to create formatted output from a
+ * {@link java.util.stream.Stream} using
+ * {@link java.util.stream.Collectors#toStringJoiner}. For example:
+ *
+ * <pre> {@code
+ * List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
+ * String commaSeparatedNumbers = numbers.stream()
+ *     .map(i -> i.toString())
+ *     .collect(Collectors.toStringJoiner(", ")).toString();
  * }</pre>
  *
- * @author Jim Gish
+ * @see java.util.stream.Collectors#toStringJoiner
  * @since  1.8
 */
 public final class StringJoiner {
--- a/jdk/src/share/classes/java/util/TimSort.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/TimSort.java	Mon Jun 10 10:38:33 2013 +0100
@@ -111,9 +111,13 @@
     private static final int INITIAL_TMP_STORAGE_LENGTH = 256;
 
     /**
-     * Temp storage for merges.
+     * Temp storage for merges. A workspace array may optionally be
+     * provided in constructor, and if so will be used as long as it
+     * is big enough.
      */
-    private T[] tmp; // Actual runtime type will be Object[], regardless of T
+    private T[] tmp;
+    private int tmpBase; // base of tmp array slice
+    private int tmpLen;  // length of tmp array slice
 
     /**
      * A stack of pending runs yet to be merged.  Run i starts at
@@ -134,17 +138,31 @@
      *
      * @param a the array to be sorted
      * @param c the comparator to determine the order of the sort
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
      */
-    private TimSort(T[] a, Comparator<? super T> c) {
+    private TimSort(T[] a, Comparator<? super T> c, T[] work, int workBase, int workLen) {
         this.a = a;
         this.c = c;
 
         // Allocate temp storage (which may be increased later if necessary)
         int len = a.length;
-        @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"})
-        T[] newArray = (T[]) new Object[len < 2 * INITIAL_TMP_STORAGE_LENGTH ?
-                                        len >>> 1 : INITIAL_TMP_STORAGE_LENGTH];
-        tmp = newArray;
+        int tlen = (len < 2 * INITIAL_TMP_STORAGE_LENGTH) ?
+            len >>> 1 : INITIAL_TMP_STORAGE_LENGTH;
+        if (work == null || workLen < tlen || workBase + tlen > work.length) {
+            @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"})
+            T[] newArray = (T[])java.lang.reflect.Array.newInstance
+                (a.getClass().getComponentType(), tlen);
+            tmp = newArray;
+            tmpBase = 0;
+            tmpLen = tlen;
+        }
+        else {
+            tmp = work;
+            tmpBase = workBase;
+            tmpLen = workLen;
+        }
 
         /*
          * Allocate runs-to-be-merged stack (which cannot be expanded).  The
@@ -164,22 +182,30 @@
     }
 
     /*
-     * The next two methods (which are package private and static) constitute
-     * the entire API of this class.  Each of these methods obeys the contract
-     * of the public method with the same signature in java.util.Arrays.
+     * The next method (package private and static) constitutes the
+     * entire API of this class.
      */
 
-    static <T> void sort(T[] a, Comparator<? super T> c) {
-        sort(a, 0, a.length, c);
-    }
+    /**
+     * Sorts the given range, using the given workspace array slice
+     * for temp storage when possible. This method is designed to be
+     * invoked from public methods (in class Arrays) after performing
+     * any necessary array bounds checks and expanding parameters into
+     * the required forms.
+     *
+     * @param a the array to be sorted
+     * @param lo the index of the first element, inclusive, to be sorted
+     * @param hi the index of the last element, exclusive, to be sorted
+     * @param c the comparator to use
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
+     * @since 1.8
+     */
+    static <T> void sort(T[] a, int lo, int hi, Comparator<? super T> c,
+                         T[] work, int workBase, int workLen) {
+        assert c != null && a != null && lo >= 0 && lo <= hi && hi <= a.length;
 
-    static <T> void sort(T[] a, int lo, int hi, Comparator<? super T> c) {
-        if (c == null) {
-            Arrays.sort(a, lo, hi);
-            return;
-        }
-
-        rangeCheck(a.length, lo, hi);
         int nRemaining  = hi - lo;
         if (nRemaining < 2)
             return;  // Arrays of size 0 and 1 are always sorted
@@ -196,7 +222,7 @@
          * extending short natural runs to minRun elements, and merging runs
          * to maintain stack invariant.
          */
-        TimSort<T> ts = new TimSort<>(a, c);
+        TimSort<T> ts = new TimSort<>(a, c, work, workBase, workLen);
         int minRun = minRunLength(nRemaining);
         do {
             // Identify next run
@@ -653,11 +679,10 @@
         // Copy first run into temp array
         T[] a = this.a; // For performance
         T[] tmp = ensureCapacity(len1);
-        System.arraycopy(a, base1, tmp, 0, len1);
-
-        int cursor1 = 0;       // Indexes into tmp array
+        int cursor1 = tmpBase; // Indexes into tmp array
         int cursor2 = base2;   // Indexes int a
         int dest = base1;      // Indexes int a
+        System.arraycopy(a, base1, tmp, cursor1, len1);
 
         // Move first element of second run and deal with degenerate cases
         a[dest++] = a[cursor2++];
@@ -770,16 +795,17 @@
         // Copy second run into temp array
         T[] a = this.a; // For performance
         T[] tmp = ensureCapacity(len2);
-        System.arraycopy(a, base2, tmp, 0, len2);
+        int tmpBase = this.tmpBase;
+        System.arraycopy(a, base2, tmp, tmpBase, len2);
 
         int cursor1 = base1 + len1 - 1;  // Indexes into a
-        int cursor2 = len2 - 1;          // Indexes into tmp array
+        int cursor2 = tmpBase + len2 - 1; // Indexes into tmp array
         int dest = base2 + len2 - 1;     // Indexes into a
 
         // Move last element of first run and deal with degenerate cases
         a[dest--] = a[cursor1--];
         if (--len1 == 0) {
-            System.arraycopy(tmp, 0, a, dest - (len2 - 1), len2);
+            System.arraycopy(tmp, tmpBase, a, dest - (len2 - 1), len2);
             return;
         }
         if (len2 == 1) {
@@ -838,7 +864,7 @@
                 if (--len2 == 1)
                     break outer;
 
-                count2 = len2 - gallopLeft(a[cursor1], tmp, 0, len2, len2 - 1, c);
+                count2 = len2 - gallopLeft(a[cursor1], tmp, tmpBase, len2, len2 - 1, c);
                 if (count2 != 0) {
                     dest -= count2;
                     cursor2 -= count2;
@@ -870,7 +896,7 @@
         } else {
             assert len1 == 0;
             assert len2 > 0;
-            System.arraycopy(tmp, 0, a, dest - (len2 - 1), len2);
+            System.arraycopy(tmp, tmpBase, a, dest - (len2 - 1), len2);
         }
     }
 
@@ -883,7 +909,7 @@
      * @return tmp, whether or not it grew
      */
     private T[] ensureCapacity(int minCapacity) {
-        if (tmp.length < minCapacity) {
+        if (tmpLen < minCapacity) {
             // Compute smallest power of 2 > minCapacity
             int newSize = minCapacity;
             newSize |= newSize >> 1;
@@ -899,30 +925,12 @@
                 newSize = Math.min(newSize, a.length >>> 1);
 
             @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"})
-            T[] newArray = (T[]) new Object[newSize];
+            T[] newArray = (T[])java.lang.reflect.Array.newInstance
+                (a.getClass().getComponentType(), newSize);
             tmp = newArray;
+            tmpLen = newSize;
+            tmpBase = 0;
         }
         return tmp;
     }
-
-    /**
-     * Checks that fromIndex and toIndex are in range, and throws an
-     * appropriate exception if they aren't.
-     *
-     * @param arrayLen the length of the array
-     * @param fromIndex the index of the first element of the range
-     * @param toIndex the index after the last element of the range
-     * @throws IllegalArgumentException if fromIndex > toIndex
-     * @throws ArrayIndexOutOfBoundsException if fromIndex < 0
-     *         or toIndex > arrayLen
-     */
-    private static void rangeCheck(int arrayLen, int fromIndex, int toIndex) {
-        if (fromIndex > toIndex)
-            throw new IllegalArgumentException("fromIndex(" + fromIndex +
-                       ") > toIndex(" + toIndex+")");
-        if (fromIndex < 0)
-            throw new ArrayIndexOutOfBoundsException(fromIndex);
-        if (toIndex > arrayLen)
-            throw new ArrayIndexOutOfBoundsException(toIndex);
-    }
 }
--- a/jdk/src/share/classes/java/util/WeakHashMap.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/WeakHashMap.java	Mon Jun 10 10:38:33 2013 +0100
@@ -187,11 +187,37 @@
      */
     int modCount;
 
+    private static class Holder {
+        static final boolean USE_HASHSEED;
+
+        static {
+            String hashSeedProp = java.security.AccessController.doPrivileged(
+                    new sun.security.action.GetPropertyAction(
+                        "jdk.map.useRandomSeed"));
+            boolean localBool = (null != hashSeedProp)
+                    ? Boolean.parseBoolean(hashSeedProp) : false;
+            USE_HASHSEED = localBool;
+        }
+    }
+
     /**
      * A randomizing value associated with this instance that is applied to
      * hash code of keys to make hash collisions harder to find.
+     *
+     * Non-final so it can be set lazily, but be sure not to set more than once.
      */
-    transient final int hashSeed = sun.misc.Hashing.randomHashSeed(this);
+    transient int hashSeed;
+
+    /**
+     * Initialize the hashing mask value.
+     */
+    final void initHashSeed() {
+        if (sun.misc.VM.isBooted() && Holder.USE_HASHSEED) {
+            // Do not set hashSeed more than once!
+            // assert hashSeed == 0;
+            hashSeed = sun.misc.Hashing.randomHashSeed(this);
+        }
+    }
 
     @SuppressWarnings("unchecked")
     private Entry<K,V>[] newTable(int n) {
@@ -223,6 +249,7 @@
         table = newTable(capacity);
         this.loadFactor = loadFactor;
         threshold = (int)(capacity * loadFactor);
+        initHashSeed();
     }
 
     /**
@@ -298,10 +325,7 @@
      * in lower bits.
      */
     final int hash(Object k) {
-        if (k instanceof String) {
-            return ((String) k).hash32();
-        }
-        int  h = hashSeed ^ k.hashCode();
+        int h = hashSeed ^ k.hashCode();
 
         // This function ensures that hashCodes that differ only by
         // constant multiples at each bit position have a bounded
@@ -1076,9 +1100,10 @@
             }
             else
                 mc = expectedModCount;
-            if (tab.length >= hi && (i = index) >= 0 && i < hi) {
-                index = hi;
+            if (tab.length >= hi && (i = index) >= 0 &&
+                (i < (index = hi) || current != null)) {
                 WeakHashMap.Entry<K,V> p = current;
+                current = null; // exhaust
                 do {
                     if (p == null)
                         p = tab[i++];
@@ -1155,9 +1180,10 @@
             }
             else
                 mc = expectedModCount;
-            if (tab.length >= hi && (i = index) >= 0 && i < hi) {
-                index = hi;
+            if (tab.length >= hi && (i = index) >= 0 &&
+                (i < (index = hi) || current != null)) {
                 WeakHashMap.Entry<K,V> p = current;
+                current = null; // exhaust
                 do {
                     if (p == null)
                         p = tab[i++];
@@ -1232,9 +1258,10 @@
             }
             else
                 mc = expectedModCount;
-            if (tab.length >= hi && (i = index) >= 0 && i < hi) {
-                index = hi;
+            if (tab.length >= hi && (i = index) >= 0 &&
+                (i < (index = hi) || current != null)) {
                 WeakHashMap.Entry<K,V> p = current;
+                current = null; // exhaust
                 do {
                     if (p == null)
                         p = tab[i++];
--- a/jdk/src/share/classes/java/util/concurrent/ConcurrentHashMap.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/concurrent/ConcurrentHashMap.java	Mon Jun 10 10:38:33 2013 +0100
@@ -34,59 +34,226 @@
  */
 
 package java.util.concurrent;
-import java.io.ObjectInputStream;
-import java.util.concurrent.locks.*;
-import java.util.*;
 import java.io.Serializable;
+import java.io.ObjectStreamField;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.AbstractMap;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.ConcurrentModificationException;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.StampedLock;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.BinaryOperator;
+import java.util.function.Consumer;
+import java.util.function.DoubleBinaryOperator;
+import java.util.function.Function;
+import java.util.function.IntBinaryOperator;
+import java.util.function.LongBinaryOperator;
+import java.util.function.ToDoubleBiFunction;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntBiFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongBiFunction;
+import java.util.function.ToLongFunction;
+import java.util.stream.Stream;
 
 /**
  * A hash table supporting full concurrency of retrievals and
- * adjustable expected concurrency for updates. This class obeys the
+ * high expected concurrency for updates. This class obeys the
  * same functional specification as {@link java.util.Hashtable}, and
  * includes versions of methods corresponding to each method of
- * <tt>Hashtable</tt>. However, even though all operations are
+ * {@code Hashtable}. However, even though all operations are
  * thread-safe, retrieval operations do <em>not</em> entail locking,
  * and there is <em>not</em> any support for locking the entire table
  * in a way that prevents all access.  This class is fully
- * interoperable with <tt>Hashtable</tt> in programs that rely on its
+ * interoperable with {@code Hashtable} in programs that rely on its
  * thread safety but not on its synchronization details.
  *
- * <p> Retrieval operations (including <tt>get</tt>) generally do not
- * block, so may overlap with update operations (including
- * <tt>put</tt> and <tt>remove</tt>). Retrievals reflect the results
- * of the most recently <em>completed</em> update operations holding
- * upon their onset.  For aggregate operations such as <tt>putAll</tt>
- * and <tt>clear</tt>, concurrent retrievals may reflect insertion or
- * removal of only some entries.  Similarly, Iterators and
- * Enumerations return elements reflecting the state of the hash table
- * at some point at or since the creation of the iterator/enumeration.
- * They do <em>not</em> throw {@link ConcurrentModificationException}.
- * However, iterators are designed to be used by only one thread at a time.
+ * <p>Retrieval operations (including {@code get}) generally do not
+ * block, so may overlap with update operations (including {@code put}
+ * and {@code remove}). Retrievals reflect the results of the most
+ * recently <em>completed</em> update operations holding upon their
+ * onset. (More formally, an update operation for a given key bears a
+ * <em>happens-before</em> relation with any (non-null) retrieval for
+ * that key reporting the updated value.)  For aggregate operations
+ * such as {@code putAll} and {@code clear}, concurrent retrievals may
+ * reflect insertion or removal of only some entries.  Similarly,
+ * Iterators and Enumerations return elements reflecting the state of
+ * the hash table at some point at or since the creation of the
+ * iterator/enumeration.  They do <em>not</em> throw {@link
+ * ConcurrentModificationException}.  However, iterators are designed
+ * to be used by only one thread at a time.  Bear in mind that the
+ * results of aggregate status methods including {@code size}, {@code
+ * isEmpty}, and {@code containsValue} are typically useful only when
+ * a map is not undergoing concurrent updates in other threads.
+ * Otherwise the results of these methods reflect transient states
+ * that may be adequate for monitoring or estimation purposes, but not
+ * for program control.
  *
- * <p> The allowed concurrency among update operations is guided by
- * the optional <tt>concurrencyLevel</tt> constructor argument
- * (default <tt>16</tt>), which is used as a hint for internal sizing.  The
- * table is internally partitioned to try to permit the indicated
- * number of concurrent updates without contention. Because placement
- * in hash tables is essentially random, the actual concurrency will
- * vary.  Ideally, you should choose a value to accommodate as many
- * threads as will ever concurrently modify the table. Using a
- * significantly higher value than you need can waste space and time,
- * and a significantly lower value can lead to thread contention. But
- * overestimates and underestimates within an order of magnitude do
- * not usually have much noticeable impact. A value of one is
- * appropriate when it is known that only one thread will modify and
- * all others will only read. Also, resizing this or any other kind of
- * hash table is a relatively slow operation, so, when possible, it is
- * a good idea to provide estimates of expected table sizes in
- * constructors.
+ * <p>The table is dynamically expanded when there are too many
+ * collisions (i.e., keys that have distinct hash codes but fall into
+ * the same slot modulo the table size), with the expected average
+ * effect of maintaining roughly two bins per mapping (corresponding
+ * to a 0.75 load factor threshold for resizing). There may be much
+ * variance around this average as mappings are added and removed, but
+ * overall, this maintains a commonly accepted time/space tradeoff for
+ * hash tables.  However, resizing this or any other kind of hash
+ * table may be a relatively slow operation. When possible, it is a
+ * good idea to provide a size estimate as an optional {@code
+ * initialCapacity} constructor argument. An additional optional
+ * {@code loadFactor} constructor argument provides a further means of
+ * customizing initial table capacity by specifying the table density
+ * to be used in calculating the amount of space to allocate for the
+ * given number of elements.  Also, for compatibility with previous
+ * versions of this class, constructors may optionally specify an
+ * expected {@code concurrencyLevel} as an additional hint for
+ * internal sizing.  Note that using many keys with exactly the same
+ * {@code hashCode()} is a sure way to slow down performance of any
+ * hash table. To ameliorate impact, when keys are {@link Comparable},
+ * this class may use comparison order among keys to help break ties.
+ *
+ * <p>A {@link Set} projection of a ConcurrentHashMap may be created
+ * (using {@link #newKeySet()} or {@link #newKeySet(int)}), or viewed
+ * (using {@link #keySet(Object)} when only keys are of interest, and the
+ * mapped values are (perhaps transiently) not used or all take the
+ * same mapping value.
+ *
+ * <p>A ConcurrentHashMap can be used as scalable frequency map (a
+ * form of histogram or multiset) by using {@link
+ * java.util.concurrent.atomic.LongAdder} values and initializing via
+ * {@link #computeIfAbsent computeIfAbsent}. For example, to add a count
+ * to a {@code ConcurrentHashMap<String,LongAdder> freqs}, you can use
+ * {@code freqs.computeIfAbsent(k -> new LongAdder()).increment();}
  *
  * <p>This class and its views and iterators implement all of the
  * <em>optional</em> methods of the {@link Map} and {@link Iterator}
  * interfaces.
  *
- * <p> Like {@link Hashtable} but unlike {@link HashMap}, this class
- * does <em>not</em> allow <tt>null</tt> to be used as a key or value.
+ * <p>Like {@link Hashtable} but unlike {@link HashMap}, this class
+ * does <em>not</em> allow {@code null} to be used as a key or value.
+ *
+ * <p>ConcurrentHashMaps support a set of sequential and parallel bulk
+ * operations that, unlike most {@link Stream} methods, are designed
+ * to be safely, and often sensibly, applied even with maps that are
+ * being concurrently updated by other threads; for example, when
+ * computing a snapshot summary of the values in a shared registry.
+ * There are three kinds of operation, each with four forms, accepting
+ * functions with Keys, Values, Entries, and (Key, Value) arguments
+ * and/or return values. Because the elements of a ConcurrentHashMap
+ * are not ordered in any particular way, and may be processed in
+ * different orders in different parallel executions, the correctness
+ * of supplied functions should not depend on any ordering, or on any
+ * other objects or values that may transiently change while
+ * computation is in progress; and except for forEach actions, should
+ * ideally be side-effect-free. Bulk operations on {@link java.util.Map.Entry}
+ * objects do not support method {@code setValue}.
+ *
+ * <ul>
+ * <li> forEach: Perform a given action on each element.
+ * A variant form applies a given transformation on each element
+ * before performing the action.</li>
+ *
+ * <li> search: Return the first available non-null result of
+ * applying a given function on each element; skipping further
+ * search when a result is found.</li>
+ *
+ * <li> reduce: Accumulate each element.  The supplied reduction
+ * function cannot rely on ordering (more formally, it should be
+ * both associative and commutative).  There are five variants:
+ *
+ * <ul>
+ *
+ * <li> Plain reductions. (There is not a form of this method for
+ * (key, value) function arguments since there is no corresponding
+ * return type.)</li>
+ *
+ * <li> Mapped reductions that accumulate the results of a given
+ * function applied to each element.</li>
+ *
+ * <li> Reductions to scalar doubles, longs, and ints, using a
+ * given basis value.</li>
+ *
+ * </ul>
+ * </li>
+ * </ul>
+ *
+ * <p>These bulk operations accept a {@code parallelismThreshold}
+ * argument. Methods proceed sequentially if the current map size is
+ * estimated to be less than the given threshold. Using a value of
+ * {@code Long.MAX_VALUE} suppresses all parallelism.  Using a value
+ * of {@code 1} results in maximal parallelism by partitioning into
+ * enough subtasks to fully utilize the {@link
+ * ForkJoinPool#commonPool()} that is used for all parallel
+ * computations. Normally, you would initially choose one of these
+ * extreme values, and then measure performance of using in-between
+ * values that trade off overhead versus throughput.
+ *
+ * <p>The concurrency properties of bulk operations follow
+ * from those of ConcurrentHashMap: Any non-null result returned
+ * from {@code get(key)} and related access methods bears a
+ * happens-before relation with the associated insertion or
+ * update.  The result of any bulk operation reflects the
+ * composition of these per-element relations (but is not
+ * necessarily atomic with respect to the map as a whole unless it
+ * is somehow known to be quiescent).  Conversely, because keys
+ * and values in the map are never null, null serves as a reliable
+ * atomic indicator of the current lack of any result.  To
+ * maintain this property, null serves as an implicit basis for
+ * all non-scalar reduction operations. For the double, long, and
+ * int versions, the basis should be one that, when combined with
+ * any other value, returns that other value (more formally, it
+ * should be the identity element for the reduction). Most common
+ * reductions have these properties; for example, computing a sum
+ * with basis 0 or a minimum with basis MAX_VALUE.
+ *
+ * <p>Search and transformation functions provided as arguments
+ * should similarly return null to indicate the lack of any result
+ * (in which case it is not used). In the case of mapped
+ * reductions, this also enables transformations to serve as
+ * filters, returning null (or, in the case of primitive
+ * specializations, the identity basis) if the element should not
+ * be combined. You can create compound transformations and
+ * filterings by composing them yourself under this "null means
+ * there is nothing there now" rule before using them in search or
+ * reduce operations.
+ *
+ * <p>Methods accepting and/or returning Entry arguments maintain
+ * key-value associations. They may be useful for example when
+ * finding the key for the greatest value. Note that "plain" Entry
+ * arguments can be supplied using {@code new
+ * AbstractMap.SimpleEntry(k,v)}.
+ *
+ * <p>Bulk operations may complete abruptly, throwing an
+ * exception encountered in the application of a supplied
+ * function. Bear in mind when handling such exceptions that other
+ * concurrently executing functions could also have thrown
+ * exceptions, or would have done so if the first exception had
+ * not occurred.
+ *
+ * <p>Speedups for parallel compared to sequential forms are common
+ * but not guaranteed.  Parallel operations involving brief functions
+ * on small maps may execute more slowly than sequential forms if the
+ * underlying work to parallelize the computation is more expensive
+ * than the computation itself.  Similarly, parallelization may not
+ * lead to much actual parallelism if all processors are busy
+ * performing unrelated tasks.
+ *
+ * <p>All arguments to all task methods must be non-null.
  *
  * <p>This class is a member of the
  * <a href="{@docRoot}/../technotes/guides/collections/index.html">
@@ -97,822 +264,2411 @@
  * @param <K> the type of keys maintained by this map
  * @param <V> the type of mapped values
  */
-public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>
-        implements ConcurrentMap<K, V>, Serializable {
+@SuppressWarnings({"unchecked", "rawtypes", "serial"})
+public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
+    implements ConcurrentMap<K,V>, Serializable {
+
     private static final long serialVersionUID = 7249069246763182397L;
 
     /*
-     * The basic strategy is to subdivide the table among Segments,
-     * each of which itself is a concurrently readable hash table.  To
-     * reduce footprint, all but one segments are constructed only
-     * when first needed (see ensureSegment). To maintain visibility
-     * in the presence of lazy construction, accesses to segments as
-     * well as elements of segment's table must use volatile access,
-     * which is done via Unsafe within methods segmentAt etc
-     * below. These provide the functionality of AtomicReferenceArrays
-     * but reduce the levels of indirection. Additionally,
-     * volatile-writes of table elements and entry "next" fields
-     * within locked operations use the cheaper "lazySet" forms of
-     * writes (via putOrderedObject) because these writes are always
-     * followed by lock releases that maintain sequential consistency
-     * of table updates.
+     * Overview:
+     *
+     * The primary design goal of this hash table is to maintain
+     * concurrent readability (typically method get(), but also
+     * iterators and related methods) while minimizing update
+     * contention. Secondary goals are to keep space consumption about
+     * the same or better than java.util.HashMap, and to support high
+     * initial insertion rates on an empty table by many threads.
+     *
+     * Each key-value mapping is held in a Node.  Because Node key
+     * fields can contain special values, they are defined using plain
+     * Object types (not type "K"). This leads to a lot of explicit
+     * casting (and the use of class-wide warning suppressions).  It
+     * also allows some of the public methods to be factored into a
+     * smaller number of internal methods (although sadly not so for
+     * the five variants of put-related operations). The
+     * validation-based approach explained below leads to a lot of
+     * code sprawl because retry-control precludes factoring into
+     * smaller methods.
+     *
+     * The table is lazily initialized to a power-of-two size upon the
+     * first insertion.  Each bin in the table normally contains a
+     * list of Nodes (most often, the list has only zero or one Node).
+     * Table accesses require volatile/atomic reads, writes, and
+     * CASes.  Because there is no other way to arrange this without
+     * adding further indirections, we use intrinsics
+     * (sun.misc.Unsafe) operations.
+     *
+     * We use the top (sign) bit of Node hash fields for control
+     * purposes -- it is available anyway because of addressing
+     * constraints.  Nodes with negative hash fields are forwarding
+     * nodes to either TreeBins or resized tables.  The lower 31 bits
+     * of each normal Node's hash field contain a transformation of
+     * the key's hash code.
+     *
+     * Insertion (via put or its variants) of the first node in an
+     * empty bin is performed by just CASing it to the bin.  This is
+     * by far the most common case for put operations under most
+     * key/hash distributions.  Other update operations (insert,
+     * delete, and replace) require locks.  We do not want to waste
+     * the space required to associate a distinct lock object with
+     * each bin, so instead use the first node of a bin list itself as
+     * a lock. Locking support for these locks relies on builtin
+     * "synchronized" monitors.
+     *
+     * Using the first node of a list as a lock does not by itself
+     * suffice though: When a node is locked, any update must first
+     * validate that it is still the first node after locking it, and
+     * retry if not. Because new nodes are always appended to lists,
+     * once a node is first in a bin, it remains first until deleted
+     * or the bin becomes invalidated (upon resizing).
+     *
+     * The main disadvantage of per-bin locks is that other update
+     * operations on other nodes in a bin list protected by the same
+     * lock can stall, for example when user equals() or mapping
+     * functions take a long time.  However, statistically, under
+     * random hash codes, this is not a common problem.  Ideally, the
+     * frequency of nodes in bins follows a Poisson distribution
+     * (http://en.wikipedia.org/wiki/Poisson_distribution) with a
+     * parameter of about 0.5 on average, given the resizing threshold
+     * of 0.75, although with a large variance because of resizing
+     * granularity. Ignoring variance, the expected occurrences of
+     * list size k are (exp(-0.5) * pow(0.5, k) / factorial(k)). The
+     * first values are:
+     *
+     * 0:    0.60653066
+     * 1:    0.30326533
+     * 2:    0.07581633
+     * 3:    0.01263606
+     * 4:    0.00157952
+     * 5:    0.00015795
+     * 6:    0.00001316
+     * 7:    0.00000094
+     * 8:    0.00000006
+     * more: less than 1 in ten million
+     *
+     * Lock contention probability for two threads accessing distinct
+     * elements is roughly 1 / (8 * #elements) under random hashes.
      *
-     * Historical note: The previous version of this class relied
-     * heavily on "final" fields, which avoided some volatile reads at
-     * the expense of a large initial footprint.  Some remnants of
-     * that design (including forced construction of segment 0) exist
-     * to ensure serialization compatibility.
+     * Actual hash code distributions encountered in practice
+     * sometimes deviate significantly from uniform randomness.  This
+     * includes the case when N > (1<<30), so some keys MUST collide.
+     * Similarly for dumb or hostile usages in which multiple keys are
+     * designed to have identical hash codes. Also, although we guard
+     * against the worst effects of this (see method spread), sets of
+     * hashes may differ only in bits that do not impact their bin
+     * index for a given power-of-two mask.  So we use a secondary
+     * strategy that applies when the number of nodes in a bin exceeds
+     * a threshold, and at least one of the keys implements
+     * Comparable.  These TreeBins use a balanced tree to hold nodes
+     * (a specialized form of red-black trees), bounding search time
+     * to O(log N).  Each search step in a TreeBin is at least twice as
+     * slow as in a regular list, but given that N cannot exceed
+     * (1<<64) (before running out of addresses) this bounds search
+     * steps, lock hold times, etc, to reasonable constants (roughly
+     * 100 nodes inspected per operation worst case) so long as keys
+     * are Comparable (which is very common -- String, Long, etc).
+     * TreeBin nodes (TreeNodes) also maintain the same "next"
+     * traversal pointers as regular nodes, so can be traversed in
+     * iterators in the same way.
+     *
+     * The table is resized when occupancy exceeds a percentage
+     * threshold (nominally, 0.75, but see below).  Any thread
+     * noticing an overfull bin may assist in resizing after the
+     * initiating thread allocates and sets up the replacement
+     * array. However, rather than stalling, these other threads may
+     * proceed with insertions etc.  The use of TreeBins shields us
+     * from the worst case effects of overfilling while resizes are in
+     * progress.  Resizing proceeds by transferring bins, one by one,
+     * from the table to the next table. To enable concurrency, the
+     * next table must be (incrementally) prefilled with place-holders
+     * serving as reverse forwarders to the old table.  Because we are
+     * using power-of-two expansion, the elements from each bin must
+     * either stay at same index, or move with a power of two
+     * offset. We eliminate unnecessary node creation by catching
+     * cases where old nodes can be reused because their next fields
+     * won't change.  On average, only about one-sixth of them need
+     * cloning when a table doubles. The nodes they replace will be
+     * garbage collectable as soon as they are no longer referenced by
+     * any reader thread that may be in the midst of concurrently
+     * traversing table.  Upon transfer, the old table bin contains
+     * only a special forwarding node (with hash field "MOVED") that
+     * contains the next table as its key. On encountering a
+     * forwarding node, access and update operations restart, using
+     * the new table.
+     *
+     * Each bin transfer requires its bin lock, which can stall
+     * waiting for locks while resizing. However, because other
+     * threads can join in and help resize rather than contend for
+     * locks, average aggregate waits become shorter as resizing
+     * progresses.  The transfer operation must also ensure that all
+     * accessible bins in both the old and new table are usable by any
+     * traversal.  This is arranged by proceeding from the last bin
+     * (table.length - 1) up towards the first.  Upon seeing a
+     * forwarding node, traversals (see class Traverser) arrange to
+     * move to the new table without revisiting nodes.  However, to
+     * ensure that no intervening nodes are skipped, bin splitting can
+     * only begin after the associated reverse-forwarders are in
+     * place.
+     *
+     * The traversal scheme also applies to partial traversals of
+     * ranges of bins (via an alternate Traverser constructor)
+     * to support partitioned aggregate operations.  Also, read-only
+     * operations give up if ever forwarded to a null table, which
+     * provides support for shutdown-style clearing, which is also not
+     * currently implemented.
+     *
+     * Lazy table initialization minimizes footprint until first use,
+     * and also avoids resizings when the first operation is from a
+     * putAll, constructor with map argument, or deserialization.
+     * These cases attempt to override the initial capacity settings,
+     * but harmlessly fail to take effect in cases of races.
+     *
+     * The element count is maintained using a specialization of
+     * LongAdder. We need to incorporate a specialization rather than
+     * just use a LongAdder in order to access implicit
+     * contention-sensing that leads to creation of multiple
+     * Cells.  The counter mechanics avoid contention on
+     * updates but can encounter cache thrashing if read too
+     * frequently during concurrent access. To avoid reading so often,
+     * resizing under contention is attempted only upon adding to a
+     * bin already holding two or more nodes. Under uniform hash
+     * distributions, the probability of this occurring at threshold
+     * is around 13%, meaning that only about 1 in 8 puts check
+     * threshold (and after resizing, many fewer do so). The bulk
+     * putAll operation further reduces contention by only committing
+     * count updates upon these size checks.
+     *
+     * Maintaining API and serialization compatibility with previous
+     * versions of this class introduces several oddities. Mainly: We
+     * leave untouched but unused constructor arguments refering to
+     * concurrencyLevel. We accept a loadFactor constructor argument,
+     * but apply it only to initial table capacity (which is the only
+     * time that we can guarantee to honor it.) We also declare an
+     * unused "Segment" class that is instantiated in minimal form
+     * only when serializing.
      */
 
     /* ---------------- Constants -------------- */
 
     /**
-     * The default initial capacity for this table,
-     * used when not otherwise specified in a constructor.
+     * The largest possible table capacity.  This value must be
+     * exactly 1<<30 to stay within Java array allocation and indexing
+     * bounds for power of two table sizes, and is further required
+     * because the top two bits of 32bit hash fields are used for
+     * control purposes.
      */
-    static final int DEFAULT_INITIAL_CAPACITY = 16;
+    private static final int MAXIMUM_CAPACITY = 1 << 30;
+
+    /**
+     * The default initial table capacity.  Must be a power of 2
+     * (i.e., at least 1) and at most MAXIMUM_CAPACITY.
+     */
+    private static final int DEFAULT_CAPACITY = 16;
 
     /**
-     * The default load factor for this table, used when not
-     * otherwise specified in a constructor.
+     * The largest possible (non-power of two) array size.
+     * Needed by toArray and related methods.
      */
-    static final float DEFAULT_LOAD_FACTOR = 0.75f;
+    static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
 
     /**
-     * The default concurrency level for this table, used when not
-     * otherwise specified in a constructor.
+     * The default concurrency level for this table. Unused but
+     * defined for compatibility with previous versions of this class.
      */
-    static final int DEFAULT_CONCURRENCY_LEVEL = 16;
+    private static final int DEFAULT_CONCURRENCY_LEVEL = 16;
+
+    /**
+     * The load factor for this table. Overrides of this value in
+     * constructors affect only the initial table capacity.  The
+     * actual floating point value isn't normally used -- it is
+     * simpler to use expressions such as {@code n - (n >>> 2)} for
+     * the associated resizing threshold.
+     */
+    private static final float LOAD_FACTOR = 0.75f;
 
     /**
-     * The maximum capacity, used if a higher value is implicitly
-     * specified by either of the constructors with arguments.  MUST
-     * be a power of two <= 1<<30 to ensure that entries are indexable
-     * using ints.
+     * The bin count threshold for using a tree rather than list for a
+     * bin.  The value reflects the approximate break-even point for
+     * using tree-based operations.
      */
-    static final int MAXIMUM_CAPACITY = 1 << 30;
+    private static final int TREE_THRESHOLD = 8;
 
     /**
-     * The minimum capacity for per-segment tables.  Must be a power
-     * of two, at least two to avoid immediate resizing on next use
-     * after lazy construction.
+     * Minimum number of rebinnings per transfer step. Ranges are
+     * subdivided to allow multiple resizer threads.  This value
+     * serves as a lower bound to avoid resizers encountering
+     * excessive memory contention.  The value should be at least
+     * DEFAULT_CAPACITY.
+     */
+    private static final int MIN_TRANSFER_STRIDE = 16;
+
+    /*
+     * Encodings for Node hash fields. See above for explanation.
      */
-    static final int MIN_SEGMENT_TABLE_CAPACITY = 2;
+    static final int MOVED     = 0x80000000; // hash field for forwarding nodes
+    static final int HASH_BITS = 0x7fffffff; // usable bits of normal node hash
+
+    /** Number of CPUS, to place bounds on some sizings */
+    static final int NCPU = Runtime.getRuntime().availableProcessors();
+
+    /** For serialization compatibility. */
+    private static final ObjectStreamField[] serialPersistentFields = {
+        new ObjectStreamField("segments", Segment[].class),
+        new ObjectStreamField("segmentMask", Integer.TYPE),
+        new ObjectStreamField("segmentShift", Integer.TYPE)
+    };
 
     /**
-     * The maximum number of segments to allow; used to bound
-     * constructor arguments. Must be power of two less than 1 << 24.
+     * A padded cell for distributing counts.  Adapted from LongAdder
+     * and Striped64.  See their internal docs for explanation.
      */
-    static final int MAX_SEGMENTS = 1 << 16; // slightly conservative
-
-    /**
-     * Number of unsynchronized retries in size and containsValue
-     * methods before resorting to locking. This is used to avoid
-     * unbounded retries if tables undergo continuous modification
-     * which would make it impossible to obtain an accurate result.
-     */
-    static final int RETRIES_BEFORE_LOCK = 2;
+    @sun.misc.Contended static final class Cell {
+        volatile long value;
+        Cell(long x) { value = x; }
+    }
 
     /* ---------------- Fields -------------- */
 
     /**
-     * A randomizing value associated with this instance that is applied to
-     * hash code of keys to make hash collisions harder to find.
+     * The array of bins. Lazily initialized upon first insertion.
+     * Size is always a power of two. Accessed directly by iterators.
+     */
+    transient volatile Node<K,V>[] table;
+
+    /**
+     * The next table to use; non-null only while resizing.
+     */
+    private transient volatile Node<K,V>[] nextTable;
+
+    /**
+     * Base counter value, used mainly when there is no contention,
+     * but also as a fallback during table initialization
+     * races. Updated via CAS.
+     */
+    private transient volatile long baseCount;
+
+    /**
+     * Table initialization and resizing control.  When negative, the
+     * table is being initialized or resized: -1 for initialization,
+     * else -(1 + the number of active resizing threads).  Otherwise,
+     * when table is null, holds the initial table size to use upon
+     * creation, or 0 for default. After initialization, holds the
+     * next element count value upon which to resize the table.
+     */
+    private transient volatile int sizeCtl;
+
+    /**
+     * The next table index (plus one) to split while resizing.
+     */
+    private transient volatile int transferIndex;
+
+    /**
+     * The least available table index to split while resizing.
+     */
+    private transient volatile int transferOrigin;
+
+    /**
+     * Spinlock (locked via CAS) used when resizing and/or creating Cells.
      */
-   private transient final int hashSeed = sun.misc.Hashing.randomHashSeed(this);
+    private transient volatile int cellsBusy;
+
+    /**
+     * Table of counter cells. When non-null, size is a power of 2.
+     */
+    private transient volatile Cell[] counterCells;
+
+    // views
+    private transient KeySetView<K,V> keySet;
+    private transient ValuesView<K,V> values;
+    private transient EntrySetView<K,V> entrySet;
+
+    /* ---------------- Table element access -------------- */
+
+    /*
+     * Volatile access methods are used for table elements as well as
+     * elements of in-progress next table while resizing.  Uses are
+     * null checked by callers, and implicitly bounds-checked, relying
+     * on the invariants that tab arrays have non-zero size, and all
+     * indices are masked with (tab.length - 1) which is never
+     * negative and always less than length. Note that, to be correct
+     * wrt arbitrary concurrency errors by users, bounds checks must
+     * operate on local variables, which accounts for some odd-looking
+     * inline assignments below.
+     */
+
+    static final <K,V> Node<K,V> tabAt(Node<K,V>[] tab, int i) {
+        return (Node<K,V>)U.getObjectVolatile(tab, ((long)i << ASHIFT) + ABASE);
+    }
+
+    static final <K,V> boolean casTabAt(Node<K,V>[] tab, int i,
+                                        Node<K,V> c, Node<K,V> v) {
+        return U.compareAndSwapObject(tab, ((long)i << ASHIFT) + ABASE, c, v);
+    }
+
+    static final <K,V> void setTabAt(Node<K,V>[] tab, int i, Node<K,V> v) {
+        U.putObjectVolatile(tab, ((long)i << ASHIFT) + ABASE, v);
+    }
+
+    /* ---------------- Nodes -------------- */
 
     /**
-     * Mask value for indexing into segments. The upper bits of a
-     * key's hash code are used to choose the segment.
+     * Key-value entry.  This class is never exported out as a
+     * user-mutable Map.Entry (i.e., one supporting setValue; see
+     * MapEntry below), but can be used for read-only traversals used
+     * in bulk tasks.  Nodes with a hash field of MOVED are special,
+     * and do not contain user keys or values (and are never
+     * exported).  Otherwise, keys and vals are never null.
      */
-    final int segmentMask;
+    static class Node<K,V> implements Map.Entry<K,V> {
+        final int hash;
+        final Object key;
+        volatile V val;
+        Node<K,V> next;
+
+        Node(int hash, Object key, V val, Node<K,V> next) {
+            this.hash = hash;
+            this.key = key;
+            this.val = val;
+            this.next = next;
+        }
+
+        public final K getKey()       { return (K)key; }
+        public final V getValue()     { return val; }
+        public final int hashCode()   { return key.hashCode() ^ val.hashCode(); }
+        public final String toString(){ return key + "=" + val; }
+        public final V setValue(V value) {
+            throw new UnsupportedOperationException();
+        }
+
+        public final boolean equals(Object o) {
+            Object k, v, u; Map.Entry<?,?> e;
+            return ((o instanceof Map.Entry) &&
+                    (k = (e = (Map.Entry<?,?>)o).getKey()) != null &&
+                    (v = e.getValue()) != null &&
+                    (k == key || k.equals(key)) &&
+                    (v == (u = val) || v.equals(u)));
+        }
+    }
 
     /**
-     * Shift value for indexing within segments.
+     * Exported Entry for EntryIterator
      */
-    final int segmentShift;
+    static final class MapEntry<K,V> implements Map.Entry<K,V> {
+        final K key; // non-null
+        V val;       // non-null
+        final ConcurrentHashMap<K,V> map;
+        MapEntry(K key, V val, ConcurrentHashMap<K,V> map) {
+            this.key = key;
+            this.val = val;
+            this.map = map;
+        }
+        public K getKey()        { return key; }
+        public V getValue()      { return val; }
+        public int hashCode()    { return key.hashCode() ^ val.hashCode(); }
+        public String toString() { return key + "=" + val; }
+
+        public boolean equals(Object o) {
+            Object k, v; Map.Entry<?,?> e;
+            return ((o instanceof Map.Entry) &&
+                    (k = (e = (Map.Entry<?,?>)o).getKey()) != null &&
+                    (v = e.getValue()) != null &&
+                    (k == key || k.equals(key)) &&
+                    (v == val || v.equals(val)));
+        }
+
+        /**
+         * Sets our entry's value and writes through to the map. The
+         * value to return is somewhat arbitrary here. Since we do not
+         * necessarily track asynchronous changes, the most recent
+         * "previous" value could be different from what we return (or
+         * could even have been removed, in which case the put will
+         * re-establish). We do not and cannot guarantee more.
+         */
+        public V setValue(V value) {
+            if (value == null) throw new NullPointerException();
+            V v = val;
+            val = value;
+            map.put(key, value);
+            return v;
+        }
+    }
+
+
+    /* ---------------- TreeBins -------------- */
+
+    /**
+     * Nodes for use in TreeBins
+     */
+    static final class TreeNode<K,V> extends Node<K,V> {
+        TreeNode<K,V> parent;  // red-black tree links
+        TreeNode<K,V> left;
+        TreeNode<K,V> right;
+        TreeNode<K,V> prev;    // needed to unlink next upon deletion
+        boolean red;
+
+        TreeNode(int hash, Object key, V val, Node<K,V> next,
+                 TreeNode<K,V> parent) {
+            super(hash, key, val, next);
+            this.parent = parent;
+        }
+    }
+
+    /**
+     * Returns a Class for the given type of the form "class C
+     * implements Comparable<C>", if one exists, else null.  See below
+     * for explanation.
+     */
+    static Class<?> comparableClassFor(Class<?> c) {
+        Class<?> s, cmpc; Type[] ts, as; Type t; ParameterizedType p;
+        if (c == String.class) // bypass checks
+            return c;
+        if (c != null && (cmpc = Comparable.class).isAssignableFrom(c)) {
+            while (cmpc.isAssignableFrom(s = c.getSuperclass()))
+                c = s; // find topmost comparable class
+            if ((ts = c.getGenericInterfaces()) != null) {
+                for (int i = 0; i < ts.length; ++i) {
+                    if (((t = ts[i]) instanceof ParameterizedType) &&
+                        ((p = (ParameterizedType)t).getRawType() == cmpc) &&
+                        (as = p.getActualTypeArguments()) != null &&
+                        as.length == 1 && as[0] == c) // type arg is c
+                        return c;
+                }
+            }
+        }
+        return null;
+    }
 
     /**
-     * The segments, each of which is a specialized hash table.
-     */
-    final Segment<K,V>[] segments;
-
-    transient Set<K> keySet;
-    transient Set<Map.Entry<K,V>> entrySet;
-    transient Collection<V> values;
-
-    /**
-     * ConcurrentHashMap list entry. Note that this is never exported
-     * out as a user-visible Map.Entry.
+     * A specialized form of red-black tree for use in bins
+     * whose size exceeds a threshold.
+     *
+     * TreeBins use a special form of comparison for search and
+     * related operations (which is the main reason we cannot use
+     * existing collections such as TreeMaps). TreeBins contain
+     * Comparable elements, but may contain others, as well as
+     * elements that are Comparable but not necessarily Comparable
+     * for the same T, so we cannot invoke compareTo among them. To
+     * handle this, the tree is ordered primarily by hash value, then
+     * by Comparable.compareTo order if applicable.  On lookup at a
+     * node, if elements are not comparable or compare as 0 then both
+     * left and right children may need to be searched in the case of
+     * tied hash values. (This corresponds to the full list search
+     * that would be necessary if all elements were non-Comparable and
+     * had tied hashes.)  The red-black balancing code is updated from
+     * pre-jdk-collections
+     * (http://gee.cs.oswego.edu/dl/classes/collections/RBCell.java)
+     * based in turn on Cormen, Leiserson, and Rivest "Introduction to
+     * Algorithms" (CLR).
+     *
+     * TreeBins also maintain a separate locking discipline than
+     * regular bins. Because they are forwarded via special MOVED
+     * nodes at bin heads (which can never change once established),
+     * we cannot use those nodes as locks. Instead, TreeBin extends
+     * StampedLock to support a form of read-write lock. For update
+     * operations and table validation, the exclusive form of lock
+     * behaves in the same way as bin-head locks. However, lookups use
+     * shared read-lock mechanics to allow multiple readers in the
+     * absence of writers.  Additionally, these lookups do not ever
+     * block: While the lock is not available, they proceed along the
+     * slow traversal path (via next-pointers) until the lock becomes
+     * available or the list is exhausted, whichever comes
+     * first. These cases are not fast, but maximize aggregate
+     * expected throughput.
      */
-    static final class HashEntry<K,V> {
-        final int hash;
-        final K key;
-        volatile V value;
-        volatile HashEntry<K,V> next;
-
-        HashEntry(int hash, K key, V value, HashEntry<K,V> next) {
-            this.hash = hash;
-            this.key = key;
-            this.value = value;
-            this.next = next;
+    static final class TreeBin<K,V> extends StampedLock {
+        private static final long serialVersionUID = 2249069246763182397L;
+        transient TreeNode<K,V> root;  // root of tree
+        transient TreeNode<K,V> first; // head of next-pointer list
+
+        /** From CLR */
+        private void rotateLeft(TreeNode<K,V> p) {
+            if (p != null) {
+                TreeNode<K,V> r = p.right, pp, rl;
+                if ((rl = p.right = r.left) != null)
+                    rl.parent = p;
+                if ((pp = r.parent = p.parent) == null)
+                    root = r;
+                else if (pp.left == p)
+                    pp.left = r;
+                else
+                    pp.right = r;
+                r.left = p;
+                p.parent = r;
+            }
+        }
+
+        /** From CLR */
+        private void rotateRight(TreeNode<K,V> p) {
+            if (p != null) {
+                TreeNode<K,V> l = p.left, pp, lr;
+                if ((lr = p.left = l.right) != null)
+                    lr.parent = p;
+                if ((pp = l.parent = p.parent) == null)
+                    root = l;
+                else if (pp.right == p)
+                    pp.right = l;
+                else
+                    pp.left = l;
+                l.right = p;
+                p.parent = l;
+            }
+        }
+
+        /**
+         * Returns the TreeNode (or null if not found) for the given key
+         * starting at given root.
+         */
+        final TreeNode<K,V> getTreeNode(int h, Object k, TreeNode<K,V> p,
+                                        Class<?> cc) {
+            while (p != null) {
+                int dir, ph; Object pk; Class<?> pc;
+                if ((ph = p.hash) != h)
+                    dir = (h < ph) ? -1 : 1;
+                else if ((pk = p.key) == k || k.equals(pk))
+                    return p;
+                else if (cc == null || pk == null ||
+                         ((pc = pk.getClass()) != cc &&
+                          comparableClassFor(pc) != cc) ||
+                         (dir = ((Comparable<Object>)k).compareTo(pk)) == 0) {
+                    TreeNode<K,V> r, pr; // check both sides
+                    if ((pr = p.right) != null &&
+                        (r = getTreeNode(h, k, pr, cc)) != null)
+                        return r;
+                    else // continue left
+                        dir = -1;
+                }
+                p = (dir > 0) ? p.right : p.left;
+            }
+            return null;
+        }
+
+        /**
+         * Wrapper for getTreeNode used by CHM.get. Tries to obtain
+         * read-lock to call getTreeNode, but during failure to get
+         * lock, searches along next links.
+         */
+        final V getValue(int h, Object k) {
+            Class<?> cc = comparableClassFor(k.getClass());
+            Node<K,V> r = null;
+            for (Node<K,V> e = first; e != null; e = e.next) {
+                long s;
+                if ((s = tryReadLock()) != 0L) {
+                    try {
+                        r = getTreeNode(h, k, root, cc);
+                    } finally {
+                        unlockRead(s);
+                    }
+                    break;
+                }
+                else if (e.hash == h && k.equals(e.key)) {
+                    r = e;
+                    break;
+                }
+            }
+            return r == null ? null : r.val;
+        }
+
+        /**
+         * Finds or adds a node.
+         * @return null if added
+         */
+        final TreeNode<K,V> putTreeNode(int h, Object k, V v) {
+            Class<?> cc = comparableClassFor(k.getClass());
+            TreeNode<K,V> pp = root, p = null;
+            int dir = 0;
+            while (pp != null) { // find existing node or leaf to insert at
+                int ph; Object pk; Class<?> pc;
+                p = pp;
+                if ((ph = p.hash) != h)
+                    dir = (h < ph) ? -1 : 1;
+                else if ((pk = p.key) == k || k.equals(pk))
+                    return p;
+                else if (cc == null || pk == null ||
+                         ((pc = pk.getClass()) != cc &&
+                          comparableClassFor(pc) != cc) ||
+                         (dir = ((Comparable<Object>)k).compareTo(pk)) == 0) {
+                    TreeNode<K,V> r, pr;
+                    if ((pr = p.right) != null &&
+                        (r = getTreeNode(h, k, pr, cc)) != null)
+                        return r;
+                    else // continue left
+                        dir = -1;
+                }
+                pp = (dir > 0) ? p.right : p.left;
+            }
+
+            TreeNode<K,V> f = first;
+            TreeNode<K,V> x = first = new TreeNode<K,V>(h, k, v, f, p);
+            if (p == null)
+                root = x;
+            else { // attach and rebalance; adapted from CLR
+                if (f != null)
+                    f.prev = x;
+                if (dir <= 0)
+                    p.left = x;
+                else
+                    p.right = x;
+                x.red = true;
+                for (TreeNode<K,V> xp, xpp, xppl, xppr;;) {
+                    if ((xp = x.parent) == null) {
+                        (root = x).red = false;
+                        break;
+                    }
+                    else if (!xp.red || (xpp = xp.parent) == null) {
+                        TreeNode<K,V> r = root;
+                        if (r != null && r.red)
+                            r.red = false;
+                        break;
+                    }
+                    else if ((xppl = xpp.left) == xp) {
+                        if ((xppr = xpp.right) != null && xppr.red) {
+                            xppr.red = false;
+                            xp.red = false;
+                            xpp.red = true;
+                            x = xpp;
+                        }
+                        else {
+                            if (x == xp.right) {
+                                rotateLeft(x = xp);
+                                xpp = (xp = x.parent) == null ? null : xp.parent;
+                            }
+                            if (xp != null) {
+                                xp.red = false;
+                                if (xpp != null) {
+                                    xpp.red = true;
+                                    rotateRight(xpp);
+                                }
+                            }
+                        }
+                    }
+                    else {
+                        if (xppl != null && xppl.red) {
+                            xppl.red = false;
+                            xp.red = false;
+                            xpp.red = true;
+                            x = xpp;
+                        }
+                        else {
+                            if (x == xp.left) {
+                                rotateRight(x = xp);
+                                xpp = (xp = x.parent) == null ? null : xp.parent;
+                            }
+                            if (xp != null) {
+                                xp.red = false;
+                                if (xpp != null) {
+                                    xpp.red = true;
+                                    rotateLeft(xpp);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            assert checkInvariants();
+            return null;
+        }
+
+        /**
+         * Removes the given node, that must be present before this
+         * call.  This is messier than typical red-black deletion code
+         * because we cannot swap the contents of an interior node
+         * with a leaf successor that is pinned by "next" pointers
+         * that are accessible independently of lock. So instead we
+         * swap the tree linkages.
+         */
+        final void deleteTreeNode(TreeNode<K,V> p) {
+            TreeNode<K,V> next = (TreeNode<K,V>)p.next;
+            TreeNode<K,V> pred = p.prev;  // unlink traversal pointers
+            if (pred == null)
+                first = next;
+            else
+                pred.next = next;
+            if (next != null)
+                next.prev = pred;
+            else if (pred == null) {
+                root = null;
+                return;
+            }
+            TreeNode<K,V> replacement;
+            TreeNode<K,V> pl = p.left;
+            TreeNode<K,V> pr = p.right;
+            if (pl != null && pr != null) {
+                TreeNode<K,V> s = pr, sl;
+                while ((sl = s.left) != null) // find successor
+                    s = sl;
+                boolean c = s.red; s.red = p.red; p.red = c; // swap colors
+                TreeNode<K,V> sr = s.right;
+                TreeNode<K,V> pp = p.parent;
+                if (s == pr) { // p was s's direct parent
+                    p.parent = s;
+                    s.right = p;
+                }
+                else {
+                    TreeNode<K,V> sp = s.parent;
+                    if ((p.parent = sp) != null) {
+                        if (s == sp.left)
+                            sp.left = p;
+                        else
+                            sp.right = p;
+                    }
+                    if ((s.right = pr) != null)
+                        pr.parent = s;
+                }
+                p.left = null;
+                if ((p.right = sr) != null)
+                    sr.parent = p;
+                if ((s.left = pl) != null)
+                    pl.parent = s;
+                if ((s.parent = pp) == null)
+                    root = s;
+                else if (p == pp.left)
+                    pp.left = s;
+                else
+                    pp.right = s;
+                if (sr != null)
+                    replacement = sr;
+                else
+                    replacement = p;
+            }
+            else if (pl != null)
+                replacement = pl;
+            else if (pr != null)
+                replacement = pr;
+            else
+                replacement = p;
+            if (replacement != p) {
+                TreeNode<K,V> pp = replacement.parent = p.parent;
+                if (pp == null)
+                    root = replacement;
+                else if (p == pp.left)
+                    pp.left = replacement;
+                else
+                    pp.right = replacement;
+                p.left = p.right = p.parent = null;
+            }
+            if (!p.red) { // rebalance, from CLR
+                for (TreeNode<K,V> x = replacement; x != null; ) {
+                    TreeNode<K,V> xp, xpl, xpr;
+                    if (x.red || (xp = x.parent) == null) {
+                        x.red = false;
+                        break;
+                    }
+                    else if ((xpl = xp.left) == x) {
+                        if ((xpr = xp.right) != null && xpr.red) {
+                            xpr.red = false;
+                            xp.red = true;
+                            rotateLeft(xp);
+                            xpr = (xp = x.parent) == null ? null : xp.right;
+                        }
+                        if (xpr == null)
+                            x = xp;
+                        else {
+                            TreeNode<K,V> sl = xpr.left, sr = xpr.right;
+                            if ((sr == null || !sr.red) &&
+                                (sl == null || !sl.red)) {
+                                xpr.red = true;
+                                x = xp;
+                            }
+                            else {
+                                if (sr == null || !sr.red) {
+                                    if (sl != null)
+                                        sl.red = false;
+                                    xpr.red = true;
+                                    rotateRight(xpr);
+                                    xpr = (xp = x.parent) == null ?
+                                        null : xp.right;
+                                }
+                                if (xpr != null) {
+                                    xpr.red = (xp == null) ? false : xp.red;
+                                    if ((sr = xpr.right) != null)
+                                        sr.red = false;
+                                }
+                                if (xp != null) {
+                                    xp.red = false;
+                                    rotateLeft(xp);
+                                }
+                                x = root;
+                            }
+                        }
+                    }
+                    else { // symmetric
+                        if (xpl != null && xpl.red) {
+                            xpl.red = false;
+                            xp.red = true;
+                            rotateRight(xp);
+                            xpl = (xp = x.parent) == null ? null : xp.left;
+                        }
+                        if (xpl == null)
+                            x = xp;
+                        else {
+                            TreeNode<K,V> sl = xpl.left, sr = xpl.right;
+                            if ((sl == null || !sl.red) &&
+                                (sr == null || !sr.red)) {
+                                xpl.red = true;
+                                x = xp;
+                            }
+                            else {
+                                if (sl == null || !sl.red) {
+                                    if (sr != null)
+                                        sr.red = false;
+                                    xpl.red = true;
+                                    rotateLeft(xpl);
+                                    xpl = (xp = x.parent) == null ?
+                                        null : xp.left;
+                                }
+                                if (xpl != null) {
+                                    xpl.red = (xp == null) ? false : xp.red;
+                                    if ((sl = xpl.left) != null)
+                                        sl.red = false;
+                                }
+                                if (xp != null) {
+                                    xp.red = false;
+                                    rotateRight(xp);
+                                }
+                                x = root;
+                            }
+                        }
+                    }
+                }
+            }
+            if (p == replacement) {  // detach pointers
+                TreeNode<K,V> pp;
+                if ((pp = p.parent) != null) {
+                    if (p == pp.left)
+                        pp.left = null;
+                    else if (p == pp.right)
+                        pp.right = null;
+                    p.parent = null;
+                }
+            }
+            assert checkInvariants();
+        }
+
+        /**
+         * Checks linkage and balance invariants at root
+         */
+        final boolean checkInvariants() {
+            TreeNode<K,V> r = root;
+            if (r == null)
+                return (first == null);
+            else
+                return (first != null) && checkTreeNode(r);
         }
 
         /**
-         * Sets next field with volatile write semantics.  (See above
-         * about use of putOrderedObject.)
+         * Recursive invariant check
          */
-        final void setNext(HashEntry<K,V> n) {
-            UNSAFE.putOrderedObject(this, nextOffset, n);
+        final boolean checkTreeNode(TreeNode<K,V> t) {
+            TreeNode<K,V> tp = t.parent, tl = t.left, tr = t.right,
+                tb = t.prev, tn = (TreeNode<K,V>)t.next;
+            if (tb != null && tb.next != t)
+                return false;
+            if (tn != null && tn.prev != t)
+                return false;
+            if (tp != null && t != tp.left && t != tp.right)
+                return false;
+            if (tl != null && (tl.parent != t || tl.hash > t.hash))
+                return false;
+            if (tr != null && (tr.parent != t || tr.hash < t.hash))
+                return false;
+            if (t.red && tl != null && tl.red && tr != null && tr.red)
+                return false;
+            if (tl != null && !checkTreeNode(tl))
+                return false;
+            if (tr != null && !checkTreeNode(tr))
+                return false;
+            return true;
+        }
+    }
+
+    /* ---------------- Collision reduction methods -------------- */
+
+    /**
+     * Spreads higher bits to lower, and also forces top bit to 0.
+     * Because the table uses power-of-two masking, sets of hashes
+     * that vary only in bits above the current mask will always
+     * collide. (Among known examples are sets of Float keys holding
+     * consecutive whole numbers in small tables.)  To counter this,
+     * we apply a transform that spreads the impact of higher bits
+     * downward. There is a tradeoff between speed, utility, and
+     * quality of bit-spreading. Because many common sets of hashes
+     * are already reasonably distributed across bits (so don't benefit
+     * from spreading), and because we use trees to handle large sets
+     * of collisions in bins, we don't need excessively high quality.
+     */
+    private static final int spread(int h) {
+        h ^= (h >>> 18) ^ (h >>> 12);
+        return (h ^ (h >>> 10)) & HASH_BITS;
+    }
+
+    /**
+     * Replaces a list bin with a tree bin if key is comparable.  Call
+     * only when locked.
+     */
+    private final void replaceWithTreeBin(Node<K,V>[] tab, int index, Object key) {
+        if (tab != null && comparableClassFor(key.getClass()) != null) {
+            TreeBin<K,V> t = new TreeBin<K,V>();
+            for (Node<K,V> e = tabAt(tab, index); e != null; e = e.next)
+                t.putTreeNode(e.hash, e.key, e.val);
+            setTabAt(tab, index, new Node<K,V>(MOVED, t, null, null));
+        }
+    }
+
+    /* ---------------- Internal access and update methods -------------- */
+
+    /** Implementation for get and containsKey */
+    private final V internalGet(Object k) {
+        int h = spread(k.hashCode());
+        V v = null;
+        Node<K,V>[] tab; Node<K,V> e;
+        if ((tab = table) != null &&
+            (e = tabAt(tab, (tab.length - 1) & h)) != null) {
+            for (;;) {
+                int eh; Object ek;
+                if ((eh = e.hash) < 0) {
+                    if ((ek = e.key) instanceof TreeBin) { // search TreeBin
+                        v = ((TreeBin<K,V>)ek).getValue(h, k);
+                        break;
+                    }
+                    else if (!(ek instanceof Node[]) ||    // try new table
+                             (e = tabAt(tab = (Node<K,V>[])ek,
+                                        (tab.length - 1) & h)) == null)
+                        break;
+                }
+                else if (eh == h && ((ek = e.key) == k || k.equals(ek))) {
+                    v = e.val;
+                    break;
+                }
+                else if ((e = e.next) == null)
+                    break;
+            }
+        }
+        return v;
+    }
+
+    /**
+     * Implementation for the four public remove/replace methods:
+     * Replaces node value with v, conditional upon match of cv if
+     * non-null.  If resulting value is null, delete.
+     */
+    private final V internalReplace(Object k, V v, Object cv) {
+        int h = spread(k.hashCode());
+        V oldVal = null;
+        for (Node<K,V>[] tab = table;;) {
+            Node<K,V> f; int i, fh; Object fk;
+            if (tab == null ||
+                (f = tabAt(tab, i = (tab.length - 1) & h)) == null)
+                break;
+            else if ((fh = f.hash) < 0) {
+                if ((fk = f.key) instanceof TreeBin) {
+                    TreeBin<K,V> t = (TreeBin<K,V>)fk;
+                    long stamp = t.writeLock();
+                    boolean validated = false;
+                    boolean deleted = false;
+                    try {
+                        if (tabAt(tab, i) == f) {
+                            validated = true;
+                            Class<?> cc = comparableClassFor(k.getClass());
+                            TreeNode<K,V> p = t.getTreeNode(h, k, t.root, cc);
+                            if (p != null) {
+                                V pv = p.val;
+                                if (cv == null || cv == pv || cv.equals(pv)) {
+                                    oldVal = pv;
+                                    if (v != null)
+                                        p.val = v;
+                                    else {
+                                        deleted = true;
+                                        t.deleteTreeNode(p);
+                                    }
+                                }
+                            }
+                        }
+                    } finally {
+                        t.unlockWrite(stamp);
+                    }
+                    if (validated) {
+                        if (deleted)
+                            addCount(-1L, -1);
+                        break;
+                    }
+                }
+                else
+                    tab = (Node<K,V>[])fk;
+            }
+            else {
+                boolean validated = false;
+                boolean deleted = false;
+                synchronized (f) {
+                    if (tabAt(tab, i) == f) {
+                        validated = true;
+                        for (Node<K,V> e = f, pred = null;;) {
+                            Object ek;
+                            if (e.hash == h &&
+                                ((ek = e.key) == k || k.equals(ek))) {
+                                V ev = e.val;
+                                if (cv == null || cv == ev || cv.equals(ev)) {
+                                    oldVal = ev;
+                                    if (v != null)
+                                        e.val = v;
+                                    else {
+                                        deleted = true;
+                                        Node<K,V> en = e.next;
+                                        if (pred != null)
+                                            pred.next = en;
+                                        else
+                                            setTabAt(tab, i, en);
+                                    }
+                                }
+                                break;
+                            }
+                            pred = e;
+                            if ((e = e.next) == null)
+                                break;
+                        }
+                    }
+                }
+                if (validated) {
+                    if (deleted)
+                        addCount(-1L, -1);
+                    break;
+                }
+            }
+        }
+        return oldVal;
+    }
+
+    /*
+     * Internal versions of insertion methods
+     * All have the same basic structure as the first (internalPut):
+     *  1. If table uninitialized, create
+     *  2. If bin empty, try to CAS new node
+     *  3. If bin stale, use new table
+     *  4. if bin converted to TreeBin, validate and relay to TreeBin methods
+     *  5. Lock and validate; if valid, scan and add or update
+     *
+     * The putAll method differs mainly in attempting to pre-allocate
+     * enough table space, and also more lazily performs count updates
+     * and checks.
+     *
+     * Most of the function-accepting methods can't be factored nicely
+     * because they require different functional forms, so instead
+     * sprawl out similar mechanics.
+     */
+
+    /** Implementation for put and putIfAbsent */
+    private final V internalPut(K k, V v, boolean onlyIfAbsent) {
+        if (k == null || v == null) throw new NullPointerException();
+        int h = spread(k.hashCode());
+        int len = 0;
+        for (Node<K,V>[] tab = table;;) {
+            int i, fh; Node<K,V> f; Object fk;
+            if (tab == null)
+                tab = initTable();
+            else if ((f = tabAt(tab, i = (tab.length - 1) & h)) == null) {
+                if (casTabAt(tab, i, null, new Node<K,V>(h, k, v, null)))
+                    break;                   // no lock when adding to empty bin
+            }
+            else if ((fh = f.hash) < 0) {
+                if ((fk = f.key) instanceof TreeBin) {
+                    TreeBin<K,V> t = (TreeBin<K,V>)fk;
+                    long stamp = t.writeLock();
+                    V oldVal = null;
+                    try {
+                        if (tabAt(tab, i) == f) {
+                            len = 2;
+                            TreeNode<K,V> p = t.putTreeNode(h, k, v);
+                            if (p != null) {
+                                oldVal = p.val;
+                                if (!onlyIfAbsent)
+                                    p.val = v;
+                            }
+                        }
+                    } finally {
+                        t.unlockWrite(stamp);
+                    }
+                    if (len != 0) {
+                        if (oldVal != null)
+                            return oldVal;
+                        break;
+                    }
+                }
+                else
+                    tab = (Node<K,V>[])fk;
+            }
+            else {
+                V oldVal = null;
+                synchronized (f) {
+                    if (tabAt(tab, i) == f) {
+                        len = 1;
+                        for (Node<K,V> e = f;; ++len) {
+                            Object ek;
+                            if (e.hash == h &&
+                                ((ek = e.key) == k || k.equals(ek))) {
+                                oldVal = e.val;
+                                if (!onlyIfAbsent)
+                                    e.val = v;
+                                break;
+                            }
+                            Node<K,V> last = e;
+                            if ((e = e.next) == null) {
+                                last.next = new Node<K,V>(h, k, v, null);
+                                if (len > TREE_THRESHOLD)
+                                    replaceWithTreeBin(tab, i, k);
+                                break;
+                            }
+                        }
+                    }
+                }
+                if (len != 0) {
+                    if (oldVal != null)
+                        return oldVal;
+                    break;
+                }
+            }
+        }
+        addCount(1L, len);
+        return null;
+    }
+
+    /** Implementation for computeIfAbsent */
+    private final V internalComputeIfAbsent(K k, Function<? super K, ? extends V> mf) {
+        if (k == null || mf == null)
+            throw new NullPointerException();
+        int h = spread(k.hashCode());
+        V val = null;
+        int len = 0;
+        for (Node<K,V>[] tab = table;;) {
+            Node<K,V> f; int i; Object fk;
+            if (tab == null)
+                tab = initTable();
+            else if ((f = tabAt(tab, i = (tab.length - 1) & h)) == null) {
+                Node<K,V> node = new Node<K,V>(h, k, null, null);
+                synchronized (node) {
+                    if (casTabAt(tab, i, null, node)) {
+                        len = 1;
+                        try {
+                            if ((val = mf.apply(k)) != null)
+                                node.val = val;
+                        } finally {
+                            if (val == null)
+                                setTabAt(tab, i, null);
+                        }
+                    }
+                }
+                if (len != 0)
+                    break;
+            }
+            else if (f.hash < 0) {
+                if ((fk = f.key) instanceof TreeBin) {
+                    TreeBin<K,V> t = (TreeBin<K,V>)fk;
+                    long stamp = t.writeLock();
+                    boolean added = false;
+                    try {
+                        if (tabAt(tab, i) == f) {
+                            len = 2;
+                            Class<?> cc = comparableClassFor(k.getClass());
+                            TreeNode<K,V> p = t.getTreeNode(h, k, t.root, cc);
+                            if (p != null)
+                                val = p.val;
+                            else if ((val = mf.apply(k)) != null) {
+                                added = true;
+                                t.putTreeNode(h, k, val);
+                            }
+                        }
+                    } finally {
+                        t.unlockWrite(stamp);
+                    }
+                    if (len != 0) {
+                        if (!added)
+                            return val;
+                        break;
+                    }
+                }
+                else
+                    tab = (Node<K,V>[])fk;
+            }
+            else {
+                boolean added = false;
+                synchronized (f) {
+                    if (tabAt(tab, i) == f) {
+                        len = 1;
+                        for (Node<K,V> e = f;; ++len) {
+                            Object ek; V ev;
+                            if (e.hash == h &&
+                                ((ek = e.key) == k || k.equals(ek))) {
+                                val = e.val;
+                                break;
+                            }
+                            Node<K,V> last = e;
+                            if ((e = e.next) == null) {
+                                if ((val = mf.apply(k)) != null) {
+                                    added = true;
+                                    last.next = new Node<K,V>(h, k, val, null);
+                                    if (len > TREE_THRESHOLD)
+                                        replaceWithTreeBin(tab, i, k);
+                                }
+                                break;
+                            }
+                        }
+                    }
+                }
+                if (len != 0) {
+                    if (!added)
+                        return val;
+                    break;
+                }
+            }
         }
-
-        // Unsafe mechanics
-        static final sun.misc.Unsafe UNSAFE;
-        static final long nextOffset;
-        static {
-            try {
-                UNSAFE = sun.misc.Unsafe.getUnsafe();
-                Class<?> k = HashEntry.class;
-                nextOffset = UNSAFE.objectFieldOffset
-                    (k.getDeclaredField("next"));
-            } catch (Exception e) {
-                throw new Error(e);
+        if (val != null)
+            addCount(1L, len);
+        return val;
+    }
+
+    /** Implementation for compute */
+    private final V internalCompute(K k, boolean onlyIfPresent,
+                                    BiFunction<? super K, ? super V, ? extends V> mf) {
+        if (k == null || mf == null)
+            throw new NullPointerException();
+        int h = spread(k.hashCode());
+        V val = null;
+        int delta = 0;
+        int len = 0;
+        for (Node<K,V>[] tab = table;;) {
+            Node<K,V> f; int i, fh; Object fk;
+            if (tab == null)
+                tab = initTable();
+            else if ((f = tabAt(tab, i = (tab.length - 1) & h)) == null) {
+                if (onlyIfPresent)
+                    break;
+                Node<K,V> node = new Node<K,V>(h, k, null, null);
+                synchronized (node) {
+                    if (casTabAt(tab, i, null, node)) {
+                        try {
+                            len = 1;
+                            if ((val = mf.apply(k, null)) != null) {
+                                node.val = val;
+                                delta = 1;
+                            }
+                        } finally {
+                            if (delta == 0)
+                                setTabAt(tab, i, null);
+                        }
+                    }
+                }
+                if (len != 0)
+                    break;
+            }
+            else if ((fh = f.hash) < 0) {
+                if ((fk = f.key) instanceof TreeBin) {
+                    TreeBin<K,V> t = (TreeBin<K,V>)fk;
+                    long stamp = t.writeLock();
+                    try {
+                        if (tabAt(tab, i) == f) {
+                            len = 2;
+                            Class<?> cc = comparableClassFor(k.getClass());
+                            TreeNode<K,V> p = t.getTreeNode(h, k, t.root, cc);
+                            if (p != null || !onlyIfPresent) {
+                                V pv = (p == null) ? null : p.val;
+                                if ((val = mf.apply(k, pv)) != null) {
+                                    if (p != null)
+                                        p.val = val;
+                                    else {
+                                        delta = 1;
+                                        t.putTreeNode(h, k, val);
+                                    }
+                                }
+                                else if (p != null) {
+                                    delta = -1;
+                                    t.deleteTreeNode(p);
+                                }
+                            }
+                        }
+                    } finally {
+                        t.unlockWrite(stamp);
+                    }
+                    if (len != 0)
+                        break;
+                }
+                else
+                    tab = (Node<K,V>[])fk;
+            }
+            else {
+                synchronized (f) {
+                    if (tabAt(tab, i) == f) {
+                        len = 1;
+                        for (Node<K,V> e = f, pred = null;; ++len) {
+                            Object ek;
+                            if (e.hash == h &&
+                                ((ek = e.key) == k || k.equals(ek))) {
+                                val = mf.apply(k, e.val);
+                                if (val != null)
+                                    e.val = val;
+                                else {
+                                    delta = -1;
+                                    Node<K,V> en = e.next;
+                                    if (pred != null)
+                                        pred.next = en;
+                                    else
+                                        setTabAt(tab, i, en);
+                                }
+                                break;
+                            }
+                            pred = e;
+                            if ((e = e.next) == null) {
+                                if (!onlyIfPresent &&
+                                    (val = mf.apply(k, null)) != null) {
+                                    pred.next = new Node<K,V>(h, k, val, null);
+                                    delta = 1;
+                                    if (len > TREE_THRESHOLD)
+                                        replaceWithTreeBin(tab, i, k);
+                                }
+                                break;
+                            }
+                        }
+                    }
+                }
+                if (len != 0)
+                    break;
+            }
+        }
+        if (delta != 0)
+            addCount((long)delta, len);
+        return val;
+    }
+
+    /** Implementation for merge */
+    private final V internalMerge(K k, V v,
+                                  BiFunction<? super V, ? super V, ? extends V> mf) {
+        if (k == null || v == null || mf == null)
+            throw new NullPointerException();
+        int h = spread(k.hashCode());
+        V val = null;
+        int delta = 0;
+        int len = 0;
+        for (Node<K,V>[] tab = table;;) {
+            int i; Node<K,V> f; Object fk;
+            if (tab == null)
+                tab = initTable();
+            else if ((f = tabAt(tab, i = (tab.length - 1) & h)) == null) {
+                if (casTabAt(tab, i, null, new Node<K,V>(h, k, v, null))) {
+                    delta = 1;
+                    val = v;
+                    break;
+                }
+            }
+            else if (f.hash < 0) {
+                if ((fk = f.key) instanceof TreeBin) {
+                    TreeBin<K,V> t = (TreeBin<K,V>)fk;
+                    long stamp = t.writeLock();
+                    try {
+                        if (tabAt(tab, i) == f) {
+                            len = 2;
+                            Class<?> cc = comparableClassFor(k.getClass());
+                            TreeNode<K,V> p = t.getTreeNode(h, k, t.root, cc);
+                            val = (p == null) ? v : mf.apply(p.val, v);
+                            if (val != null) {
+                                if (p != null)
+                                    p.val = val;
+                                else {
+                                    delta = 1;
+                                    t.putTreeNode(h, k, val);
+                                }
+                            }
+                            else if (p != null) {
+                                delta = -1;
+                                t.deleteTreeNode(p);
+                            }
+                        }
+                    } finally {
+                        t.unlockWrite(stamp);
+                    }
+                    if (len != 0)
+                        break;
+                }
+                else
+                    tab = (Node<K,V>[])fk;
+            }
+            else {
+                synchronized (f) {
+                    if (tabAt(tab, i) == f) {
+                        len = 1;
+                        for (Node<K,V> e = f, pred = null;; ++len) {
+                            Object ek;
+                            if (e.hash == h &&
+                                ((ek = e.key) == k || k.equals(ek))) {
+                                val = mf.apply(e.val, v);
+                                if (val != null)
+                                    e.val = val;
+                                else {
+                                    delta = -1;
+                                    Node<K,V> en = e.next;
+                                    if (pred != null)
+                                        pred.next = en;
+                                    else
+                                        setTabAt(tab, i, en);
+                                }
+                                break;
+                            }
+                            pred = e;
+                            if ((e = e.next) == null) {
+                                delta = 1;
+                                val = v;
+                                pred.next = new Node<K,V>(h, k, val, null);
+                                if (len > TREE_THRESHOLD)
+                                    replaceWithTreeBin(tab, i, k);
+                                break;
+                            }
+                        }
+                    }
+                }
+                if (len != 0)
+                    break;
+            }
+        }
+        if (delta != 0)
+            addCount((long)delta, len);
+        return val;
+    }
+
+    /** Implementation for putAll */
+    private final void internalPutAll(Map<? extends K, ? extends V> m) {
+        tryPresize(m.size());
+        long delta = 0L;     // number of uncommitted additions
+        boolean npe = false; // to throw exception on exit for nulls
+        try {                // to clean up counts on other exceptions
+            for (Map.Entry<?, ? extends V> entry : m.entrySet()) {
+                Object k; V v;
+                if (entry == null || (k = entry.getKey()) == null ||
+                    (v = entry.getValue()) == null) {
+                    npe = true;
+                    break;
+                }
+                int h = spread(k.hashCode());
+                for (Node<K,V>[] tab = table;;) {
+                    int i; Node<K,V> f; int fh; Object fk;
+                    if (tab == null)
+                        tab = initTable();
+                    else if ((f = tabAt(tab, i = (tab.length - 1) & h)) == null){
+                        if (casTabAt(tab, i, null, new Node<K,V>(h, k, v, null))) {
+                            ++delta;
+                            break;
+                        }
+                    }
+                    else if ((fh = f.hash) < 0) {
+                        if ((fk = f.key) instanceof TreeBin) {
+                            TreeBin<K,V> t = (TreeBin<K,V>)fk;
+                            long stamp = t.writeLock();
+                            boolean validated = false;
+                            try {
+                                if (tabAt(tab, i) == f) {
+                                    validated = true;
+                                    Class<?> cc = comparableClassFor(k.getClass());
+                                    TreeNode<K,V> p = t.getTreeNode(h, k,
+                                                                    t.root, cc);
+                                    if (p != null)
+                                        p.val = v;
+                                    else {
+                                        ++delta;
+                                        t.putTreeNode(h, k, v);
+                                    }
+                                }
+                            } finally {
+                                t.unlockWrite(stamp);
+                            }
+                            if (validated)
+                                break;
+                        }
+                        else
+                            tab = (Node<K,V>[])fk;
+                    }
+                    else {
+                        int len = 0;
+                        synchronized (f) {
+                            if (tabAt(tab, i) == f) {
+                                len = 1;
+                                for (Node<K,V> e = f;; ++len) {
+                                    Object ek;
+                                    if (e.hash == h &&
+                                        ((ek = e.key) == k || k.equals(ek))) {
+                                        e.val = v;
+                                        break;
+                                    }
+                                    Node<K,V> last = e;
+                                    if ((e = e.next) == null) {
+                                        ++delta;
+                                        last.next = new Node<K,V>(h, k, v, null);
+                                        if (len > TREE_THRESHOLD)
+                                            replaceWithTreeBin(tab, i, k);
+                                        break;
+                                    }
+                                }
+                            }
+                        }
+                        if (len != 0) {
+                            if (len > 1) {
+                                addCount(delta, len);
+                                delta = 0L;
+                            }
+                            break;
+                        }
+                    }
+                }
+            }
+        } finally {
+            if (delta != 0L)
+                addCount(delta, 2);
+        }
+        if (npe)
+            throw new NullPointerException();
+    }
+
+    /**
+     * Implementation for clear. Steps through each bin, removing all
+     * nodes.
+     */
+    private final void internalClear() {
+        long delta = 0L; // negative number of deletions
+        int i = 0;
+        Node<K,V>[] tab = table;
+        while (tab != null && i < tab.length) {
+            Node<K,V> f = tabAt(tab, i);
+            if (f == null)
+                ++i;
+            else if (f.hash < 0) {
+                Object fk;
+                if ((fk = f.key) instanceof TreeBin) {
+                    TreeBin<K,V> t = (TreeBin<K,V>)fk;
+                    long stamp = t.writeLock();
+                    try {
+                        if (tabAt(tab, i) == f) {
+                            for (Node<K,V> p = t.first; p != null; p = p.next)
+                                --delta;
+                            t.first = null;
+                            t.root = null;
+                            ++i;
+                        }
+                    } finally {
+                        t.unlockWrite(stamp);
+                    }
+                }
+                else
+                    tab = (Node<K,V>[])fk;
+            }
+            else {
+                synchronized (f) {
+                    if (tabAt(tab, i) == f) {
+                        for (Node<K,V> e = f; e != null; e = e.next)
+                            --delta;
+                        setTabAt(tab, i, null);
+                        ++i;
+                    }
+                }
+            }
+        }
+        if (delta != 0L)
+            addCount(delta, -1);
+    }
+
+    /* ---------------- Table Initialization and Resizing -------------- */
+
+    /**
+     * Returns a power of two table size for the given desired capacity.
+     * See Hackers Delight, sec 3.2
+     */
+    private static final int tableSizeFor(int c) {
+        int n = c - 1;
+        n |= n >>> 1;
+        n |= n >>> 2;
+        n |= n >>> 4;
+        n |= n >>> 8;
+        n |= n >>> 16;
+        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
+    }
+
+    /**
+     * Initializes table, using the size recorded in sizeCtl.
+     */
+    private final Node<K,V>[] initTable() {
+        Node<K,V>[] tab; int sc;
+        while ((tab = table) == null) {
+            if ((sc = sizeCtl) < 0)
+                Thread.yield(); // lost initialization race; just spin
+            else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
+                try {
+                    if ((tab = table) == null) {
+                        int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
+                        table = tab = (Node<K,V>[])new Node[n];
+                        sc = n - (n >>> 2);
+                    }
+                } finally {
+                    sizeCtl = sc;
+                }
+                break;
+            }
+        }
+        return tab;
+    }
+
+    /**
+     * Adds to count, and if table is too small and not already
+     * resizing, initiates transfer. If already resizing, helps
+     * perform transfer if work is available.  Rechecks occupancy
+     * after a transfer to see if another resize is already needed
+     * because resizings are lagging additions.
+     *
+     * @param x the count to add
+     * @param check if <0, don't check resize, if <= 1 only check if uncontended
+     */
+    private final void addCount(long x, int check) {
+        Cell[] as; long b, s;
+        if ((as = counterCells) != null ||
+            !U.compareAndSwapLong(this, BASECOUNT, b = baseCount, s = b + x)) {
+            Cell a; long v; int m;
+            boolean uncontended = true;
+            if (as == null || (m = as.length - 1) < 0 ||
+                (a = as[ThreadLocalRandom.getProbe() & m]) == null ||
+                !(uncontended =
+                  U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))) {
+                fullAddCount(x, uncontended);
+                return;
+            }
+            if (check <= 1)
+                return;
+            s = sumCount();
+        }
+        if (check >= 0) {
+            Node<K,V>[] tab, nt; int sc;
+            while (s >= (long)(sc = sizeCtl) && (tab = table) != null &&
+                   tab.length < MAXIMUM_CAPACITY) {
+                if (sc < 0) {
+                    if (sc == -1 || transferIndex <= transferOrigin ||
+                        (nt = nextTable) == null)
+                        break;
+                    if (U.compareAndSwapInt(this, SIZECTL, sc, sc - 1))
+                        transfer(tab, nt);
+                }
+                else if (U.compareAndSwapInt(this, SIZECTL, sc, -2))
+                    transfer(tab, null);
+                s = sumCount();
             }
         }
     }
 
     /**
-     * Gets the ith element of given table (if nonnull) with volatile
-     * read semantics. Note: This is manually integrated into a few
-     * performance-sensitive methods to reduce call overhead.
-     */
-    @SuppressWarnings("unchecked")
-    static final <K,V> HashEntry<K,V> entryAt(HashEntry<K,V>[] tab, int i) {
-        return (tab == null) ? null :
-            (HashEntry<K,V>) UNSAFE.getObjectVolatile
-            (tab, ((long)i << TSHIFT) + TBASE);
-    }
-
-    /**
-     * Sets the ith element of given table, with volatile write
-     * semantics. (See above about use of putOrderedObject.)
+     * Tries to presize table to accommodate the given number of elements.
+     *
+     * @param size number of elements (doesn't need to be perfectly accurate)
      */
-    static final <K,V> void setEntryAt(HashEntry<K,V>[] tab, int i,
-                                       HashEntry<K,V> e) {
-        UNSAFE.putOrderedObject(tab, ((long)i << TSHIFT) + TBASE, e);
-    }
-
-    /**
-     * Applies a supplemental hash function to a given hashCode, which
-     * defends against poor quality hash functions.  This is critical
-     * because ConcurrentHashMap uses power-of-two length hash tables,
-     * that otherwise encounter collisions for hashCodes that do not
-     * differ in lower or upper bits.
-     */
-    private int hash(Object k) {
-        if (k instanceof String) {
-            return ((String) k).hash32();
+    private final void tryPresize(int size) {
+        int c = (size >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY :
+            tableSizeFor(size + (size >>> 1) + 1);
+        int sc;
+        while ((sc = sizeCtl) >= 0) {
+            Node<K,V>[] tab = table; int n;
+            if (tab == null || (n = tab.length) == 0) {
+                n = (sc > c) ? sc : c;
+                if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
+                    try {
+                        if (table == tab) {
+                            table = (Node<K,V>[])new Node[n];
+                            sc = n - (n >>> 2);
+                        }
+                    } finally {
+                        sizeCtl = sc;
+                    }
+                }
+            }
+            else if (c <= sc || n >= MAXIMUM_CAPACITY)
+                break;
+            else if (tab == table &&
+                     U.compareAndSwapInt(this, SIZECTL, sc, -2))
+                transfer(tab, null);
         }
-
-        int h = hashSeed ^ k.hashCode();
-
-        // Spread bits to regularize both segment and index locations,
-        // using variant of single-word Wang/Jenkins hash.
-        h += (h <<  15) ^ 0xffffcd7d;
-        h ^= (h >>> 10);
-        h += (h <<   3);
-        h ^= (h >>>  6);
-        h += (h <<   2) + (h << 14);
-        return h ^ (h >>> 16);
     }
 
     /**
-     * Segments are specialized versions of hash tables.  This
-     * subclasses from ReentrantLock opportunistically, just to
-     * simplify some locking and avoid separate construction.
+     * Moves and/or copies the nodes in each bin to new table. See
+     * above for explanation.
      */
-    static final class Segment<K,V> extends ReentrantLock implements Serializable {
-        /*
-         * Segments maintain a table of entry lists that are always
-         * kept in a consistent state, so can be read (via volatile
-         * reads of segments and tables) without locking.  This
-         * requires replicating nodes when necessary during table
-         * resizing, so the old lists can be traversed by readers
-         * still using old version of table.
-         *
-         * This class defines only mutative methods requiring locking.
-         * Except as noted, the methods of this class perform the
-         * per-segment versions of ConcurrentHashMap methods.  (Other
-         * methods are integrated directly into ConcurrentHashMap
-         * methods.) These mutative methods use a form of controlled
-         * spinning on contention via methods scanAndLock and
-         * scanAndLockForPut. These intersperse tryLocks with
-         * traversals to locate nodes.  The main benefit is to absorb
-         * cache misses (which are very common for hash tables) while
-         * obtaining locks so that traversal is faster once
-         * acquired. We do not actually use the found nodes since they
-         * must be re-acquired under lock anyway to ensure sequential
-         * consistency of updates (and in any case may be undetectably
-         * stale), but they will normally be much faster to re-locate.
-         * Also, scanAndLockForPut speculatively creates a fresh node
-         * to use in put if no node is found.
-         */
-
-        private static final long serialVersionUID = 2249069246763182397L;
-
-        /**
-         * The maximum number of times to tryLock in a prescan before
-         * possibly blocking on acquire in preparation for a locked
-         * segment operation. On multiprocessors, using a bounded
-         * number of retries maintains cache acquired while locating
-         * nodes.
-         */
-        static final int MAX_SCAN_RETRIES =
-            Runtime.getRuntime().availableProcessors() > 1 ? 64 : 1;
-
-        /**
-         * The per-segment table. Elements are accessed via
-         * entryAt/setEntryAt providing volatile semantics.
-         */
-        transient volatile HashEntry<K,V>[] table;
-
-        /**
-         * The number of elements. Accessed only either within locks
-         * or among other volatile reads that maintain visibility.
-         */
-        transient int count;
-
-        /**
-         * The total number of mutative operations in this segment.
-         * Even though this may overflows 32 bits, it provides
-         * sufficient accuracy for stability checks in CHM isEmpty()
-         * and size() methods.  Accessed only either within locks or
-         * among other volatile reads that maintain visibility.
-         */
-        transient int modCount;
-
-        /**
-         * The table is rehashed when its size exceeds this threshold.
-         * (The value of this field is always <tt>(int)(capacity *
-         * loadFactor)</tt>.)
-         */
-        transient int threshold;
-
-        /**
-         * The load factor for the hash table.  Even though this value
-         * is same for all segments, it is replicated to avoid needing
-         * links to outer object.
-         * @serial
-         */
-        final float loadFactor;
-
-        Segment(float lf, int threshold, HashEntry<K,V>[] tab) {
-            this.loadFactor = lf;
-            this.threshold = threshold;
-            this.table = tab;
+    private final void transfer(Node<K,V>[] tab, Node<K,V>[] nextTab) {
+        int n = tab.length, stride;
+        if ((stride = (NCPU > 1) ? (n >>> 3) / NCPU : n) < MIN_TRANSFER_STRIDE)
+            stride = MIN_TRANSFER_STRIDE; // subdivide range
+        if (nextTab == null) {            // initiating
+            try {
+                nextTab = (Node<K,V>[])new Node[n << 1];
+            } catch (Throwable ex) {      // try to cope with OOME
+                sizeCtl = Integer.MAX_VALUE;
+                return;
+            }
+            nextTable = nextTab;
+            transferOrigin = n;
+            transferIndex = n;
+            Node<K,V> rev = new Node<K,V>(MOVED, tab, null, null);
+            for (int k = n; k > 0;) {    // progressively reveal ready slots
+                int nextk = (k > stride) ? k - stride : 0;
+                for (int m = nextk; m < k; ++m)
+                    nextTab[m] = rev;
+                for (int m = n + nextk; m < n + k; ++m)
+                    nextTab[m] = rev;
+                U.putOrderedInt(this, TRANSFERORIGIN, k = nextk);
+            }
         }
-
-        final V put(K key, int hash, V value, boolean onlyIfAbsent) {
-            HashEntry<K,V> node = tryLock() ? null :
-                scanAndLockForPut(key, hash, value);
-            V oldValue;
-            try {
-                HashEntry<K,V>[] tab = table;
-                int index = (tab.length - 1) & hash;
-                HashEntry<K,V> first = entryAt(tab, index);
-                for (HashEntry<K,V> e = first;;) {
-                    if (e != null) {
-                        K k;
-                        if ((k = e.key) == key ||
-                            (e.hash == hash && key.equals(k))) {
-                            oldValue = e.value;
-                            if (!onlyIfAbsent) {
-                                e.value = value;
-                                ++modCount;
-                            }
-                            break;
+        int nextn = nextTab.length;
+        Node<K,V> fwd = new Node<K,V>(MOVED, nextTab, null, null);
+        boolean advance = true;
+        for (int i = 0, bound = 0;;) {
+            int nextIndex, nextBound; Node<K,V> f; Object fk;
+            while (advance) {
+                if (--i >= bound)
+                    advance = false;
+                else if ((nextIndex = transferIndex) <= transferOrigin) {
+                    i = -1;
+                    advance = false;
+                }
+                else if (U.compareAndSwapInt
+                         (this, TRANSFERINDEX, nextIndex,
+                          nextBound = (nextIndex > stride ?
+                                       nextIndex - stride : 0))) {
+                    bound = nextBound;
+                    i = nextIndex - 1;
+                    advance = false;
+                }
+            }
+            if (i < 0 || i >= n || i + n >= nextn) {
+                for (int sc;;) {
+                    if (U.compareAndSwapInt(this, SIZECTL, sc = sizeCtl, ++sc)) {
+                        if (sc == -1) {
+                            nextTable = null;
+                            table = nextTab;
+                            sizeCtl = (n << 1) - (n >>> 1);
                         }
-                        e = e.next;
-                    }
-                    else {
-                        if (node != null)
-                            node.setNext(first);
-                        else
-                            node = new HashEntry<K,V>(hash, key, value, first);
-                        int c = count + 1;
-                        if (c > threshold && tab.length < MAXIMUM_CAPACITY)
-                            rehash(node);
-                        else
-                            setEntryAt(tab, index, node);
-                        ++modCount;
-                        count = c;
-                        oldValue = null;
-                        break;
+                        return;
                     }
                 }
-            } finally {
-                unlock();
+            }
+            else if ((f = tabAt(tab, i)) == null) {
+                if (casTabAt(tab, i, null, fwd)) {
+                    setTabAt(nextTab, i, null);
+                    setTabAt(nextTab, i + n, null);
+                    advance = true;
+                }
             }
-            return oldValue;
-        }
-
-        /**
-         * Doubles size of table and repacks entries, also adding the
-         * given node to new table
-         */
-        @SuppressWarnings("unchecked")
-        private void rehash(HashEntry<K,V> node) {
-            /*
-             * Reclassify nodes in each list to new table.  Because we
-             * are using power-of-two expansion, the elements from
-             * each bin must either stay at same index, or move with a
-             * power of two offset. We eliminate unnecessary node
-             * creation by catching cases where old nodes can be
-             * reused because their next fields won't change.
-             * Statistically, at the default threshold, only about
-             * one-sixth of them need cloning when a table
-             * doubles. The nodes they replace will be garbage
-             * collectable as soon as they are no longer referenced by
-             * any reader thread that may be in the midst of
-             * concurrently traversing table. Entry accesses use plain
-             * array indexing because they are followed by volatile
-             * table write.
-             */
-            HashEntry<K,V>[] oldTable = table;
-            int oldCapacity = oldTable.length;
-            int newCapacity = oldCapacity << 1;
-            threshold = (int)(newCapacity * loadFactor);
-            HashEntry<K,V>[] newTable =
-                (HashEntry<K,V>[]) new HashEntry<?,?>[newCapacity];
-            int sizeMask = newCapacity - 1;
-            for (int i = 0; i < oldCapacity ; i++) {
-                HashEntry<K,V> e = oldTable[i];
-                if (e != null) {
-                    HashEntry<K,V> next = e.next;
-                    int idx = e.hash & sizeMask;
-                    if (next == null)   //  Single node on list
-                        newTable[idx] = e;
-                    else { // Reuse consecutive sequence at same slot
-                        HashEntry<K,V> lastRun = e;
-                        int lastIdx = idx;
-                        for (HashEntry<K,V> last = next;
-                             last != null;
-                             last = last.next) {
-                            int k = last.hash & sizeMask;
-                            if (k != lastIdx) {
-                                lastIdx = k;
-                                lastRun = last;
+            else if (f.hash >= 0) {
+                synchronized (f) {
+                    if (tabAt(tab, i) == f) {
+                        int runBit = f.hash & n;
+                        Node<K,V> lastRun = f, lo = null, hi = null;
+                        for (Node<K,V> p = f.next; p != null; p = p.next) {
+                            int b = p.hash & n;
+                            if (b != runBit) {
+                                runBit = b;
+                                lastRun = p;
                             }
                         }
-                        newTable[lastIdx] = lastRun;
-                        // Clone remaining nodes
-                        for (HashEntry<K,V> p = e; p != lastRun; p = p.next) {
-                            V v = p.value;
-                            int h = p.hash;
-                            int k = h & sizeMask;
-                            HashEntry<K,V> n = newTable[k];
-                            newTable[k] = new HashEntry<K,V>(h, p.key, v, n);
+                        if (runBit == 0)
+                            lo = lastRun;
+                        else
+                            hi = lastRun;
+                        for (Node<K,V> p = f; p != lastRun; p = p.next) {
+                            int ph = p.hash; Object pk = p.key; V pv = p.val;
+                            if ((ph & n) == 0)
+                                lo = new Node<K,V>(ph, pk, pv, lo);
+                            else
+                                hi = new Node<K,V>(ph, pk, pv, hi);
                         }
+                        setTabAt(nextTab, i, lo);
+                        setTabAt(nextTab, i + n, hi);
+                        setTabAt(tab, i, fwd);
+                        advance = true;
                     }
                 }
             }
-            int nodeIndex = node.hash & sizeMask; // add the new node
-            node.setNext(newTable[nodeIndex]);
-            newTable[nodeIndex] = node;
-            table = newTable;
-        }
-
-        /**
-         * Scans for a node containing given key while trying to
-         * acquire lock, creating and returning one if not found. Upon
-         * return, guarantees that lock is held. UNlike in most
-         * methods, calls to method equals are not screened: Since
-         * traversal speed doesn't matter, we might as well help warm
-         * up the associated code and accesses as well.
-         *
-         * @return a new node if key not found, else null
-         */
-        private HashEntry<K,V> scanAndLockForPut(K key, int hash, V value) {
-            HashEntry<K,V> first = entryForHash(this, hash);
-            HashEntry<K,V> e = first;
-            HashEntry<K,V> node = null;
-            int retries = -1; // negative while locating node
-            while (!tryLock()) {
-                HashEntry<K,V> f; // to recheck first below
-                if (retries < 0) {
-                    if (e == null) {
-                        if (node == null) // speculatively create node
-                            node = new HashEntry<K,V>(hash, key, value, null);
-                        retries = 0;
+            else if ((fk = f.key) instanceof TreeBin) {
+                TreeBin<K,V> t = (TreeBin<K,V>)fk;
+                long stamp = t.writeLock();
+                try {
+                    if (tabAt(tab, i) == f) {
+                        TreeNode<K,V> root;
+                        Node<K,V> ln = null, hn = null;
+                        if ((root = t.root) != null) {
+                            Node<K,V> e, p; TreeNode<K,V> lr, rr; int lh;
+                            TreeBin<K,V> lt = null, ht = null;
+                            for (lr = root; lr.left != null; lr = lr.left);
+                            for (rr = root; rr.right != null; rr = rr.right);
+                            if ((lh = lr.hash) == rr.hash) { // move entire tree
+                                if ((lh & n) == 0)
+                                    lt = t;
+                                else
+                                    ht = t;
+                            }
+                            else {
+                                lt = new TreeBin<K,V>();
+                                ht = new TreeBin<K,V>();
+                                int lc = 0, hc = 0;
+                                for (e = t.first; e != null; e = e.next) {
+                                    int h = e.hash;
+                                    Object k = e.key; V v = e.val;
+                                    if ((h & n) == 0) {
+                                        ++lc;
+                                        lt.putTreeNode(h, k, v);
+                                    }
+                                    else {
+                                        ++hc;
+                                        ht.putTreeNode(h, k, v);
+                                    }
+                                }
+                                if (lc < TREE_THRESHOLD) { // throw away
+                                    for (p = lt.first; p != null; p = p.next)
+                                        ln = new Node<K,V>(p.hash, p.key,
+                                                           p.val, ln);
+                                    lt = null;
+                                }
+                                if (hc < TREE_THRESHOLD) {
+                                    for (p = ht.first; p != null; p = p.next)
+                                        hn = new Node<K,V>(p.hash, p.key,
+                                                           p.val, hn);
+                                    ht = null;
+                                }
+                            }
+                            if (ln == null && lt != null)
+                                ln = new Node<K,V>(MOVED, lt, null, null);
+                            if (hn == null && ht != null)
+                                hn = new Node<K,V>(MOVED, ht, null, null);
+                        }
+                        setTabAt(nextTab, i, ln);
+                        setTabAt(nextTab, i + n, hn);
+                        setTabAt(tab, i, fwd);
+                        advance = true;
                     }
-                    else if (key.equals(e.key))
-                        retries = 0;
-                    else
-                        e = e.next;
-                }
-                else if (++retries > MAX_SCAN_RETRIES) {
-                    lock();
-                    break;
-                }
-                else if ((retries & 1) == 0 &&
-                         (f = entryForHash(this, hash)) != first) {
-                    e = first = f; // re-traverse if entry changed
-                    retries = -1;
+                } finally {
+                    t.unlockWrite(stamp);
                 }
             }
-            return node;
+            else
+                advance = true; // already processed
+        }
+    }
+
+    /* ---------------- Counter support -------------- */
+
+    final long sumCount() {
+        Cell[] as = counterCells; Cell a;
+        long sum = baseCount;
+        if (as != null) {
+            for (int i = 0; i < as.length; ++i) {
+                if ((a = as[i]) != null)
+                    sum += a.value;
+            }
+        }
+        return sum;
+    }
+
+    // See LongAdder version for explanation
+    private final void fullAddCount(long x, boolean wasUncontended) {
+        int h;
+        if ((h = ThreadLocalRandom.getProbe()) == 0) {
+            ThreadLocalRandom.localInit();      // force initialization
+            h = ThreadLocalRandom.getProbe();
+            wasUncontended = true;
         }
-
-        /**
-         * Scans for a node containing the given key while trying to
-         * acquire lock for a remove or replace operation. Upon
-         * return, guarantees that lock is held.  Note that we must
-         * lock even if the key is not found, to ensure sequential
-         * consistency of updates.
-         */
-        private void scanAndLock(Object key, int hash) {
-            // similar to but simpler than scanAndLockForPut
-            HashEntry<K,V> first = entryForHash(this, hash);
-            HashEntry<K,V> e = first;
-            int retries = -1;
-            while (!tryLock()) {
-                HashEntry<K,V> f;
-                if (retries < 0) {
-                    if (e == null || key.equals(e.key))
-                        retries = 0;
-                    else
-                        e = e.next;
+        boolean collide = false;                // True if last slot nonempty
+        for (;;) {
+            Cell[] as; Cell a; int n; long v;
+            if ((as = counterCells) != null && (n = as.length) > 0) {
+                if ((a = as[(n - 1) & h]) == null) {
+                    if (cellsBusy == 0) {            // Try to attach new Cell
+                        Cell r = new Cell(x); // Optimistic create
+                        if (cellsBusy == 0 &&
+                            U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
+                            boolean created = false;
+                            try {               // Recheck under lock
+                                Cell[] rs; int m, j;
+                                if ((rs = counterCells) != null &&
+                                    (m = rs.length) > 0 &&
+                                    rs[j = (m - 1) & h] == null) {
+                                    rs[j] = r;
+                                    created = true;
+                                }
+                            } finally {
+                                cellsBusy = 0;
+                            }
+                            if (created)
+                                break;
+                            continue;           // Slot is now non-empty
+                        }
+                    }
+                    collide = false;
+                }
+                else if (!wasUncontended)       // CAS already known to fail
+                    wasUncontended = true;      // Continue after rehash
+                else if (U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))
+                    break;
+                else if (counterCells != as || n >= NCPU)
+                    collide = false;            // At max size or stale
+                else if (!collide)
+                    collide = true;
+                else if (cellsBusy == 0 &&
+                         U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
+                    try {
+                        if (counterCells == as) {// Expand table unless stale
+                            Cell[] rs = new Cell[n << 1];
+                            for (int i = 0; i < n; ++i)
+                                rs[i] = as[i];
+                            counterCells = rs;
+                        }
+                    } finally {
+                        cellsBusy = 0;
+                    }
+                    collide = false;
+                    continue;                   // Retry with expanded table
                 }
-                else if (++retries > MAX_SCAN_RETRIES) {
-                    lock();
-                    break;
+                h = ThreadLocalRandom.advanceProbe(h);
+            }
+            else if (cellsBusy == 0 && counterCells == as &&
+                     U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
+                boolean init = false;
+                try {                           // Initialize table
+                    if (counterCells == as) {
+                        Cell[] rs = new Cell[2];
+                        rs[h & 1] = new Cell(x);
+                        counterCells = rs;
+                        init = true;
+                    }
+                } finally {
+                    cellsBusy = 0;
                 }
-                else if ((retries & 1) == 0 &&
-                         (f = entryForHash(this, hash)) != first) {
-                    e = first = f;
-                    retries = -1;
-                }
+                if (init)
+                    break;
             }
+            else if (U.compareAndSwapLong(this, BASECOUNT, v = baseCount, v + x))
+                break;                          // Fall back on using base
+        }
+    }
+
+    /* ----------------Table Traversal -------------- */
+
+    /**
+     * Encapsulates traversal for methods such as containsValue; also
+     * serves as a base class for other iterators and spliterators.
+     *
+     * Method advance visits once each still-valid node that was
+     * reachable upon iterator construction. It might miss some that
+     * were added to a bin after the bin was visited, which is OK wrt
+     * consistency guarantees. Maintaining this property in the face
+     * of possible ongoing resizes requires a fair amount of
+     * bookkeeping state that is difficult to optimize away amidst
+     * volatile accesses.  Even so, traversal maintains reasonable
+     * throughput.
+     *
+     * Normally, iteration proceeds bin-by-bin traversing lists.
+     * However, if the table has been resized, then all future steps
+     * must traverse both the bin at the current index as well as at
+     * (index + baseSize); and so on for further resizings. To
+     * paranoically cope with potential sharing by users of iterators
+     * across threads, iteration terminates if a bounds checks fails
+     * for a table read.
+     */
+    static class Traverser<K,V> {
+        Node<K,V>[] tab;        // current table; updated if resized
+        Node<K,V> next;         // the next entry to use
+        int index;              // index of bin to use next
+        int baseIndex;          // current index of initial table
+        int baseLimit;          // index bound for initial table
+        final int baseSize;     // initial table size
+
+        Traverser(Node<K,V>[] tab, int size, int index, int limit) {
+            this.tab = tab;
+            this.baseSize = size;
+            this.baseIndex = this.index = index;
+            this.baseLimit = limit;
+            this.next = null;
         }
 
         /**
-         * Remove; match on key only if value null, else match both.
+         * Advances if possible, returning next valid node, or null if none.
          */
-        final V remove(Object key, int hash, Object value) {
-            if (!tryLock())
-                scanAndLock(key, hash);
-            V oldValue = null;
-            try {
-                HashEntry<K,V>[] tab = table;
-                int index = (tab.length - 1) & hash;
-                HashEntry<K,V> e = entryAt(tab, index);
-                HashEntry<K,V> pred = null;
-                while (e != null) {
-                    K k;
-                    HashEntry<K,V> next = e.next;
-                    if ((k = e.key) == key ||
-                        (e.hash == hash && key.equals(k))) {
-                        V v = e.value;
-                        if (value == null || value == v || value.equals(v)) {
-                            if (pred == null)
-                                setEntryAt(tab, index, next);
-                            else
-                                pred.setNext(next);
-                            ++modCount;
-                            --count;
-                            oldValue = v;
-                        }
-                        break;
-                    }
-                    pred = e;
-                    e = next;
-                }
-            } finally {
-                unlock();
-            }
-            return oldValue;
-        }
-
-        final boolean replace(K key, int hash, V oldValue, V newValue) {
-            if (!tryLock())
-                scanAndLock(key, hash);
-            boolean replaced = false;
-            try {
-                HashEntry<K,V> e;
-                for (e = entryForHash(this, hash); e != null; e = e.next) {
-                    K k;
-                    if ((k = e.key) == key ||
-                        (e.hash == hash && key.equals(k))) {
-                        if (oldValue.equals(e.value)) {
-                            e.value = newValue;
-                            ++modCount;
-                            replaced = true;
-                        }
-                        break;
+        final Node<K,V> advance() {
+            Node<K,V> e;
+            if ((e = next) != null)
+                e = e.next;
+            for (;;) {
+                Node<K,V>[] t; int i, n; Object ek;  // must use locals in checks
+                if (e != null)
+                    return next = e;
+                if (baseIndex >= baseLimit || (t = tab) == null ||
+                    (n = t.length) <= (i = index) || i < 0)
+                    return next = null;
+                if ((e = tabAt(t, index)) != null && e.hash < 0) {
+                    if ((ek = e.key) instanceof TreeBin)
+                        e = ((TreeBin<K,V>)ek).first;
+                    else {
+                        tab = (Node<K,V>[])ek;
+                        e = null;
+                        continue;
                     }
                 }
-            } finally {
-                unlock();
-            }
-            return replaced;
-        }
-
-        final V replace(K key, int hash, V value) {
-            if (!tryLock())
-                scanAndLock(key, hash);
-            V oldValue = null;
-            try {
-                HashEntry<K,V> e;
-                for (e = entryForHash(this, hash); e != null; e = e.next) {
-                    K k;
-                    if ((k = e.key) == key ||
-                        (e.hash == hash && key.equals(k))) {
-                        oldValue = e.value;
-                        e.value = value;
-                        ++modCount;
-                        break;
-                    }
-                }
-            } finally {
-                unlock();
-            }
-            return oldValue;
-        }
-
-        final void clear() {
-            lock();
-            try {
-                HashEntry<K,V>[] tab = table;
-                for (int i = 0; i < tab.length ; i++)
-                    setEntryAt(tab, i, null);
-                ++modCount;
-                count = 0;
-            } finally {
-                unlock();
+                if ((index += baseSize) >= n)
+                    index = ++baseIndex;    // visit upper slots if present
             }
         }
     }
 
-    // Accessing segments
-
     /**
-     * Gets the jth element of given segment array (if nonnull) with
-     * volatile element access semantics via Unsafe. (The null check
-     * can trigger harmlessly only during deserialization.) Note:
-     * because each element of segments array is set only once (using
-     * fully ordered writes), some performance-sensitive methods rely
-     * on this method only as a recheck upon null reads.
-     */
-    @SuppressWarnings("unchecked")
-    static final <K,V> Segment<K,V> segmentAt(Segment<K,V>[] ss, int j) {
-        long u = (j << SSHIFT) + SBASE;
-        return ss == null ? null :
-            (Segment<K,V>) UNSAFE.getObjectVolatile(ss, u);
-    }
-
-    /**
-     * Returns the segment for the given index, creating it and
-     * recording in segment table (via CAS) if not already present.
-     *
-     * @param k the index
-     * @return the segment
+     * Base of key, value, and entry Iterators. Adds fields to
+     * Traverser to support iterator.remove
      */
-    @SuppressWarnings("unchecked")
-    private Segment<K,V> ensureSegment(int k) {
-        final Segment<K,V>[] ss = this.segments;
-        long u = (k << SSHIFT) + SBASE; // raw offset
-        Segment<K,V> seg;
-        if ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u)) == null) {
-            Segment<K,V> proto = ss[0]; // use segment 0 as prototype
-            int cap = proto.table.length;
-            float lf = proto.loadFactor;
-            int threshold = (int)(cap * lf);
-            HashEntry<K,V>[] tab = (HashEntry<K,V>[])new HashEntry<?,?>[cap];
-            if ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u))
-                == null) { // recheck
-                Segment<K,V> s = new Segment<K,V>(lf, threshold, tab);
-                while ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u))
-                       == null) {
-                    if (UNSAFE.compareAndSwapObject(ss, u, null, seg = s))
-                        break;
-                }
-            }
+    static class BaseIterator<K,V> extends Traverser<K,V> {
+        final ConcurrentHashMap<K,V> map;
+        Node<K,V> lastReturned;
+        BaseIterator(Node<K,V>[] tab, int size, int index, int limit,
+                    ConcurrentHashMap<K,V> map) {
+            super(tab, size, index, limit);
+            this.map = map;
+            advance();
+        }
+
+        public final boolean hasNext() { return next != null; }
+        public final boolean hasMoreElements() { return next != null; }
+
+        public final void remove() {
+            Node<K,V> p;
+            if ((p = lastReturned) == null)
+                throw new IllegalStateException();
+            lastReturned = null;
+            map.internalReplace((K)p.key, null, null);
+        }
+    }
+
+    static final class KeyIterator<K,V> extends BaseIterator<K,V>
+        implements Iterator<K>, Enumeration<K> {
+        KeyIterator(Node<K,V>[] tab, int index, int size, int limit,
+                    ConcurrentHashMap<K,V> map) {
+            super(tab, index, size, limit, map);
+        }
+
+        public final K next() {
+            Node<K,V> p;
+            if ((p = next) == null)
+                throw new NoSuchElementException();
+            K k = (K)p.key;
+            lastReturned = p;
+            advance();
+            return k;
         }
-        return seg;
+
+        public final K nextElement() { return next(); }
+    }
+
+    static final class ValueIterator<K,V> extends BaseIterator<K,V>
+        implements Iterator<V>, Enumeration<V> {
+        ValueIterator(Node<K,V>[] tab, int index, int size, int limit,
+                      ConcurrentHashMap<K,V> map) {
+            super(tab, index, size, limit, map);
+        }
+
+        public final V next() {
+            Node<K,V> p;
+            if ((p = next) == null)
+                throw new NoSuchElementException();
+            V v = p.val;
+            lastReturned = p;
+            advance();
+            return v;
+        }
+
+        public final V nextElement() { return next(); }
+    }
+
+    static final class EntryIterator<K,V> extends BaseIterator<K,V>
+        implements Iterator<Map.Entry<K,V>> {
+        EntryIterator(Node<K,V>[] tab, int index, int size, int limit,
+                      ConcurrentHashMap<K,V> map) {
+            super(tab, index, size, limit, map);
+        }
+
+        public final Map.Entry<K,V> next() {
+            Node<K,V> p;
+            if ((p = next) == null)
+                throw new NoSuchElementException();
+            K k = (K)p.key;
+            V v = p.val;
+            lastReturned = p;
+            advance();
+            return new MapEntry<K,V>(k, v, map);
+        }
     }
 
-    // Hash-based segment and entry accesses
-
-    /**
-     * Gets the segment for the given hash code.
-     */
-    @SuppressWarnings("unchecked")
-    private Segment<K,V> segmentForHash(int h) {
-        long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
-        return (Segment<K,V>) UNSAFE.getObjectVolatile(segments, u);
+    static final class KeySpliterator<K,V> extends Traverser<K,V>
+        implements Spliterator<K> {
+        long est;               // size estimate
+        KeySpliterator(Node<K,V>[] tab, int size, int index, int limit,
+                       long est) {
+            super(tab, size, index, limit);
+            this.est = est;
+        }
+
+        public Spliterator<K> trySplit() {
+            int i, f, h;
+            return (h = ((i = baseIndex) + (f = baseLimit)) >>> 1) <= i ? null :
+                new KeySpliterator<K,V>(tab, baseSize, baseLimit = h,
+                                        f, est >>>= 1);
+        }
+
+        public void forEachRemaining(Consumer<? super K> action) {
+            if (action == null) throw new NullPointerException();
+            for (Node<K,V> p; (p = advance()) != null;)
+                action.accept((K)p.key);
+        }
+
+        public boolean tryAdvance(Consumer<? super K> action) {
+            if (action == null) throw new NullPointerException();
+            Node<K,V> p;
+            if ((p = advance()) == null)
+                return false;
+            action.accept((K)p.key);
+            return true;
+        }
+
+        public long estimateSize() { return est; }
+
+        public int characteristics() {
+            return Spliterator.DISTINCT | Spliterator.CONCURRENT |
+                Spliterator.NONNULL;
+        }
     }
 
-    /**
-     * Gets the table entry for the given segment and hash code.
-     */
-    @SuppressWarnings("unchecked")
-    static final <K,V> HashEntry<K,V> entryForHash(Segment<K,V> seg, int h) {
-        HashEntry<K,V>[] tab;
-        return (seg == null || (tab = seg.table) == null) ? null :
-            (HashEntry<K,V>) UNSAFE.getObjectVolatile
-            (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);
+    static final class ValueSpliterator<K,V> extends Traverser<K,V>
+        implements Spliterator<V> {
+        long est;               // size estimate
+        ValueSpliterator(Node<K,V>[] tab, int size, int index, int limit,
+                         long est) {
+            super(tab, size, index, limit);
+            this.est = est;
+        }
+
+        public Spliterator<V> trySplit() {
+            int i, f, h;
+            return (h = ((i = baseIndex) + (f = baseLimit)) >>> 1) <= i ? null :
+                new ValueSpliterator<K,V>(tab, baseSize, baseLimit = h,
+                                          f, est >>>= 1);
+        }
+
+        public void forEachRemaining(Consumer<? super V> action) {
+            if (action == null) throw new NullPointerException();
+            for (Node<K,V> p; (p = advance()) != null;)
+                action.accept(p.val);
+        }
+
+        public boolean tryAdvance(Consumer<? super V> action) {
+            if (action == null) throw new NullPointerException();
+            Node<K,V> p;
+            if ((p = advance()) == null)
+                return false;
+            action.accept(p.val);
+            return true;
+        }
+
+        public long estimateSize() { return est; }
+
+        public int characteristics() {
+            return Spliterator.CONCURRENT | Spliterator.NONNULL;
+        }
     }
 
+    static final class EntrySpliterator<K,V> extends Traverser<K,V>
+        implements Spliterator<Map.Entry<K,V>> {
+        final ConcurrentHashMap<K,V> map; // To export MapEntry
+        long est;               // size estimate
+        EntrySpliterator(Node<K,V>[] tab, int size, int index, int limit,
+                         long est, ConcurrentHashMap<K,V> map) {
+            super(tab, size, index, limit);
+            this.map = map;
+            this.est = est;
+        }
+
+        public Spliterator<Map.Entry<K,V>> trySplit() {
+            int i, f, h;
+            return (h = ((i = baseIndex) + (f = baseLimit)) >>> 1) <= i ? null :
+                new EntrySpliterator<K,V>(tab, baseSize, baseLimit = h,
+                                          f, est >>>= 1, map);
+        }
+
+        public void forEachRemaining(Consumer<? super Map.Entry<K,V>> action) {
+            if (action == null) throw new NullPointerException();
+            for (Node<K,V> p; (p = advance()) != null; )
+                action.accept(new MapEntry<K,V>((K)p.key, p.val, map));
+        }
+
+        public boolean tryAdvance(Consumer<? super Map.Entry<K,V>> action) {
+            if (action == null) throw new NullPointerException();
+            Node<K,V> p;
+            if ((p = advance()) == null)
+                return false;
+            action.accept(new MapEntry<K,V>((K)p.key, p.val, map));
+            return true;
+        }
+
+        public long estimateSize() { return est; }
+
+        public int characteristics() {
+            return Spliterator.DISTINCT | Spliterator.CONCURRENT |
+                Spliterator.NONNULL;
+        }
+    }
+
+
     /* ---------------- Public operations -------------- */
 
     /**
-     * Creates a new, empty map with the specified initial
-     * capacity, load factor and concurrency level.
-     *
-     * @param initialCapacity the initial capacity. The implementation
-     * performs internal sizing to accommodate this many elements.
-     * @param loadFactor  the load factor threshold, used to control resizing.
-     * Resizing may be performed when the average number of elements per
-     * bin exceeds this threshold.
-     * @param concurrencyLevel the estimated number of concurrently
-     * updating threads. The implementation performs internal sizing
-     * to try to accommodate this many threads.
-     * @throws IllegalArgumentException if the initial capacity is
-     * negative or the load factor or concurrencyLevel are
-     * nonpositive.
+     * Creates a new, empty map with the default initial table size (16).
      */
-    @SuppressWarnings("unchecked")
-    public ConcurrentHashMap(int initialCapacity,
-                             float loadFactor, int concurrencyLevel) {
-        if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0)
-            throw new IllegalArgumentException();
-        if (concurrencyLevel > MAX_SEGMENTS)
-            concurrencyLevel = MAX_SEGMENTS;
-        // Find power-of-two sizes best matching arguments
-        int sshift = 0;
-        int ssize = 1;
-        while (ssize < concurrencyLevel) {
-            ++sshift;
-            ssize <<= 1;
-        }
-        this.segmentShift = 32 - sshift;
-        this.segmentMask = ssize - 1;
-        if (initialCapacity > MAXIMUM_CAPACITY)
-            initialCapacity = MAXIMUM_CAPACITY;
-        int c = initialCapacity / ssize;
-        if (c * ssize < initialCapacity)
-            ++c;
-        int cap = MIN_SEGMENT_TABLE_CAPACITY;
-        while (cap < c)
-            cap <<= 1;
-        // create segments and segments[0]
-        Segment<K,V> s0 =
-            new Segment<K,V>(loadFactor, (int)(cap * loadFactor),
-                             (HashEntry<K,V>[])new HashEntry<?,?>[cap]);
-        Segment<K,V>[] ss = (Segment<K,V>[])new Segment<?,?>[ssize];
-        UNSAFE.putOrderedObject(ss, SBASE, s0); // ordered write of segments[0]
-        this.segments = ss;
+    public ConcurrentHashMap() {
     }
 
     /**
-     * Creates a new, empty map with the specified initial capacity
-     * and load factor and with the default concurrencyLevel (16).
+     * Creates a new, empty map with an initial table size
+     * accommodating the specified number of elements without the need
+     * to dynamically resize.
      *
      * @param initialCapacity The implementation performs internal
      * sizing to accommodate this many elements.
-     * @param loadFactor  the load factor threshold, used to control resizing.
-     * Resizing may be performed when the average number of elements per
-     * bin exceeds this threshold.
+     * @throws IllegalArgumentException if the initial capacity of
+     * elements is negative
+     */
+    public ConcurrentHashMap(int initialCapacity) {
+        if (initialCapacity < 0)
+            throw new IllegalArgumentException();
+        int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ?
+                   MAXIMUM_CAPACITY :
+                   tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1));
+        this.sizeCtl = cap;
+    }
+
+    /**
+     * Creates a new map with the same mappings as the given map.
+     *
+     * @param m the map
+     */
+    public ConcurrentHashMap(Map<? extends K, ? extends V> m) {
+        this.sizeCtl = DEFAULT_CAPACITY;
+        internalPutAll(m);
+    }
+
+    /**
+     * Creates a new, empty map with an initial table size based on
+     * the given number of elements ({@code initialCapacity}) and
+     * initial table density ({@code loadFactor}).
+     *
+     * @param initialCapacity the initial capacity. The implementation
+     * performs internal sizing to accommodate this many elements,
+     * given the specified load factor.
+     * @param loadFactor the load factor (table density) for
+     * establishing the initial table size
      * @throws IllegalArgumentException if the initial capacity of
      * elements is negative or the load factor is nonpositive
      *
      * @since 1.6
      */
     public ConcurrentHashMap(int initialCapacity, float loadFactor) {
-        this(initialCapacity, loadFactor, DEFAULT_CONCURRENCY_LEVEL);
+        this(initialCapacity, loadFactor, 1);
     }
 
     /**
-     * Creates a new, empty map with the specified initial capacity,
-     * and with default load factor (0.75) and concurrencyLevel (16).
+     * Creates a new, empty map with an initial table size based on
+     * the given number of elements ({@code initialCapacity}), table
+     * density ({@code loadFactor}), and number of concurrently
+     * updating threads ({@code concurrencyLevel}).
      *
      * @param initialCapacity the initial capacity. The implementation
-     * performs internal sizing to accommodate this many elements.
-     * @throws IllegalArgumentException if the initial capacity of
-     * elements is negative.
+     * performs internal sizing to accommodate this many elements,
+     * given the specified load factor.
+     * @param loadFactor the load factor (table density) for
+     * establishing the initial table size
+     * @param concurrencyLevel the estimated number of concurrently
+     * updating threads. The implementation may use this value as
+     * a sizing hint.
+     * @throws IllegalArgumentException if the initial capacity is
+     * negative or the load factor or concurrencyLevel are
+     * nonpositive
      */
-    public ConcurrentHashMap(int initialCapacity) {
-        this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
-    }
-
-    /**
-     * Creates a new, empty map with a default initial capacity (16),
-     * load factor (0.75) and concurrencyLevel (16).
-     */
-    public ConcurrentHashMap() {
-        this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
+    public ConcurrentHashMap(int initialCapacity,
+                             float loadFactor, int concurrencyLevel) {
+        if (!(loadFactor > 0.0f) || initialCapacity < 0 || concurrencyLevel <= 0)
+            throw new IllegalArgumentException();
+        if (initialCapacity < concurrencyLevel)   // Use at least as many bins
+            initialCapacity = concurrencyLevel;   // as estimated threads
+        long size = (long)(1.0 + (long)initialCapacity / loadFactor);
+        int cap = (size >= (long)MAXIMUM_CAPACITY) ?
+            MAXIMUM_CAPACITY : tableSizeFor((int)size);
+        this.sizeCtl = cap;
     }
 
     /**
-     * Creates a new map with the same mappings as the given map.
-     * The map is created with a capacity of 1.5 times the number
-     * of mappings in the given map or 16 (whichever is greater),
-     * and a default load factor (0.75) and concurrencyLevel (16).
+     * Creates a new {@link Set} backed by a ConcurrentHashMap
+     * from the given type to {@code Boolean.TRUE}.
      *
-     * @param m the map
+     * @return the new set
+     * @since 1.8
      */
-    public ConcurrentHashMap(Map<? extends K, ? extends V> m) {
-        this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
-                      DEFAULT_INITIAL_CAPACITY),
-             DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
-        putAll(m);
+    public static <K> KeySetView<K,Boolean> newKeySet() {
+        return new KeySetView<K,Boolean>
+            (new ConcurrentHashMap<K,Boolean>(), Boolean.TRUE);
     }
 
     /**
-     * Returns <tt>true</tt> if this map contains no key-value mappings.
+     * Creates a new {@link Set} backed by a ConcurrentHashMap
+     * from the given type to {@code Boolean.TRUE}.
      *
-     * @return <tt>true</tt> if this map contains no key-value mappings
+     * @param initialCapacity The implementation performs internal
+     * sizing to accommodate this many elements.
+     * @throws IllegalArgumentException if the initial capacity of
+     * elements is negative
+     * @return the new set
+     * @since 1.8
+     */
+    public static <K> KeySetView<K,Boolean> newKeySet(int initialCapacity) {
+        return new KeySetView<K,Boolean>
+            (new ConcurrentHashMap<K,Boolean>(initialCapacity), Boolean.TRUE);
+    }
+
+    /**
+     * Returns {@code true} if this map contains no key-value mappings.
+     *
+     * @return {@code true} if this map contains no key-value mappings
      */
     public boolean isEmpty() {
-        /*
-         * Sum per-segment modCounts to avoid mis-reporting when
-         * elements are concurrently added and removed in one segment
-         * while checking another, in which case the table was never
-         * actually empty at any point. (The sum ensures accuracy up
-         * through at least 1<<31 per-segment modifications before
-         * recheck.)  Methods size() and containsValue() use similar
-         * constructions for stability checks.
-         */
-        long sum = 0L;
-        final Segment<K,V>[] segments = this.segments;
-        for (int j = 0; j < segments.length; ++j) {
-            Segment<K,V> seg = segmentAt(segments, j);
-            if (seg != null) {
-                if (seg.count != 0)
-                    return false;
-                sum += seg.modCount;
-            }
-        }
-        if (sum != 0L) { // recheck unless no modifications
-            for (int j = 0; j < segments.length; ++j) {
-                Segment<K,V> seg = segmentAt(segments, j);
-                if (seg != null) {
-                    if (seg.count != 0)
-                        return false;
-                    sum -= seg.modCount;
-                }
-            }
-            if (sum != 0L)
-                return false;
-        }
-        return true;
+        return sumCount() <= 0L; // ignore transient negative values
     }
 
     /**
      * Returns the number of key-value mappings in this map.  If the
-     * map contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
-     * <tt>Integer.MAX_VALUE</tt>.
+     * map contains more than {@code Integer.MAX_VALUE} elements, returns
+     * {@code Integer.MAX_VALUE}.
      *
      * @return the number of key-value mappings in this map
      */
     public int size() {
-        // Try a few times to get accurate count. On failure due to
-        // continuous async changes in table, resort to locking.
-        final Segment<K,V>[] segments = this.segments;
-        int size;
-        boolean overflow; // true if size overflows 32 bits
-        long sum;         // sum of modCounts
-        long last = 0L;   // previous sum
-        int retries = -1; // first iteration isn't retry
-        try {
-            for (;;) {
-                if (retries++ == RETRIES_BEFORE_LOCK) {
-                    for (int j = 0; j < segments.length; ++j)
-                        ensureSegment(j).lock(); // force creation
-                }
-                sum = 0L;
-                size = 0;
-                overflow = false;
-                for (int j = 0; j < segments.length; ++j) {
-                    Segment<K,V> seg = segmentAt(segments, j);
-                    if (seg != null) {
-                        sum += seg.modCount;
-                        int c = seg.count;
-                        if (c < 0 || (size += c) < 0)
-                            overflow = true;
-                    }
-                }
-                if (sum == last)
-                    break;
-                last = sum;
-            }
-        } finally {
-            if (retries > RETRIES_BEFORE_LOCK) {
-                for (int j = 0; j < segments.length; ++j)
-                    segmentAt(segments, j).unlock();
-            }
-        }
-        return overflow ? Integer.MAX_VALUE : size;
+        long n = sumCount();
+        return ((n < 0L) ? 0 :
+                (n > (long)Integer.MAX_VALUE) ? Integer.MAX_VALUE :
+                (int)n);
+    }
+
+    /**
+     * Returns the number of mappings. This method should be used
+     * instead of {@link #size} because a ConcurrentHashMap may
+     * contain more mappings than can be represented as an int. The
+     * value returned is an estimate; the actual count may differ if
+     * there are concurrent insertions or removals.
+     *
+     * @return the number of mappings
+     * @since 1.8
+     */
+    public long mappingCount() {
+        long n = sumCount();
+        return (n < 0L) ? 0L : n; // ignore transient negative values
     }
 
     /**
@@ -926,47 +2682,58 @@
      *
      * @throws NullPointerException if the specified key is null
      */
-    @SuppressWarnings("unchecked")
     public V get(Object key) {
-        Segment<K,V> s; // manually integrate access methods to reduce overhead
-        HashEntry<K,V>[] tab;
-        int h = hash(key);
-        long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
-        if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null &&
-            (tab = s.table) != null) {
-            for (HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile
-                     (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);
-                 e != null; e = e.next) {
-                K k;
-                if ((k = e.key) == key || (e.hash == h && key.equals(k)))
-                    return e.value;
-            }
-        }
-        return null;
+        return internalGet(key);
+    }
+
+    /**
+     * Returns the value to which the specified key is mapped, or the
+     * given default value if this map contains no mapping for the
+     * key.
+     *
+     * @param key the key whose associated value is to be returned
+     * @param defaultValue the value to return if this map contains
+     * no mapping for the given key
+     * @return the mapping for the key, if present; else the default value
+     * @throws NullPointerException if the specified key is null
+     */
+    public V getOrDefault(Object key, V defaultValue) {
+        V v;
+        return (v = internalGet(key)) == null ? defaultValue : v;
     }
 
     /**
      * Tests if the specified object is a key in this table.
      *
-     * @param  key   possible key
-     * @return <tt>true</tt> if and only if the specified object
+     * @param  key possible key
+     * @return {@code true} if and only if the specified object
      *         is a key in this table, as determined by the
-     *         <tt>equals</tt> method; <tt>false</tt> otherwise.
+     *         {@code equals} method; {@code false} otherwise
      * @throws NullPointerException if the specified key is null
      */
-    @SuppressWarnings("unchecked")
     public boolean containsKey(Object key) {
-        Segment<K,V> s; // same as get() except no need for volatile value read
-        HashEntry<K,V>[] tab;
-        int h = hash(key);
-        long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
-        if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null &&
-            (tab = s.table) != null) {
-            for (HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile
-                     (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);
-                 e != null; e = e.next) {
-                K k;
-                if ((k = e.key) == key || (e.hash == h && key.equals(k)))
+        return internalGet(key) != null;
+    }
+
+    /**
+     * Returns {@code true} if this map maps one or more keys to the
+     * specified value. Note: This method may require a full traversal
+     * of the map, and is much slower than method {@code containsKey}.
+     *
+     * @param value value whose presence in this map is to be tested
+     * @return {@code true} if this map maps one or more keys to the
+     *         specified value
+     * @throws NullPointerException if the specified value is null
+     */
+    public boolean containsValue(Object value) {
+        if (value == null)
+            throw new NullPointerException();
+        Node<K,V>[] t;
+        if ((t = table) != null) {
+            Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+            for (Node<K,V> p; (p = it.advance()) != null; ) {
+                V v;
+                if ((v = p.val) == value || value.equals(v))
                     return true;
             }
         }
@@ -974,75 +2741,18 @@
     }
 
     /**
-     * Returns <tt>true</tt> if this map maps one or more keys to the
-     * specified value. Note: This method requires a full internal
-     * traversal of the hash table, and so is much slower than
-     * method <tt>containsKey</tt>.
-     *
-     * @param value value whose presence in this map is to be tested
-     * @return <tt>true</tt> if this map maps one or more keys to the
-     *         specified value
-     * @throws NullPointerException if the specified value is null
-     */
-    public boolean containsValue(Object value) {
-        // Same idea as size()
-        if (value == null)
-            throw new NullPointerException();
-        final Segment<K,V>[] segments = this.segments;
-        boolean found = false;
-        long last = 0;
-        int retries = -1;
-        try {
-            outer: for (;;) {
-                if (retries++ == RETRIES_BEFORE_LOCK) {
-                    for (int j = 0; j < segments.length; ++j)
-                        ensureSegment(j).lock(); // force creation
-                }
-                long hashSum = 0L;
-                int sum = 0;
-                for (int j = 0; j < segments.length; ++j) {
-                    HashEntry<K,V>[] tab;
-                    Segment<K,V> seg = segmentAt(segments, j);
-                    if (seg != null && (tab = seg.table) != null) {
-                        for (int i = 0 ; i < tab.length; i++) {
-                            HashEntry<K,V> e;
-                            for (e = entryAt(tab, i); e != null; e = e.next) {
-                                V v = e.value;
-                                if (v != null && value.equals(v)) {
-                                    found = true;
-                                    break outer;
-                                }
-                            }
-                        }
-                        sum += seg.modCount;
-                    }
-                }
-                if (retries > 0 && sum == last)
-                    break;
-                last = sum;
-            }
-        } finally {
-            if (retries > RETRIES_BEFORE_LOCK) {
-                for (int j = 0; j < segments.length; ++j)
-                    segmentAt(segments, j).unlock();
-            }
-        }
-        return found;
-    }
-
-    /**
      * Legacy method testing if some key maps into the specified value
      * in this table.  This method is identical in functionality to
-     * {@link #containsValue}, and exists solely to ensure
+     * {@link #containsValue(Object)}, and exists solely to ensure
      * full compatibility with class {@link java.util.Hashtable},
      * which supported this method prior to introduction of the
      * Java Collections framework.
      *
      * @param  value a value to search for
-     * @return <tt>true</tt> if and only if some key maps to the
-     *         <tt>value</tt> argument in this table as
-     *         determined by the <tt>equals</tt> method;
-     *         <tt>false</tt> otherwise
+     * @return {@code true} if and only if some key maps to the
+     *         {@code value} argument in this table as
+     *         determined by the {@code equals} method;
+     *         {@code false} otherwise
      * @throws NullPointerException if the specified value is null
      */
     public boolean contains(Object value) {
@@ -1053,46 +2763,28 @@
      * Maps the specified key to the specified value in this table.
      * Neither the key nor the value can be null.
      *
-     * <p> The value can be retrieved by calling the <tt>get</tt> method
+     * <p>The value can be retrieved by calling the {@code get} method
      * with a key that is equal to the original key.
      *
      * @param key key with which the specified value is to be associated
      * @param value value to be associated with the specified key
-     * @return the previous value associated with <tt>key</tt>, or
-     *         <tt>null</tt> if there was no mapping for <tt>key</tt>
+     * @return the previous value associated with {@code key}, or
+     *         {@code null} if there was no mapping for {@code key}
      * @throws NullPointerException if the specified key or value is null
      */
-    @SuppressWarnings("unchecked")
     public V put(K key, V value) {
-        Segment<K,V> s;
-        if (value == null)
-            throw new NullPointerException();
-        int hash = hash(key);
-        int j = (hash >>> segmentShift) & segmentMask;
-        if ((s = (Segment<K,V>)UNSAFE.getObject          // nonvolatile; recheck
-             (segments, (j << SSHIFT) + SBASE)) == null) //  in ensureSegment
-            s = ensureSegment(j);
-        return s.put(key, hash, value, false);
+        return internalPut(key, value, false);
     }
 
     /**
      * {@inheritDoc}
      *
      * @return the previous value associated with the specified key,
-     *         or <tt>null</tt> if there was no mapping for the key
+     *         or {@code null} if there was no mapping for the key
      * @throws NullPointerException if the specified key or value is null
      */
-    @SuppressWarnings("unchecked")
     public V putIfAbsent(K key, V value) {
-        Segment<K,V> s;
-        if (value == null)
-            throw new NullPointerException();
-        int hash = hash(key);
-        int j = (hash >>> segmentShift) & segmentMask;
-        if ((s = (Segment<K,V>)UNSAFE.getObject
-             (segments, (j << SSHIFT) + SBASE)) == null)
-            s = ensureSegment(j);
-        return s.put(key, hash, value, true);
+        return internalPut(key, value, true);
     }
 
     /**
@@ -1103,8 +2795,105 @@
      * @param m mappings to be stored in this map
      */
     public void putAll(Map<? extends K, ? extends V> m) {
-        for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
-            put(e.getKey(), e.getValue());
+        internalPutAll(m);
+    }
+
+    /**
+     * If the specified key is not already associated with a value,
+     * attempts to compute its value using the given mapping function
+     * and enters it into this map unless {@code null}.  The entire
+     * method invocation is performed atomically, so the function is
+     * applied at most once per key.  Some attempted update operations
+     * on this map by other threads may be blocked while computation
+     * is in progress, so the computation should be short and simple,
+     * and must not attempt to update any other mappings of this map.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param mappingFunction the function to compute a value
+     * @return the current (existing or computed) value associated with
+     *         the specified key, or null if the computed value is null
+     * @throws NullPointerException if the specified key or mappingFunction
+     *         is null
+     * @throws IllegalStateException if the computation detectably
+     *         attempts a recursive update to this map that would
+     *         otherwise never complete
+     * @throws RuntimeException or Error if the mappingFunction does so,
+     *         in which case the mapping is left unestablished
+     */
+    public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
+        return internalComputeIfAbsent(key, mappingFunction);
+    }
+
+    /**
+     * If the value for the specified key is present, attempts to
+     * compute a new mapping given the key and its current mapped
+     * value.  The entire method invocation is performed atomically.
+     * Some attempted update operations on this map by other threads
+     * may be blocked while computation is in progress, so the
+     * computation should be short and simple, and must not attempt to
+     * update any other mappings of this map.
+     *
+     * @param key key with which a value may be associated
+     * @param remappingFunction the function to compute a value
+     * @return the new value associated with the specified key, or null if none
+     * @throws NullPointerException if the specified key or remappingFunction
+     *         is null
+     * @throws IllegalStateException if the computation detectably
+     *         attempts a recursive update to this map that would
+     *         otherwise never complete
+     * @throws RuntimeException or Error if the remappingFunction does so,
+     *         in which case the mapping is unchanged
+     */
+    public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        return internalCompute(key, true, remappingFunction);
+    }
+
+    /**
+     * Attempts to compute a mapping for the specified key and its
+     * current mapped value (or {@code null} if there is no current
+     * mapping). The entire method invocation is performed atomically.
+     * Some attempted update operations on this map by other threads
+     * may be blocked while computation is in progress, so the
+     * computation should be short and simple, and must not attempt to
+     * update any other mappings of this Map.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param remappingFunction the function to compute a value
+     * @return the new value associated with the specified key, or null if none
+     * @throws NullPointerException if the specified key or remappingFunction
+     *         is null
+     * @throws IllegalStateException if the computation detectably
+     *         attempts a recursive update to this map that would
+     *         otherwise never complete
+     * @throws RuntimeException or Error if the remappingFunction does so,
+     *         in which case the mapping is unchanged
+     */
+    public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        return internalCompute(key, false, remappingFunction);
+    }
+
+    /**
+     * If the specified key is not already associated with a
+     * (non-null) value, associates it with the given value.
+     * Otherwise, replaces the value with the results of the given
+     * remapping function, or removes if {@code null}. The entire
+     * method invocation is performed atomically.  Some attempted
+     * update operations on this map by other threads may be blocked
+     * while computation is in progress, so the computation should be
+     * short and simple, and must not attempt to update any other
+     * mappings of this Map.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param value the value to use if absent
+     * @param remappingFunction the function to recompute a value if present
+     * @return the new value associated with the specified key, or null if none
+     * @throws NullPointerException if the specified key or the
+     *         remappingFunction is null
+     * @throws RuntimeException or Error if the remappingFunction does so,
+     *         in which case the mapping is unchanged
+     */
+    public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+        return internalMerge(key, value, remappingFunction);
     }
 
     /**
@@ -1112,14 +2901,12 @@
      * This method does nothing if the key is not in the map.
      *
      * @param  key the key that needs to be removed
-     * @return the previous value associated with <tt>key</tt>, or
-     *         <tt>null</tt> if there was no mapping for <tt>key</tt>
+     * @return the previous value associated with {@code key}, or
+     *         {@code null} if there was no mapping for {@code key}
      * @throws NullPointerException if the specified key is null
      */
     public V remove(Object key) {
-        int hash = hash(key);
-        Segment<K,V> s = segmentForHash(hash);
-        return s == null ? null : s.remove(key, hash, null);
+        return internalReplace(key, null, null);
     }
 
     /**
@@ -1128,10 +2915,9 @@
      * @throws NullPointerException if the specified key is null
      */
     public boolean remove(Object key, Object value) {
-        int hash = hash(key);
-        Segment<K,V> s;
-        return value != null && (s = segmentForHash(hash)) != null &&
-            s.remove(key, hash, value) != null;
+        if (key == null)
+            throw new NullPointerException();
+        return value != null && internalReplace(key, null, value) != null;
     }
 
     /**
@@ -1140,59 +2926,69 @@
      * @throws NullPointerException if any of the arguments are null
      */
     public boolean replace(K key, V oldValue, V newValue) {
-        int hash = hash(key);
-        if (oldValue == null || newValue == null)
+        if (key == null || oldValue == null || newValue == null)
             throw new NullPointerException();
-        Segment<K,V> s = segmentForHash(hash);
-        return s != null && s.replace(key, hash, oldValue, newValue);
+        return internalReplace(key, newValue, oldValue) != null;
     }
 
     /**
      * {@inheritDoc}
      *
      * @return the previous value associated with the specified key,
-     *         or <tt>null</tt> if there was no mapping for the key
+     *         or {@code null} if there was no mapping for the key
      * @throws NullPointerException if the specified key or value is null
      */
     public V replace(K key, V value) {
-        int hash = hash(key);
-        if (value == null)
+        if (key == null || value == null)
             throw new NullPointerException();
-        Segment<K,V> s = segmentForHash(hash);
-        return s == null ? null : s.replace(key, hash, value);
+        return internalReplace(key, value, null);
     }
 
     /**
      * Removes all of the mappings from this map.
      */
     public void clear() {
-        final Segment<K,V>[] segments = this.segments;
-        for (int j = 0; j < segments.length; ++j) {
-            Segment<K,V> s = segmentAt(segments, j);
-            if (s != null)
-                s.clear();
-        }
+        internalClear();
     }
 
     /**
      * Returns a {@link Set} view of the keys contained in this map.
      * The set is backed by the map, so changes to the map are
-     * reflected in the set, and vice-versa.  The set supports element
+     * reflected in the set, and vice-versa. The set supports element
      * removal, which removes the corresponding mapping from this map,
-     * via the <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
-     * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
-     * operations.  It does not support the <tt>add</tt> or
-     * <tt>addAll</tt> operations.
+     * via the {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear}
+     * operations.  It does not support the {@code add} or
+     * {@code addAll} operations.
      *
-     * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator
+     * <p>The view's {@code iterator} is a "weakly consistent" iterator
      * that will never throw {@link ConcurrentModificationException},
      * and guarantees to traverse elements as they existed upon
      * construction of the iterator, and may (but is not guaranteed to)
      * reflect any modifications subsequent to construction.
+     *
+     * @return the set view
      */
-    public Set<K> keySet() {
-        Set<K> ks = keySet;
-        return (ks != null) ? ks : (keySet = new KeySet());
+    public KeySetView<K,V> keySet() {
+        KeySetView<K,V> ks = keySet;
+        return (ks != null) ? ks : (keySet = new KeySetView<K,V>(this, null));
+    }
+
+    /**
+     * Returns a {@link Set} view of the keys in this map, using the
+     * given common mapped value for any additions (i.e., {@link
+     * Collection#add} and {@link Collection#addAll(Collection)}).
+     * This is of course only appropriate if it is acceptable to use
+     * the same value for all additions from this view.
+     *
+     * @param mappedValue the mapped value to use for any additions
+     * @return the set view
+     * @throws NullPointerException if the mappedValue is null
+     */
+    public KeySetView<K,V> keySet(V mappedValue) {
+        if (mappedValue == null)
+            throw new NullPointerException();
+        return new KeySetView<K,V>(this, mappedValue);
     }
 
     /**
@@ -1200,20 +2996,22 @@
      * The collection is backed by the map, so changes to the map are
      * reflected in the collection, and vice-versa.  The collection
      * supports element removal, which removes the corresponding
-     * mapping from this map, via the <tt>Iterator.remove</tt>,
-     * <tt>Collection.remove</tt>, <tt>removeAll</tt>,
-     * <tt>retainAll</tt>, and <tt>clear</tt> operations.  It does not
-     * support the <tt>add</tt> or <tt>addAll</tt> operations.
+     * mapping from this map, via the {@code Iterator.remove},
+     * {@code Collection.remove}, {@code removeAll},
+     * {@code retainAll}, and {@code clear} operations.  It does not
+     * support the {@code add} or {@code addAll} operations.
      *
-     * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator
+     * <p>The view's {@code iterator} is a "weakly consistent" iterator
      * that will never throw {@link ConcurrentModificationException},
      * and guarantees to traverse elements as they existed upon
      * construction of the iterator, and may (but is not guaranteed to)
      * reflect any modifications subsequent to construction.
+     *
+     * @return the collection view
      */
     public Collection<V> values() {
-        Collection<V> vs = values;
-        return (vs != null) ? vs : (values = new Values());
+        ValuesView<K,V> vs = values;
+        return (vs != null) ? vs : (values = new ValuesView<K,V>(this));
     }
 
     /**
@@ -1221,20 +3019,21 @@
      * The set is backed by the map, so changes to the map are
      * reflected in the set, and vice-versa.  The set supports element
      * removal, which removes the corresponding mapping from the map,
-     * via the <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
-     * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
-     * operations.  It does not support the <tt>add</tt> or
-     * <tt>addAll</tt> operations.
+     * via the {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear}
+     * operations.
      *
-     * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator
+     * <p>The view's {@code iterator} is a "weakly consistent" iterator
      * that will never throw {@link ConcurrentModificationException},
      * and guarantees to traverse elements as they existed upon
      * construction of the iterator, and may (but is not guaranteed to)
      * reflect any modifications subsequent to construction.
+     *
+     * @return the set view
      */
     public Set<Map.Entry<K,V>> entrySet() {
-        Set<Map.Entry<K,V>> es = entrySet;
-        return (es != null) ? es : (entrySet = new EntrySet());
+        EntrySetView<K,V> es = entrySet;
+        return (es != null) ? es : (entrySet = new EntrySetView<K,V>(this));
     }
 
     /**
@@ -1244,7 +3043,9 @@
      * @see #keySet()
      */
     public Enumeration<K> keys() {
-        return new KeyIterator();
+        Node<K,V>[] t;
+        int f = (t = table) == null ? 0 : t.length;
+        return new KeyIterator<K,V>(t, f, 0, f, this);
     }
 
     /**
@@ -1254,193 +3055,112 @@
      * @see #values()
      */
     public Enumeration<V> elements() {
-        return new ValueIterator();
+        Node<K,V>[] t;
+        int f = (t = table) == null ? 0 : t.length;
+        return new ValueIterator<K,V>(t, f, 0, f, this);
     }
 
-    /* ---------------- Iterator Support -------------- */
-
-    abstract class HashIterator {
-        int nextSegmentIndex;
-        int nextTableIndex;
-        HashEntry<K,V>[] currentTable;
-        HashEntry<K, V> nextEntry;
-        HashEntry<K, V> lastReturned;
-
-        HashIterator() {
-            nextSegmentIndex = segments.length - 1;
-            nextTableIndex = -1;
-            advance();
+    /**
+     * Returns the hash code value for this {@link Map}, i.e.,
+     * the sum of, for each key-value pair in the map,
+     * {@code key.hashCode() ^ value.hashCode()}.
+     *
+     * @return the hash code value for this map
+     */
+    public int hashCode() {
+        int h = 0;
+        Node<K,V>[] t;
+        if ((t = table) != null) {
+            Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+            for (Node<K,V> p; (p = it.advance()) != null; )
+                h += p.key.hashCode() ^ p.val.hashCode();
         }
-
-        /**
-         * Sets nextEntry to first node of next non-empty table
-         * (in backwards order, to simplify checks).
-         */
-        final void advance() {
-            for (;;) {
-                if (nextTableIndex >= 0) {
-                    if ((nextEntry = entryAt(currentTable,
-                                             nextTableIndex--)) != null)
-                        break;
-                }
-                else if (nextSegmentIndex >= 0) {
-                    Segment<K,V> seg = segmentAt(segments, nextSegmentIndex--);
-                    if (seg != null && (currentTable = seg.table) != null)
-                        nextTableIndex = currentTable.length - 1;
-                }
-                else
-                    break;
-            }
-        }
-
-        final HashEntry<K,V> nextEntry() {
-            HashEntry<K,V> e = nextEntry;
-            if (e == null)
-                throw new NoSuchElementException();
-            lastReturned = e; // cannot assign until after null check
-            if ((nextEntry = e.next) == null)
-                advance();
-            return e;
-        }
-
-        public final boolean hasNext() { return nextEntry != null; }
-        public final boolean hasMoreElements() { return nextEntry != null; }
-
-        public final void remove() {
-            if (lastReturned == null)
-                throw new IllegalStateException();
-            ConcurrentHashMap.this.remove(lastReturned.key);
-            lastReturned = null;
-        }
-    }
-
-    final class KeyIterator
-        extends HashIterator
-        implements Iterator<K>, Enumeration<K>
-    {
-        public final K next()        { return super.nextEntry().key; }
-        public final K nextElement() { return super.nextEntry().key; }
-    }
-
-    final class ValueIterator
-        extends HashIterator
-        implements Iterator<V>, Enumeration<V>
-    {
-        public final V next()        { return super.nextEntry().value; }
-        public final V nextElement() { return super.nextEntry().value; }
+        return h;
     }
 
     /**
-     * Custom Entry class used by EntryIterator.next(), that relays
-     * setValue changes to the underlying map.
+     * Returns a string representation of this map.  The string
+     * representation consists of a list of key-value mappings (in no
+     * particular order) enclosed in braces ("{@code {}}").  Adjacent
+     * mappings are separated by the characters {@code ", "} (comma
+     * and space).  Each key-value mapping is rendered as the key
+     * followed by an equals sign ("{@code =}") followed by the
+     * associated value.
+     *
+     * @return a string representation of this map
      */
-    final class WriteThroughEntry
-        extends AbstractMap.SimpleEntry<K,V>
-    {
-        static final long serialVersionUID = 7249069246763182397L;
-
-        WriteThroughEntry(K k, V v) {
-            super(k,v);
-        }
-
-        /**
-         * Sets our entry's value and writes through to the map. The
-         * value to return is somewhat arbitrary here. Since a
-         * WriteThroughEntry does not necessarily track asynchronous
-         * changes, the most recent "previous" value could be
-         * different from what we return (or could even have been
-         * removed in which case the put will re-establish). We do not
-         * and cannot guarantee more.
-         */
-        public V setValue(V value) {
-            if (value == null) throw new NullPointerException();
-            V v = super.setValue(value);
-            ConcurrentHashMap.this.put(getKey(), value);
-            return v;
-        }
-    }
-
-    final class EntryIterator
-        extends HashIterator
-        implements Iterator<Entry<K,V>>
-    {
-        public Map.Entry<K,V> next() {
-            HashEntry<K,V> e = super.nextEntry();
-            return new WriteThroughEntry(e.key, e.value);
-        }
-    }
-
-    final class KeySet extends AbstractSet<K> {
-        public Iterator<K> iterator() {
-            return new KeyIterator();
-        }
-        public int size() {
-            return ConcurrentHashMap.this.size();
-        }
-        public boolean isEmpty() {
-            return ConcurrentHashMap.this.isEmpty();
-        }
-        public boolean contains(Object o) {
-            return ConcurrentHashMap.this.containsKey(o);
+    public String toString() {
+        Node<K,V>[] t;
+        int f = (t = table) == null ? 0 : t.length;
+        Traverser<K,V> it = new Traverser<K,V>(t, f, 0, f);
+        StringBuilder sb = new StringBuilder();
+        sb.append('{');
+        Node<K,V> p;
+        if ((p = it.advance()) != null) {
+            for (;;) {
+                K k = (K)p.key;
+                V v = p.val;
+                sb.append(k == this ? "(this Map)" : k);
+                sb.append('=');
+                sb.append(v == this ? "(this Map)" : v);
+                if ((p = it.advance()) == null)
+                    break;
+                sb.append(',').append(' ');
+            }
         }
-        public boolean remove(Object o) {
-            return ConcurrentHashMap.this.remove(o) != null;
-        }
-        public void clear() {
-            ConcurrentHashMap.this.clear();
-        }
-    }
-
-    final class Values extends AbstractCollection<V> {
-        public Iterator<V> iterator() {
-            return new ValueIterator();
-        }
-        public int size() {
-            return ConcurrentHashMap.this.size();
-        }
-        public boolean isEmpty() {
-            return ConcurrentHashMap.this.isEmpty();
-        }
-        public boolean contains(Object o) {
-            return ConcurrentHashMap.this.containsValue(o);
-        }
-        public void clear() {
-            ConcurrentHashMap.this.clear();
-        }
+        return sb.append('}').toString();
     }
 
-    final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
-        public Iterator<Map.Entry<K,V>> iterator() {
-            return new EntryIterator();
-        }
-        public boolean contains(Object o) {
-            if (!(o instanceof Map.Entry))
+    /**
+     * Compares the specified object with this map for equality.
+     * Returns {@code true} if the given object is a map with the same
+     * mappings as this map.  This operation may return misleading
+     * results if either map is concurrently modified during execution
+     * of this method.
+     *
+     * @param o object to be compared for equality with this map
+     * @return {@code true} if the specified object is equal to this map
+     */
+    public boolean equals(Object o) {
+        if (o != this) {
+            if (!(o instanceof Map))
                 return false;
-            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
-            V v = ConcurrentHashMap.this.get(e.getKey());
-            return v != null && v.equals(e.getValue());
+            Map<?,?> m = (Map<?,?>) o;
+            Node<K,V>[] t;
+            int f = (t = table) == null ? 0 : t.length;
+            Traverser<K,V> it = new Traverser<K,V>(t, f, 0, f);
+            for (Node<K,V> p; (p = it.advance()) != null; ) {
+                V val = p.val;
+                Object v = m.get(p.key);
+                if (v == null || (v != val && !v.equals(val)))
+                    return false;
+            }
+            for (Map.Entry<?,?> e : m.entrySet()) {
+                Object mk, mv, v;
+                if ((mk = e.getKey()) == null ||
+                    (mv = e.getValue()) == null ||
+                    (v = internalGet(mk)) == null ||
+                    (mv != v && !mv.equals(v)))
+                    return false;
+            }
         }
-        public boolean remove(Object o) {
-            if (!(o instanceof Map.Entry))
-                return false;
-            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
-            return ConcurrentHashMap.this.remove(e.getKey(), e.getValue());
-        }
-        public int size() {
-            return ConcurrentHashMap.this.size();
-        }
-        public boolean isEmpty() {
-            return ConcurrentHashMap.this.isEmpty();
-        }
-        public void clear() {
-            ConcurrentHashMap.this.clear();
-        }
+        return true;
     }
 
     /* ---------------- Serialization Support -------------- */
 
     /**
-     * Saves the state of the <tt>ConcurrentHashMap</tt> instance to a
+     * Stripped-down version of helper class used in previous version,
+     * declared for the sake of serialization compatibility
+     */
+    static class Segment<K,V> extends ReentrantLock implements Serializable {
+        private static final long serialVersionUID = 2249069246763182397L;
+        final float loadFactor;
+        Segment(float lf) { this.loadFactor = lf; }
+    }
+
+    /**
+     * Saves the state of the {@code ConcurrentHashMap} instance to a
      * stream (i.e., serializes it).
      * @param s the stream
      * @serialData
@@ -1449,120 +3169,2733 @@
      * The key-value mappings are emitted in no particular order.
      */
     private void writeObject(java.io.ObjectOutputStream s)
-            throws java.io.IOException {
-        // force all segments for serialization compatibility
-        for (int k = 0; k < segments.length; ++k)
-            ensureSegment(k);
-        s.defaultWriteObject();
-
-        final Segment<K,V>[] segments = this.segments;
-        for (int k = 0; k < segments.length; ++k) {
-            Segment<K,V> seg = segmentAt(segments, k);
-            seg.lock();
-            try {
-                HashEntry<K,V>[] tab = seg.table;
-                for (int i = 0; i < tab.length; ++i) {
-                    HashEntry<K,V> e;
-                    for (e = entryAt(tab, i); e != null; e = e.next) {
-                        s.writeObject(e.key);
-                        s.writeObject(e.value);
-                    }
-                }
-            } finally {
-                seg.unlock();
+        throws java.io.IOException {
+        // For serialization compatibility
+        // Emulate segment calculation from previous version of this class
+        int sshift = 0;
+        int ssize = 1;
+        while (ssize < DEFAULT_CONCURRENCY_LEVEL) {
+            ++sshift;
+            ssize <<= 1;
+        }
+        int segmentShift = 32 - sshift;
+        int segmentMask = ssize - 1;
+        Segment<K,V>[] segments = (Segment<K,V>[])
+            new Segment<?,?>[DEFAULT_CONCURRENCY_LEVEL];
+        for (int i = 0; i < segments.length; ++i)
+            segments[i] = new Segment<K,V>(LOAD_FACTOR);
+        s.putFields().put("segments", segments);
+        s.putFields().put("segmentShift", segmentShift);
+        s.putFields().put("segmentMask", segmentMask);
+        s.writeFields();
+
+        Node<K,V>[] t;
+        if ((t = table) != null) {
+            Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+            for (Node<K,V> p; (p = it.advance()) != null; ) {
+                s.writeObject(p.key);
+                s.writeObject(p.val);
             }
         }
         s.writeObject(null);
         s.writeObject(null);
+        segments = null; // throw away
+    }
+
+    /**
+     * Reconstitutes the instance from a stream (that is, deserializes it).
+     * @param s the stream
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        s.defaultReadObject();
+
+        // Create all nodes, then place in table once size is known
+        long size = 0L;
+        Node<K,V> p = null;
+        for (;;) {
+            K k = (K) s.readObject();
+            V v = (V) s.readObject();
+            if (k != null && v != null) {
+                int h = spread(k.hashCode());
+                p = new Node<K,V>(h, k, v, p);
+                ++size;
+            }
+            else
+                break;
+        }
+        if (p != null) {
+            boolean init = false;
+            int n;
+            if (size >= (long)(MAXIMUM_CAPACITY >>> 1))
+                n = MAXIMUM_CAPACITY;
+            else {
+                int sz = (int)size;
+                n = tableSizeFor(sz + (sz >>> 1) + 1);
+            }
+            int sc = sizeCtl;
+            boolean collide = false;
+            if (n > sc &&
+                U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
+                try {
+                    if (table == null) {
+                        init = true;
+                        Node<K,V>[] tab = (Node<K,V>[])new Node[n];
+                        int mask = n - 1;
+                        while (p != null) {
+                            int j = p.hash & mask;
+                            Node<K,V> next = p.next;
+                            Node<K,V> q = p.next = tabAt(tab, j);
+                            setTabAt(tab, j, p);
+                            if (!collide && q != null && q.hash == p.hash)
+                                collide = true;
+                            p = next;
+                        }
+                        table = tab;
+                        addCount(size, -1);
+                        sc = n - (n >>> 2);
+                    }
+                } finally {
+                    sizeCtl = sc;
+                }
+                if (collide) { // rescan and convert to TreeBins
+                    Node<K,V>[] tab = table;
+                    for (int i = 0; i < tab.length; ++i) {
+                        int c = 0;
+                        for (Node<K,V> e = tabAt(tab, i); e != null; e = e.next) {
+                            if (++c > TREE_THRESHOLD &&
+                                (e.key instanceof Comparable)) {
+                                replaceWithTreeBin(tab, i, e.key);
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+            if (!init) { // Can only happen if unsafely published.
+                while (p != null) {
+                    internalPut((K)p.key, p.val, false);
+                    p = p.next;
+                }
+            }
+        }
+    }
+
+    // -------------------------------------------------------
+
+    // Overrides of other default Map methods
+
+    public void forEach(BiConsumer<? super K, ? super V> action) {
+        if (action == null) throw new NullPointerException();
+        Node<K,V>[] t;
+        if ((t = table) != null) {
+            Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+            for (Node<K,V> p; (p = it.advance()) != null; ) {
+                action.accept((K)p.key, p.val);
+            }
+        }
+    }
+
+    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+        if (function == null) throw new NullPointerException();
+        Node<K,V>[] t;
+        if ((t = table) != null) {
+            Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+            for (Node<K,V> p; (p = it.advance()) != null; ) {
+                K k = (K)p.key;
+                internalPut(k, function.apply(k, p.val), false);
+            }
+        }
+    }
+
+    // -------------------------------------------------------
+
+    // Parallel bulk operations
+
+    /**
+     * Computes initial batch value for bulk tasks. The returned value
+     * is approximately exp2 of the number of times (minus one) to
+     * split task by two before executing leaf action. This value is
+     * faster to compute and more convenient to use as a guide to
+     * splitting than is the depth, since it is used while dividing by
+     * two anyway.
+     */
+    final int batchFor(long b) {
+        long n;
+        if (b == Long.MAX_VALUE || (n = sumCount()) <= 1L || n < b)
+            return 0;
+        int sp = ForkJoinPool.getCommonPoolParallelism() << 2; // slack of 4
+        return (b <= 0L || (n /= b) >= sp) ? sp : (int)n;
+    }
+
+    /**
+     * Performs the given action for each (key, value).
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param action the action
+     * @since 1.8
+     */
+    public void forEach(long parallelismThreshold,
+                        BiConsumer<? super K,? super V> action) {
+        if (action == null) throw new NullPointerException();
+        new ForEachMappingTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             action).invoke();
+    }
+
+    /**
+     * Performs the given action for each non-null transformation
+     * of each (key, value).
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element, or null if there is no transformation (in
+     * which case the action is not applied)
+     * @param action the action
+     * @since 1.8
+     */
+    public <U> void forEach(long parallelismThreshold,
+                            BiFunction<? super K, ? super V, ? extends U> transformer,
+                            Consumer<? super U> action) {
+        if (transformer == null || action == null)
+            throw new NullPointerException();
+        new ForEachTransformedMappingTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             transformer, action).invoke();
+    }
+
+    /**
+     * Returns a non-null result from applying the given search
+     * function on each (key, value), or null if none.  Upon
+     * success, further element processing is suppressed and the
+     * results of any other parallel invocations of the search
+     * function are ignored.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param searchFunction a function returning a non-null
+     * result on success, else null
+     * @return a non-null result from applying the given search
+     * function on each (key, value), or null if none
+     * @since 1.8
+     */
+    public <U> U search(long parallelismThreshold,
+                        BiFunction<? super K, ? super V, ? extends U> searchFunction) {
+        if (searchFunction == null) throw new NullPointerException();
+        return new SearchMappingsTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             searchFunction, new AtomicReference<U>()).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all (key, value) pairs using the given reducer to
+     * combine values, or null if none.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element, or null if there is no transformation (in
+     * which case it is not combined)
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all (key, value) pairs
+     * @since 1.8
+     */
+    public <U> U reduce(long parallelismThreshold,
+                        BiFunction<? super K, ? super V, ? extends U> transformer,
+                        BiFunction<? super U, ? super U, ? extends U> reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceMappingsTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all (key, value) pairs using the given reducer to
+     * combine values, and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all (key, value) pairs
+     * @since 1.8
+     */
+    public double reduceToDoubleIn(long parallelismThreshold,
+                                   ToDoubleBiFunction<? super K, ? super V> transformer,
+                                   double basis,
+                                   DoubleBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceMappingsToDoubleTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all (key, value) pairs using the given reducer to
+     * combine values, and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all (key, value) pairs
+     * @since 1.8
+     */
+    public long reduceToLong(long parallelismThreshold,
+                             ToLongBiFunction<? super K, ? super V> transformer,
+                             long basis,
+                             LongBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceMappingsToLongTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all (key, value) pairs using the given reducer to
+     * combine values, and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all (key, value) pairs
+     * @since 1.8
+     */
+    public int reduceToInt(long parallelismThreshold,
+                           ToIntBiFunction<? super K, ? super V> transformer,
+                           int basis,
+                           IntBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceMappingsToIntTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Performs the given action for each key.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param action the action
+     * @since 1.8
+     */
+    public void forEachKey(long parallelismThreshold,
+                           Consumer<? super K> action) {
+        if (action == null) throw new NullPointerException();
+        new ForEachKeyTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             action).invoke();
+    }
+
+    /**
+     * Performs the given action for each non-null transformation
+     * of each key.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element, or null if there is no transformation (in
+     * which case the action is not applied)
+     * @param action the action
+     * @since 1.8
+     */
+    public <U> void forEachKey(long parallelismThreshold,
+                               Function<? super K, ? extends U> transformer,
+                               Consumer<? super U> action) {
+        if (transformer == null || action == null)
+            throw new NullPointerException();
+        new ForEachTransformedKeyTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             transformer, action).invoke();
+    }
+
+    /**
+     * Returns a non-null result from applying the given search
+     * function on each key, or null if none. Upon success,
+     * further element processing is suppressed and the results of
+     * any other parallel invocations of the search function are
+     * ignored.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param searchFunction a function returning a non-null
+     * result on success, else null
+     * @return a non-null result from applying the given search
+     * function on each key, or null if none
+     * @since 1.8
+     */
+    public <U> U searchKeys(long parallelismThreshold,
+                            Function<? super K, ? extends U> searchFunction) {
+        if (searchFunction == null) throw new NullPointerException();
+        return new SearchKeysTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             searchFunction, new AtomicReference<U>()).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating all keys using the given
+     * reducer to combine values, or null if none.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating all keys using the given
+     * reducer to combine values, or null if none
+     * @since 1.8
+     */
+    public K reduceKeys(long parallelismThreshold,
+                        BiFunction<? super K, ? super K, ? extends K> reducer) {
+        if (reducer == null) throw new NullPointerException();
+        return new ReduceKeysTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all keys using the given reducer to combine values, or
+     * null if none.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element, or null if there is no transformation (in
+     * which case it is not combined)
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all keys
+     * @since 1.8
+     */
+    public <U> U reduceKeys(long parallelismThreshold,
+                            Function<? super K, ? extends U> transformer,
+         BiFunction<? super U, ? super U, ? extends U> reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceKeysTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all keys using the given reducer to combine values, and
+     * the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all keys
+     * @since 1.8
+     */
+    public double reduceKeysToDouble(long parallelismThreshold,
+                                     ToDoubleFunction<? super K> transformer,
+                                     double basis,
+                                     DoubleBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceKeysToDoubleTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all keys using the given reducer to combine values, and
+     * the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all keys
+     * @since 1.8
+     */
+    public long reduceKeysToLong(long parallelismThreshold,
+                                 ToLongFunction<? super K> transformer,
+                                 long basis,
+                                 LongBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceKeysToLongTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all keys using the given reducer to combine values, and
+     * the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all keys
+     * @since 1.8
+     */
+    public int reduceKeysToInt(long parallelismThreshold,
+                               ToIntFunction<? super K> transformer,
+                               int basis,
+                               IntBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceKeysToIntTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Performs the given action for each value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param action the action
+     * @since 1.8
+     */
+    public void forEachValue(long parallelismThreshold,
+                             Consumer<? super V> action) {
+        if (action == null)
+            throw new NullPointerException();
+        new ForEachValueTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             action).invoke();
+    }
+
+    /**
+     * Performs the given action for each non-null transformation
+     * of each value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element, or null if there is no transformation (in
+     * which case the action is not applied)
+     * @param action the action
+     * @since 1.8
+     */
+    public <U> void forEachValue(long parallelismThreshold,
+                                 Function<? super V, ? extends U> transformer,
+                                 Consumer<? super U> action) {
+        if (transformer == null || action == null)
+            throw new NullPointerException();
+        new ForEachTransformedValueTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             transformer, action).invoke();
+    }
+
+    /**
+     * Returns a non-null result from applying the given search
+     * function on each value, or null if none.  Upon success,
+     * further element processing is suppressed and the results of
+     * any other parallel invocations of the search function are
+     * ignored.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param searchFunction a function returning a non-null
+     * result on success, else null
+     * @return a non-null result from applying the given search
+     * function on each value, or null if none
+     * @since 1.8
+     */
+    public <U> U searchValues(long parallelismThreshold,
+                              Function<? super V, ? extends U> searchFunction) {
+        if (searchFunction == null) throw new NullPointerException();
+        return new SearchValuesTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             searchFunction, new AtomicReference<U>()).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating all values using the
+     * given reducer to combine values, or null if none.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating all values
+     * @since 1.8
+     */
+    public V reduceValues(long parallelismThreshold,
+                          BiFunction<? super V, ? super V, ? extends V> reducer) {
+        if (reducer == null) throw new NullPointerException();
+        return new ReduceValuesTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all values using the given reducer to combine values, or
+     * null if none.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element, or null if there is no transformation (in
+     * which case it is not combined)
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all values
+     * @since 1.8
+     */
+    public <U> U reduceValues(long parallelismThreshold,
+                              Function<? super V, ? extends U> transformer,
+                              BiFunction<? super U, ? super U, ? extends U> reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceValuesTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all values using the given reducer to combine values,
+     * and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all values
+     * @since 1.8
+     */
+    public double reduceValuesToDouble(long parallelismThreshold,
+                                       ToDoubleFunction<? super V> transformer,
+                                       double basis,
+                                       DoubleBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceValuesToDoubleTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all values using the given reducer to combine values,
+     * and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all values
+     * @since 1.8
+     */
+    public long reduceValuesToLong(long parallelismThreshold,
+                                   ToLongFunction<? super V> transformer,
+                                   long basis,
+                                   LongBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceValuesToLongTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all values using the given reducer to combine values,
+     * and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all values
+     * @since 1.8
+     */
+    public int reduceValuesToInt(long parallelismThreshold,
+                                 ToIntFunction<? super V> transformer,
+                                 int basis,
+                                 IntBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceValuesToIntTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Performs the given action for each entry.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param action the action
+     * @since 1.8
+     */
+    public void forEachEntry(long parallelismThreshold,
+                             Consumer<? super Map.Entry<K,V>> action) {
+        if (action == null) throw new NullPointerException();
+        new ForEachEntryTask<K,V>(null, batchFor(parallelismThreshold), 0, 0, table,
+                                  action).invoke();
+    }
+
+    /**
+     * Performs the given action for each non-null transformation
+     * of each entry.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element, or null if there is no transformation (in
+     * which case the action is not applied)
+     * @param action the action
+     * @since 1.8
+     */
+    public <U> void forEachEntry(long parallelismThreshold,
+                                 Function<Map.Entry<K,V>, ? extends U> transformer,
+                                 Consumer<? super U> action) {
+        if (transformer == null || action == null)
+            throw new NullPointerException();
+        new ForEachTransformedEntryTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             transformer, action).invoke();
+    }
+
+    /**
+     * Returns a non-null result from applying the given search
+     * function on each entry, or null if none.  Upon success,
+     * further element processing is suppressed and the results of
+     * any other parallel invocations of the search function are
+     * ignored.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param searchFunction a function returning a non-null
+     * result on success, else null
+     * @return a non-null result from applying the given search
+     * function on each entry, or null if none
+     * @since 1.8
+     */
+    public <U> U searchEntries(long parallelismThreshold,
+                               Function<Map.Entry<K,V>, ? extends U> searchFunction) {
+        if (searchFunction == null) throw new NullPointerException();
+        return new SearchEntriesTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             searchFunction, new AtomicReference<U>()).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating all entries using the
+     * given reducer to combine values, or null if none.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating all entries
+     * @since 1.8
+     */
+    public Map.Entry<K,V> reduceEntries(long parallelismThreshold,
+                                        BiFunction<Map.Entry<K,V>, Map.Entry<K,V>, ? extends Map.Entry<K,V>> reducer) {
+        if (reducer == null) throw new NullPointerException();
+        return new ReduceEntriesTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all entries using the given reducer to combine values,
+     * or null if none.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element, or null if there is no transformation (in
+     * which case it is not combined)
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all entries
+     * @since 1.8
+     */
+    public <U> U reduceEntries(long parallelismThreshold,
+                               Function<Map.Entry<K,V>, ? extends U> transformer,
+                               BiFunction<? super U, ? super U, ? extends U> reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceEntriesTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all entries using the given reducer to combine values,
+     * and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all entries
+     * @since 1.8
+     */
+    public double reduceEntriesToDouble(long parallelismThreshold,
+                                        ToDoubleFunction<Map.Entry<K,V>> transformer,
+                                        double basis,
+                                        DoubleBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceEntriesToDoubleTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all entries using the given reducer to combine values,
+     * and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all entries
+     * @since 1.8
+     */
+    public long reduceEntriesToLong(long parallelismThreshold,
+                                    ToLongFunction<Map.Entry<K,V>> transformer,
+                                    long basis,
+                                    LongBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceEntriesToLongTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all entries using the given reducer to combine values,
+     * and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all entries
+     * @since 1.8
+     */
+    public int reduceEntriesToInt(long parallelismThreshold,
+                                  ToIntFunction<Map.Entry<K,V>> transformer,
+                                  int basis,
+                                  IntBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceEntriesToIntTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+
+    /* ----------------Views -------------- */
+
+    /**
+     * Base class for views.
+     */
+    abstract static class CollectionView<K,V,E>
+        implements Collection<E>, java.io.Serializable {
+        private static final long serialVersionUID = 7249069246763182397L;
+        final ConcurrentHashMap<K,V> map;
+        CollectionView(ConcurrentHashMap<K,V> map)  { this.map = map; }
+
+        /**
+         * Returns the map backing this view.
+         *
+         * @return the map backing this view
+         */
+        public ConcurrentHashMap<K,V> getMap() { return map; }
+
+        /**
+         * Removes all of the elements from this view, by removing all
+         * the mappings from the map backing this view.
+         */
+        public final void clear()      { map.clear(); }
+        public final int size()        { return map.size(); }
+        public final boolean isEmpty() { return map.isEmpty(); }
+
+        // implementations below rely on concrete classes supplying these
+        // abstract methods
+        /**
+         * Returns a "weakly consistent" iterator that will never
+         * throw {@link ConcurrentModificationException}, and
+         * guarantees to traverse elements as they existed upon
+         * construction of the iterator, and may (but is not
+         * guaranteed to) reflect any modifications subsequent to
+         * construction.
+         */
+        public abstract Iterator<E> iterator();
+        public abstract boolean contains(Object o);
+        public abstract boolean remove(Object o);
+
+        private static final String oomeMsg = "Required array size too large";
+
+        public final Object[] toArray() {
+            long sz = map.mappingCount();
+            if (sz > MAX_ARRAY_SIZE)
+                throw new OutOfMemoryError(oomeMsg);
+            int n = (int)sz;
+            Object[] r = new Object[n];
+            int i = 0;
+            for (E e : this) {
+                if (i == n) {
+                    if (n >= MAX_ARRAY_SIZE)
+                        throw new OutOfMemoryError(oomeMsg);
+                    if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1)
+                        n = MAX_ARRAY_SIZE;
+                    else
+                        n += (n >>> 1) + 1;
+                    r = Arrays.copyOf(r, n);
+                }
+                r[i++] = e;
+            }
+            return (i == n) ? r : Arrays.copyOf(r, i);
+        }
+
+        public final <T> T[] toArray(T[] a) {
+            long sz = map.mappingCount();
+            if (sz > MAX_ARRAY_SIZE)
+                throw new OutOfMemoryError(oomeMsg);
+            int m = (int)sz;
+            T[] r = (a.length >= m) ? a :
+                (T[])java.lang.reflect.Array
+                .newInstance(a.getClass().getComponentType(), m);
+            int n = r.length;
+            int i = 0;
+            for (E e : this) {
+                if (i == n) {
+                    if (n >= MAX_ARRAY_SIZE)
+                        throw new OutOfMemoryError(oomeMsg);
+                    if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1)
+                        n = MAX_ARRAY_SIZE;
+                    else
+                        n += (n >>> 1) + 1;
+                    r = Arrays.copyOf(r, n);
+                }
+                r[i++] = (T)e;
+            }
+            if (a == r && i < n) {
+                r[i] = null; // null-terminate
+                return r;
+            }
+            return (i == n) ? r : Arrays.copyOf(r, i);
+        }
+
+        /**
+         * Returns a string representation of this collection.
+         * The string representation consists of the string representations
+         * of the collection's elements in the order they are returned by
+         * its iterator, enclosed in square brackets ({@code "[]"}).
+         * Adjacent elements are separated by the characters {@code ", "}
+         * (comma and space).  Elements are converted to strings as by
+         * {@link String#valueOf(Object)}.
+         *
+         * @return a string representation of this collection
+         */
+        public final String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append('[');
+            Iterator<E> it = iterator();
+            if (it.hasNext()) {
+                for (;;) {
+                    Object e = it.next();
+                    sb.append(e == this ? "(this Collection)" : e);
+                    if (!it.hasNext())
+                        break;
+                    sb.append(',').append(' ');
+                }
+            }
+            return sb.append(']').toString();
+        }
+
+        public final boolean containsAll(Collection<?> c) {
+            if (c != this) {
+                for (Object e : c) {
+                    if (e == null || !contains(e))
+                        return false;
+                }
+            }
+            return true;
+        }
+
+        public final boolean removeAll(Collection<?> c) {
+            boolean modified = false;
+            for (Iterator<E> it = iterator(); it.hasNext();) {
+                if (c.contains(it.next())) {
+                    it.remove();
+                    modified = true;
+                }
+            }
+            return modified;
+        }
+
+        public final boolean retainAll(Collection<?> c) {
+            boolean modified = false;
+            for (Iterator<E> it = iterator(); it.hasNext();) {
+                if (!c.contains(it.next())) {
+                    it.remove();
+                    modified = true;
+                }
+            }
+            return modified;
+        }
+
+    }
+
+    /**
+     * A view of a ConcurrentHashMap as a {@link Set} of keys, in
+     * which additions may optionally be enabled by mapping to a
+     * common value.  This class cannot be directly instantiated.
+     * See {@link #keySet() keySet()},
+     * {@link #keySet(Object) keySet(V)},
+     * {@link #newKeySet() newKeySet()},
+     * {@link #newKeySet(int) newKeySet(int)}.
+     * @since 1.8
+     */
+    public static class KeySetView<K,V> extends CollectionView<K,V,K>
+        implements Set<K>, java.io.Serializable {
+        private static final long serialVersionUID = 7249069246763182397L;
+        private final V value;
+        KeySetView(ConcurrentHashMap<K,V> map, V value) {  // non-public
+            super(map);
+            this.value = value;
+        }
+
+        /**
+         * Returns the default mapped value for additions,
+         * or {@code null} if additions are not supported.
+         *
+         * @return the default mapped value for additions, or {@code null}
+         * if not supported
+         */
+        public V getMappedValue() { return value; }
+
+        /**
+         * {@inheritDoc}
+         * @throws NullPointerException if the specified key is null
+         */
+        public boolean contains(Object o) { return map.containsKey(o); }
+
+        /**
+         * Removes the key from this map view, by removing the key (and its
+         * corresponding value) from the backing map.  This method does
+         * nothing if the key is not in the map.
+         *
+         * @param  o the key to be removed from the backing map
+         * @return {@code true} if the backing map contained the specified key
+         * @throws NullPointerException if the specified key is null
+         */
+        public boolean remove(Object o) { return map.remove(o) != null; }
+
+        /**
+         * @return an iterator over the keys of the backing map
+         */
+        public Iterator<K> iterator() {
+            Node<K,V>[] t;
+            ConcurrentHashMap<K,V> m = map;
+            int f = (t = m.table) == null ? 0 : t.length;
+            return new KeyIterator<K,V>(t, f, 0, f, m);
+        }
+
+        /**
+         * Adds the specified key to this set view by mapping the key to
+         * the default mapped value in the backing map, if defined.
+         *
+         * @param e key to be added
+         * @return {@code true} if this set changed as a result of the call
+         * @throws NullPointerException if the specified key is null
+         * @throws UnsupportedOperationException if no default mapped value
+         * for additions was provided
+         */
+        public boolean add(K e) {
+            V v;
+            if ((v = value) == null)
+                throw new UnsupportedOperationException();
+            return map.internalPut(e, v, true) == null;
+        }
+
+        /**
+         * Adds all of the elements in the specified collection to this set,
+         * as if by calling {@link #add} on each one.
+         *
+         * @param c the elements to be inserted into this set
+         * @return {@code true} if this set changed as a result of the call
+         * @throws NullPointerException if the collection or any of its
+         * elements are {@code null}
+         * @throws UnsupportedOperationException if no default mapped value
+         * for additions was provided
+         */
+        public boolean addAll(Collection<? extends K> c) {
+            boolean added = false;
+            V v;
+            if ((v = value) == null)
+                throw new UnsupportedOperationException();
+            for (K e : c) {
+                if (map.internalPut(e, v, true) == null)
+                    added = true;
+            }
+            return added;
+        }
+
+        public int hashCode() {
+            int h = 0;
+            for (K e : this)
+                h += e.hashCode();
+            return h;
+        }
+
+        public boolean equals(Object o) {
+            Set<?> c;
+            return ((o instanceof Set) &&
+                    ((c = (Set<?>)o) == this ||
+                     (containsAll(c) && c.containsAll(this))));
+        }
+
+        public Spliterator<K> spliterator() {
+            Node<K,V>[] t;
+            ConcurrentHashMap<K,V> m = map;
+            long n = m.sumCount();
+            int f = (t = m.table) == null ? 0 : t.length;
+            return new KeySpliterator<K,V>(t, f, 0, f, n < 0L ? 0L : n);
+        }
+
+        public void forEach(Consumer<? super K> action) {
+            if (action == null) throw new NullPointerException();
+            Node<K,V>[] t;
+            if ((t = map.table) != null) {
+                Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+                for (Node<K,V> p; (p = it.advance()) != null; )
+                    action.accept((K)p.key);
+            }
+        }
+    }
+
+    /**
+     * A view of a ConcurrentHashMap as a {@link Collection} of
+     * values, in which additions are disabled. This class cannot be
+     * directly instantiated. See {@link #values()}.
+     */
+    static final class ValuesView<K,V> extends CollectionView<K,V,V>
+        implements Collection<V>, java.io.Serializable {
+        private static final long serialVersionUID = 2249069246763182397L;
+        ValuesView(ConcurrentHashMap<K,V> map) { super(map); }
+        public final boolean contains(Object o) {
+            return map.containsValue(o);
+        }
+
+        public final boolean remove(Object o) {
+            if (o != null) {
+                for (Iterator<V> it = iterator(); it.hasNext();) {
+                    if (o.equals(it.next())) {
+                        it.remove();
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+
+        public final Iterator<V> iterator() {
+            ConcurrentHashMap<K,V> m = map;
+            Node<K,V>[] t;
+            int f = (t = m.table) == null ? 0 : t.length;
+            return new ValueIterator<K,V>(t, f, 0, f, m);
+        }
+
+        public final boolean add(V e) {
+            throw new UnsupportedOperationException();
+        }
+        public final boolean addAll(Collection<? extends V> c) {
+            throw new UnsupportedOperationException();
+        }
+
+        public Spliterator<V> spliterator() {
+            Node<K,V>[] t;
+            ConcurrentHashMap<K,V> m = map;
+            long n = m.sumCount();
+            int f = (t = m.table) == null ? 0 : t.length;
+            return new ValueSpliterator<K,V>(t, f, 0, f, n < 0L ? 0L : n);
+        }
+
+        public void forEach(Consumer<? super V> action) {
+            if (action == null) throw new NullPointerException();
+            Node<K,V>[] t;
+            if ((t = map.table) != null) {
+                Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+                for (Node<K,V> p; (p = it.advance()) != null; )
+                    action.accept(p.val);
+            }
+        }
     }
 
     /**
-     * Reconstitutes the <tt>ConcurrentHashMap</tt> instance from a
-     * stream (i.e., deserializes it).
-     * @param s the stream
+     * A view of a ConcurrentHashMap as a {@link Set} of (key, value)
+     * entries.  This class cannot be directly instantiated. See
+     * {@link #entrySet()}.
+     */
+    static final class EntrySetView<K,V> extends CollectionView<K,V,Map.Entry<K,V>>
+        implements Set<Map.Entry<K,V>>, java.io.Serializable {
+        private static final long serialVersionUID = 2249069246763182397L;
+        EntrySetView(ConcurrentHashMap<K,V> map) { super(map); }
+
+        public boolean contains(Object o) {
+            Object k, v, r; Map.Entry<?,?> e;
+            return ((o instanceof Map.Entry) &&
+                    (k = (e = (Map.Entry<?,?>)o).getKey()) != null &&
+                    (r = map.get(k)) != null &&
+                    (v = e.getValue()) != null &&
+                    (v == r || v.equals(r)));
+        }
+
+        public boolean remove(Object o) {
+            Object k, v; Map.Entry<?,?> e;
+            return ((o instanceof Map.Entry) &&
+                    (k = (e = (Map.Entry<?,?>)o).getKey()) != null &&
+                    (v = e.getValue()) != null &&
+                    map.remove(k, v));
+        }
+
+        /**
+         * @return an iterator over the entries of the backing map
+         */
+        public Iterator<Map.Entry<K,V>> iterator() {
+            ConcurrentHashMap<K,V> m = map;
+            Node<K,V>[] t;
+            int f = (t = m.table) == null ? 0 : t.length;
+            return new EntryIterator<K,V>(t, f, 0, f, m);
+        }
+
+        public boolean add(Entry<K,V> e) {
+            return map.internalPut(e.getKey(), e.getValue(), false) == null;
+        }
+
+        public boolean addAll(Collection<? extends Entry<K,V>> c) {
+            boolean added = false;
+            for (Entry<K,V> e : c) {
+                if (add(e))
+                    added = true;
+            }
+            return added;
+        }
+
+        public final int hashCode() {
+            int h = 0;
+            Node<K,V>[] t;
+            if ((t = map.table) != null) {
+                Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+                for (Node<K,V> p; (p = it.advance()) != null; ) {
+                    h += p.hashCode();
+                }
+            }
+            return h;
+        }
+
+        public final boolean equals(Object o) {
+            Set<?> c;
+            return ((o instanceof Set) &&
+                    ((c = (Set<?>)o) == this ||
+                     (containsAll(c) && c.containsAll(this))));
+        }
+
+        public Spliterator<Map.Entry<K,V>> spliterator() {
+            Node<K,V>[] t;
+            ConcurrentHashMap<K,V> m = map;
+            long n = m.sumCount();
+            int f = (t = m.table) == null ? 0 : t.length;
+            return new EntrySpliterator<K,V>(t, f, 0, f, n < 0L ? 0L : n, m);
+        }
+
+        public void forEach(Consumer<? super Map.Entry<K,V>> action) {
+            if (action == null) throw new NullPointerException();
+            Node<K,V>[] t;
+            if ((t = map.table) != null) {
+                Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+                for (Node<K,V> p; (p = it.advance()) != null; )
+                    action.accept(new MapEntry<K,V>((K)p.key, p.val, map));
+            }
+        }
+
+    }
+
+    // -------------------------------------------------------
+
+    /**
+     * Base class for bulk tasks. Repeats some fields and code from
+     * class Traverser, because we need to subclass CountedCompleter.
+     */
+    abstract static class BulkTask<K,V,R> extends CountedCompleter<R> {
+        Node<K,V>[] tab;        // same as Traverser
+        Node<K,V> next;
+        int index;
+        int baseIndex;
+        int baseLimit;
+        final int baseSize;
+        int batch;              // split control
+
+        BulkTask(BulkTask<K,V,?> par, int b, int i, int f, Node<K,V>[] t) {
+            super(par);
+            this.batch = b;
+            this.index = this.baseIndex = i;
+            if ((this.tab = t) == null)
+                this.baseSize = this.baseLimit = 0;
+            else if (par == null)
+                this.baseSize = this.baseLimit = t.length;
+            else {
+                this.baseLimit = f;
+                this.baseSize = par.baseSize;
+            }
+        }
+
+        /**
+         * Same as Traverser version
+         */
+        final Node<K,V> advance() {
+            Node<K,V> e;
+            if ((e = next) != null)
+                e = e.next;
+            for (;;) {
+                Node<K,V>[] t; int i, n; Object ek;
+                if (e != null)
+                    return next = e;
+                if (baseIndex >= baseLimit || (t = tab) == null ||
+                    (n = t.length) <= (i = index) || i < 0)
+                    return next = null;
+                if ((e = tabAt(t, index)) != null && e.hash < 0) {
+                    if ((ek = e.key) instanceof TreeBin)
+                        e = ((TreeBin<K,V>)ek).first;
+                    else {
+                        tab = (Node<K,V>[])ek;
+                        e = null;
+                        continue;
+                    }
+                }
+                if ((index += baseSize) >= n)
+                    index = ++baseIndex;
+            }
+        }
+    }
+
+    /*
+     * Task classes. Coded in a regular but ugly format/style to
+     * simplify checks that each variant differs in the right way from
+     * others. The null screenings exist because compilers cannot tell
+     * that we've already null-checked task arguments, so we force
+     * simplest hoisted bypass to help avoid convoluted traps.
      */
-    @SuppressWarnings("unchecked")
-    private void readObject(java.io.ObjectInputStream s)
-            throws java.io.IOException, ClassNotFoundException {
-        // Don't call defaultReadObject()
-        ObjectInputStream.GetField oisFields = s.readFields();
-        final Segment<K,V>[] oisSegments = (Segment<K,V>[])oisFields.get("segments", null);
-
-        final int ssize = oisSegments.length;
-        if (ssize < 1 || ssize > MAX_SEGMENTS
-            || (ssize & (ssize-1)) != 0 )  // ssize not power of two
-            throw new java.io.InvalidObjectException("Bad number of segments:"
-                                                     + ssize);
-        int sshift = 0, ssizeTmp = ssize;
-        while (ssizeTmp > 1) {
-            ++sshift;
-            ssizeTmp >>>= 1;
+
+    static final class ForEachKeyTask<K,V>
+        extends BulkTask<K,V,Void> {
+        final Consumer<? super K> action;
+        ForEachKeyTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Consumer<? super K> action) {
+            super(p, b, i, f, t);
+            this.action = action;
+        }
+        public final void compute() {
+            final Consumer<? super K> action;
+            if ((action = this.action) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    new ForEachKeyTask<K,V>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         action).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null;)
+                    action.accept((K)p.key);
+                propagateCompletion();
+            }
+        }
+    }
+
+    static final class ForEachValueTask<K,V>
+        extends BulkTask<K,V,Void> {
+        final Consumer<? super V> action;
+        ForEachValueTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Consumer<? super V> action) {
+            super(p, b, i, f, t);
+            this.action = action;
+        }
+        public final void compute() {
+            final Consumer<? super V> action;
+            if ((action = this.action) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    new ForEachValueTask<K,V>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         action).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null;)
+                    action.accept(p.val);
+                propagateCompletion();
+            }
+        }
+    }
+
+    static final class ForEachEntryTask<K,V>
+        extends BulkTask<K,V,Void> {
+        final Consumer<? super Entry<K,V>> action;
+        ForEachEntryTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Consumer<? super Entry<K,V>> action) {
+            super(p, b, i, f, t);
+            this.action = action;
+        }
+        public final void compute() {
+            final Consumer<? super Entry<K,V>> action;
+            if ((action = this.action) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    new ForEachEntryTask<K,V>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         action).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    action.accept(p);
+                propagateCompletion();
+            }
+        }
+    }
+
+    static final class ForEachMappingTask<K,V>
+        extends BulkTask<K,V,Void> {
+        final BiConsumer<? super K, ? super V> action;
+        ForEachMappingTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             BiConsumer<? super K,? super V> action) {
+            super(p, b, i, f, t);
+            this.action = action;
+        }
+        public final void compute() {
+            final BiConsumer<? super K, ? super V> action;
+            if ((action = this.action) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    new ForEachMappingTask<K,V>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         action).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    action.accept((K)p.key, p.val);
+                propagateCompletion();
+            }
+        }
+    }
+
+    static final class ForEachTransformedKeyTask<K,V,U>
+        extends BulkTask<K,V,Void> {
+        final Function<? super K, ? extends U> transformer;
+        final Consumer<? super U> action;
+        ForEachTransformedKeyTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Function<? super K, ? extends U> transformer, Consumer<? super U> action) {
+            super(p, b, i, f, t);
+            this.transformer = transformer; this.action = action;
+        }
+        public final void compute() {
+            final Function<? super K, ? extends U> transformer;
+            final Consumer<? super U> action;
+            if ((transformer = this.transformer) != null &&
+                (action = this.action) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    new ForEachTransformedKeyTask<K,V,U>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         transformer, action).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    U u;
+                    if ((u = transformer.apply((K)p.key)) != null)
+                        action.accept(u);
+                }
+                propagateCompletion();
+            }
+        }
+    }
+
+    static final class ForEachTransformedValueTask<K,V,U>
+        extends BulkTask<K,V,Void> {
+        final Function<? super V, ? extends U> transformer;
+        final Consumer<? super U> action;
+        ForEachTransformedValueTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Function<? super V, ? extends U> transformer, Consumer<? super U> action) {
+            super(p, b, i, f, t);
+            this.transformer = transformer; this.action = action;
+        }
+        public final void compute() {
+            final Function<? super V, ? extends U> transformer;
+            final Consumer<? super U> action;
+            if ((transformer = this.transformer) != null &&
+                (action = this.action) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    new ForEachTransformedValueTask<K,V,U>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         transformer, action).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    U u;
+                    if ((u = transformer.apply(p.val)) != null)
+                        action.accept(u);
+                }
+                propagateCompletion();
+            }
+        }
+    }
+
+    static final class ForEachTransformedEntryTask<K,V,U>
+        extends BulkTask<K,V,Void> {
+        final Function<Map.Entry<K,V>, ? extends U> transformer;
+        final Consumer<? super U> action;
+        ForEachTransformedEntryTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Function<Map.Entry<K,V>, ? extends U> transformer, Consumer<? super U> action) {
+            super(p, b, i, f, t);
+            this.transformer = transformer; this.action = action;
+        }
+        public final void compute() {
+            final Function<Map.Entry<K,V>, ? extends U> transformer;
+            final Consumer<? super U> action;
+            if ((transformer = this.transformer) != null &&
+                (action = this.action) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    new ForEachTransformedEntryTask<K,V,U>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         transformer, action).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    U u;
+                    if ((u = transformer.apply(p)) != null)
+                        action.accept(u);
+                }
+                propagateCompletion();
+            }
+        }
+    }
+
+    static final class ForEachTransformedMappingTask<K,V,U>
+        extends BulkTask<K,V,Void> {
+        final BiFunction<? super K, ? super V, ? extends U> transformer;
+        final Consumer<? super U> action;
+        ForEachTransformedMappingTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             BiFunction<? super K, ? super V, ? extends U> transformer,
+             Consumer<? super U> action) {
+            super(p, b, i, f, t);
+            this.transformer = transformer; this.action = action;
+        }
+        public final void compute() {
+            final BiFunction<? super K, ? super V, ? extends U> transformer;
+            final Consumer<? super U> action;
+            if ((transformer = this.transformer) != null &&
+                (action = this.action) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    new ForEachTransformedMappingTask<K,V,U>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         transformer, action).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    U u;
+                    if ((u = transformer.apply((K)p.key, p.val)) != null)
+                        action.accept(u);
+                }
+                propagateCompletion();
+            }
+        }
+    }
+
+    static final class SearchKeysTask<K,V,U>
+        extends BulkTask<K,V,U> {
+        final Function<? super K, ? extends U> searchFunction;
+        final AtomicReference<U> result;
+        SearchKeysTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Function<? super K, ? extends U> searchFunction,
+             AtomicReference<U> result) {
+            super(p, b, i, f, t);
+            this.searchFunction = searchFunction; this.result = result;
         }
-        UNSAFE.putIntVolatile(this, SEGSHIFT_OFFSET, 32 - sshift);
-        UNSAFE.putIntVolatile(this, SEGMASK_OFFSET, ssize - 1);
-        UNSAFE.putObjectVolatile(this, SEGMENTS_OFFSET, oisSegments);
-
-        // set hashMask
-        UNSAFE.putIntVolatile(this, HASHSEED_OFFSET,
-                 sun.misc.Hashing.randomHashSeed(this));
-
-        // Re-initialize segments to be minimally sized, and let grow.
-        int cap = MIN_SEGMENT_TABLE_CAPACITY;
-        final Segment<K,V>[] segments = this.segments;
-        for (int k = 0; k < segments.length; ++k) {
-            Segment<K,V> seg = segments[k];
-            if (seg != null) {
-                seg.threshold = (int)(cap * seg.loadFactor);
-                seg.table = (HashEntry<K,V>[]) new HashEntry<?,?>[cap];
+        public final U getRawResult() { return result.get(); }
+        public final void compute() {
+            final Function<? super K, ? extends U> searchFunction;
+            final AtomicReference<U> result;
+            if ((searchFunction = this.searchFunction) != null &&
+                (result = this.result) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    if (result.get() != null)
+                        return;
+                    addToPendingCount(1);
+                    new SearchKeysTask<K,V,U>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         searchFunction, result).fork();
+                }
+                while (result.get() == null) {
+                    U u;
+                    Node<K,V> p;
+                    if ((p = advance()) == null) {
+                        propagateCompletion();
+                        break;
+                    }
+                    if ((u = searchFunction.apply((K)p.key)) != null) {
+                        if (result.compareAndSet(null, u))
+                            quietlyCompleteRoot();
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    static final class SearchValuesTask<K,V,U>
+        extends BulkTask<K,V,U> {
+        final Function<? super V, ? extends U> searchFunction;
+        final AtomicReference<U> result;
+        SearchValuesTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Function<? super V, ? extends U> searchFunction,
+             AtomicReference<U> result) {
+            super(p, b, i, f, t);
+            this.searchFunction = searchFunction; this.result = result;
+        }
+        public final U getRawResult() { return result.get(); }
+        public final void compute() {
+            final Function<? super V, ? extends U> searchFunction;
+            final AtomicReference<U> result;
+            if ((searchFunction = this.searchFunction) != null &&
+                (result = this.result) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    if (result.get() != null)
+                        return;
+                    addToPendingCount(1);
+                    new SearchValuesTask<K,V,U>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         searchFunction, result).fork();
+                }
+                while (result.get() == null) {
+                    U u;
+                    Node<K,V> p;
+                    if ((p = advance()) == null) {
+                        propagateCompletion();
+                        break;
+                    }
+                    if ((u = searchFunction.apply(p.val)) != null) {
+                        if (result.compareAndSet(null, u))
+                            quietlyCompleteRoot();
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    static final class SearchEntriesTask<K,V,U>
+        extends BulkTask<K,V,U> {
+        final Function<Entry<K,V>, ? extends U> searchFunction;
+        final AtomicReference<U> result;
+        SearchEntriesTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Function<Entry<K,V>, ? extends U> searchFunction,
+             AtomicReference<U> result) {
+            super(p, b, i, f, t);
+            this.searchFunction = searchFunction; this.result = result;
+        }
+        public final U getRawResult() { return result.get(); }
+        public final void compute() {
+            final Function<Entry<K,V>, ? extends U> searchFunction;
+            final AtomicReference<U> result;
+            if ((searchFunction = this.searchFunction) != null &&
+                (result = this.result) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    if (result.get() != null)
+                        return;
+                    addToPendingCount(1);
+                    new SearchEntriesTask<K,V,U>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         searchFunction, result).fork();
+                }
+                while (result.get() == null) {
+                    U u;
+                    Node<K,V> p;
+                    if ((p = advance()) == null) {
+                        propagateCompletion();
+                        break;
+                    }
+                    if ((u = searchFunction.apply(p)) != null) {
+                        if (result.compareAndSet(null, u))
+                            quietlyCompleteRoot();
+                        return;
+                    }
+                }
+            }
+        }
+    }
+
+    static final class SearchMappingsTask<K,V,U>
+        extends BulkTask<K,V,U> {
+        final BiFunction<? super K, ? super V, ? extends U> searchFunction;
+        final AtomicReference<U> result;
+        SearchMappingsTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             BiFunction<? super K, ? super V, ? extends U> searchFunction,
+             AtomicReference<U> result) {
+            super(p, b, i, f, t);
+            this.searchFunction = searchFunction; this.result = result;
+        }
+        public final U getRawResult() { return result.get(); }
+        public final void compute() {
+            final BiFunction<? super K, ? super V, ? extends U> searchFunction;
+            final AtomicReference<U> result;
+            if ((searchFunction = this.searchFunction) != null &&
+                (result = this.result) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    if (result.get() != null)
+                        return;
+                    addToPendingCount(1);
+                    new SearchMappingsTask<K,V,U>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         searchFunction, result).fork();
+                }
+                while (result.get() == null) {
+                    U u;
+                    Node<K,V> p;
+                    if ((p = advance()) == null) {
+                        propagateCompletion();
+                        break;
+                    }
+                    if ((u = searchFunction.apply((K)p.key, p.val)) != null) {
+                        if (result.compareAndSet(null, u))
+                            quietlyCompleteRoot();
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    static final class ReduceKeysTask<K,V>
+        extends BulkTask<K,V,K> {
+        final BiFunction<? super K, ? super K, ? extends K> reducer;
+        K result;
+        ReduceKeysTask<K,V> rights, nextRight;
+        ReduceKeysTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             ReduceKeysTask<K,V> nextRight,
+             BiFunction<? super K, ? super K, ? extends K> reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.reducer = reducer;
+        }
+        public final K getRawResult() { return result; }
+        public final void compute() {
+            final BiFunction<? super K, ? super K, ? extends K> reducer;
+            if ((reducer = this.reducer) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new ReduceKeysTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, reducer)).fork();
+                }
+                K r = null;
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    K u = (K)p.key;
+                    r = (r == null) ? u : u == null ? r : reducer.apply(r, u);
+                }
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    ReduceKeysTask<K,V>
+                        t = (ReduceKeysTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        K tr, sr;
+                        if ((sr = s.result) != null)
+                            t.result = (((tr = t.result) == null) ? sr :
+                                        reducer.apply(tr, sr));
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    static final class ReduceValuesTask<K,V>
+        extends BulkTask<K,V,V> {
+        final BiFunction<? super V, ? super V, ? extends V> reducer;
+        V result;
+        ReduceValuesTask<K,V> rights, nextRight;
+        ReduceValuesTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             ReduceValuesTask<K,V> nextRight,
+             BiFunction<? super V, ? super V, ? extends V> reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.reducer = reducer;
+        }
+        public final V getRawResult() { return result; }
+        public final void compute() {
+            final BiFunction<? super V, ? super V, ? extends V> reducer;
+            if ((reducer = this.reducer) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new ReduceValuesTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, reducer)).fork();
+                }
+                V r = null;
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    V v = p.val;
+                    r = (r == null) ? v : reducer.apply(r, v);
+                }
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    ReduceValuesTask<K,V>
+                        t = (ReduceValuesTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        V tr, sr;
+                        if ((sr = s.result) != null)
+                            t.result = (((tr = t.result) == null) ? sr :
+                                        reducer.apply(tr, sr));
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    static final class ReduceEntriesTask<K,V>
+        extends BulkTask<K,V,Map.Entry<K,V>> {
+        final BiFunction<Map.Entry<K,V>, Map.Entry<K,V>, ? extends Map.Entry<K,V>> reducer;
+        Map.Entry<K,V> result;
+        ReduceEntriesTask<K,V> rights, nextRight;
+        ReduceEntriesTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             ReduceEntriesTask<K,V> nextRight,
+             BiFunction<Entry<K,V>, Map.Entry<K,V>, ? extends Map.Entry<K,V>> reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.reducer = reducer;
+        }
+        public final Map.Entry<K,V> getRawResult() { return result; }
+        public final void compute() {
+            final BiFunction<Map.Entry<K,V>, Map.Entry<K,V>, ? extends Map.Entry<K,V>> reducer;
+            if ((reducer = this.reducer) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new ReduceEntriesTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, reducer)).fork();
+                }
+                Map.Entry<K,V> r = null;
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = (r == null) ? p : reducer.apply(r, p);
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    ReduceEntriesTask<K,V>
+                        t = (ReduceEntriesTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        Map.Entry<K,V> tr, sr;
+                        if ((sr = s.result) != null)
+                            t.result = (((tr = t.result) == null) ? sr :
+                                        reducer.apply(tr, sr));
+                        s = t.rights = s.nextRight;
+                    }
+                }
             }
         }
-
-        // Read the keys and values, and put the mappings in the table
-        for (;;) {
-            K key = (K) s.readObject();
-            V value = (V) s.readObject();
-            if (key == null)
-                break;
-            put(key, value);
+    }
+
+    static final class MapReduceKeysTask<K,V,U>
+        extends BulkTask<K,V,U> {
+        final Function<? super K, ? extends U> transformer;
+        final BiFunction<? super U, ? super U, ? extends U> reducer;
+        U result;
+        MapReduceKeysTask<K,V,U> rights, nextRight;
+        MapReduceKeysTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceKeysTask<K,V,U> nextRight,
+             Function<? super K, ? extends U> transformer,
+             BiFunction<? super U, ? super U, ? extends U> reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.reducer = reducer;
+        }
+        public final U getRawResult() { return result; }
+        public final void compute() {
+            final Function<? super K, ? extends U> transformer;
+            final BiFunction<? super U, ? super U, ? extends U> reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceKeysTask<K,V,U>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, reducer)).fork();
+                }
+                U r = null;
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    U u;
+                    if ((u = transformer.apply((K)p.key)) != null)
+                        r = (r == null) ? u : reducer.apply(r, u);
+                }
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    MapReduceKeysTask<K,V,U>
+                        t = (MapReduceKeysTask<K,V,U>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        U tr, sr;
+                        if ((sr = s.result) != null)
+                            t.result = (((tr = t.result) == null) ? sr :
+                                        reducer.apply(tr, sr));
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    static final class MapReduceValuesTask<K,V,U>
+        extends BulkTask<K,V,U> {
+        final Function<? super V, ? extends U> transformer;
+        final BiFunction<? super U, ? super U, ? extends U> reducer;
+        U result;
+        MapReduceValuesTask<K,V,U> rights, nextRight;
+        MapReduceValuesTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceValuesTask<K,V,U> nextRight,
+             Function<? super V, ? extends U> transformer,
+             BiFunction<? super U, ? super U, ? extends U> reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.reducer = reducer;
+        }
+        public final U getRawResult() { return result; }
+        public final void compute() {
+            final Function<? super V, ? extends U> transformer;
+            final BiFunction<? super U, ? super U, ? extends U> reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceValuesTask<K,V,U>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, reducer)).fork();
+                }
+                U r = null;
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    U u;
+                    if ((u = transformer.apply(p.val)) != null)
+                        r = (r == null) ? u : reducer.apply(r, u);
+                }
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    MapReduceValuesTask<K,V,U>
+                        t = (MapReduceValuesTask<K,V,U>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        U tr, sr;
+                        if ((sr = s.result) != null)
+                            t.result = (((tr = t.result) == null) ? sr :
+                                        reducer.apply(tr, sr));
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    static final class MapReduceEntriesTask<K,V,U>
+        extends BulkTask<K,V,U> {
+        final Function<Map.Entry<K,V>, ? extends U> transformer;
+        final BiFunction<? super U, ? super U, ? extends U> reducer;
+        U result;
+        MapReduceEntriesTask<K,V,U> rights, nextRight;
+        MapReduceEntriesTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceEntriesTask<K,V,U> nextRight,
+             Function<Map.Entry<K,V>, ? extends U> transformer,
+             BiFunction<? super U, ? super U, ? extends U> reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.reducer = reducer;
+        }
+        public final U getRawResult() { return result; }
+        public final void compute() {
+            final Function<Map.Entry<K,V>, ? extends U> transformer;
+            final BiFunction<? super U, ? super U, ? extends U> reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceEntriesTask<K,V,U>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, reducer)).fork();
+                }
+                U r = null;
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    U u;
+                    if ((u = transformer.apply(p)) != null)
+                        r = (r == null) ? u : reducer.apply(r, u);
+                }
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    MapReduceEntriesTask<K,V,U>
+                        t = (MapReduceEntriesTask<K,V,U>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        U tr, sr;
+                        if ((sr = s.result) != null)
+                            t.result = (((tr = t.result) == null) ? sr :
+                                        reducer.apply(tr, sr));
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    static final class MapReduceMappingsTask<K,V,U>
+        extends BulkTask<K,V,U> {
+        final BiFunction<? super K, ? super V, ? extends U> transformer;
+        final BiFunction<? super U, ? super U, ? extends U> reducer;
+        U result;
+        MapReduceMappingsTask<K,V,U> rights, nextRight;
+        MapReduceMappingsTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceMappingsTask<K,V,U> nextRight,
+             BiFunction<? super K, ? super V, ? extends U> transformer,
+             BiFunction<? super U, ? super U, ? extends U> reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.reducer = reducer;
+        }
+        public final U getRawResult() { return result; }
+        public final void compute() {
+            final BiFunction<? super K, ? super V, ? extends U> transformer;
+            final BiFunction<? super U, ? super U, ? extends U> reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceMappingsTask<K,V,U>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, reducer)).fork();
+                }
+                U r = null;
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    U u;
+                    if ((u = transformer.apply((K)p.key, p.val)) != null)
+                        r = (r == null) ? u : reducer.apply(r, u);
+                }
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    MapReduceMappingsTask<K,V,U>
+                        t = (MapReduceMappingsTask<K,V,U>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        U tr, sr;
+                        if ((sr = s.result) != null)
+                            t.result = (((tr = t.result) == null) ? sr :
+                                        reducer.apply(tr, sr));
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    static final class MapReduceKeysToDoubleTask<K,V>
+        extends BulkTask<K,V,Double> {
+        final ToDoubleFunction<? super K> transformer;
+        final DoubleBinaryOperator reducer;
+        final double basis;
+        double result;
+        MapReduceKeysToDoubleTask<K,V> rights, nextRight;
+        MapReduceKeysToDoubleTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceKeysToDoubleTask<K,V> nextRight,
+             ToDoubleFunction<? super K> transformer,
+             double basis,
+             DoubleBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Double getRawResult() { return result; }
+        public final void compute() {
+            final ToDoubleFunction<? super K> transformer;
+            final DoubleBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                double r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceKeysToDoubleTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsDouble(r, transformer.applyAsDouble((K)p.key));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    MapReduceKeysToDoubleTask<K,V>
+                        t = (MapReduceKeysToDoubleTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsDouble(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    static final class MapReduceValuesToDoubleTask<K,V>
+        extends BulkTask<K,V,Double> {
+        final ToDoubleFunction<? super V> transformer;
+        final DoubleBinaryOperator reducer;
+        final double basis;
+        double result;
+        MapReduceValuesToDoubleTask<K,V> rights, nextRight;
+        MapReduceValuesToDoubleTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceValuesToDoubleTask<K,V> nextRight,
+             ToDoubleFunction<? super V> transformer,
+             double basis,
+             DoubleBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Double getRawResult() { return result; }
+        public final void compute() {
+            final ToDoubleFunction<? super V> transformer;
+            final DoubleBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                double r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceValuesToDoubleTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsDouble(r, transformer.applyAsDouble(p.val));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    MapReduceValuesToDoubleTask<K,V>
+                        t = (MapReduceValuesToDoubleTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsDouble(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    static final class MapReduceEntriesToDoubleTask<K,V>
+        extends BulkTask<K,V,Double> {
+        final ToDoubleFunction<Map.Entry<K,V>> transformer;
+        final DoubleBinaryOperator reducer;
+        final double basis;
+        double result;
+        MapReduceEntriesToDoubleTask<K,V> rights, nextRight;
+        MapReduceEntriesToDoubleTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceEntriesToDoubleTask<K,V> nextRight,
+             ToDoubleFunction<Map.Entry<K,V>> transformer,
+             double basis,
+             DoubleBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Double getRawResult() { return result; }
+        public final void compute() {
+            final ToDoubleFunction<Map.Entry<K,V>> transformer;
+            final DoubleBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                double r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceEntriesToDoubleTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsDouble(r, transformer.applyAsDouble(p));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    MapReduceEntriesToDoubleTask<K,V>
+                        t = (MapReduceEntriesToDoubleTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsDouble(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    static final class MapReduceMappingsToDoubleTask<K,V>
+        extends BulkTask<K,V,Double> {
+        final ToDoubleBiFunction<? super K, ? super V> transformer;
+        final DoubleBinaryOperator reducer;
+        final double basis;
+        double result;
+        MapReduceMappingsToDoubleTask<K,V> rights, nextRight;
+        MapReduceMappingsToDoubleTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceMappingsToDoubleTask<K,V> nextRight,
+             ToDoubleBiFunction<? super K, ? super V> transformer,
+             double basis,
+             DoubleBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Double getRawResult() { return result; }
+        public final void compute() {
+            final ToDoubleBiFunction<? super K, ? super V> transformer;
+            final DoubleBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                double r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceMappingsToDoubleTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsDouble(r, transformer.applyAsDouble((K)p.key, p.val));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    MapReduceMappingsToDoubleTask<K,V>
+                        t = (MapReduceMappingsToDoubleTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsDouble(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    static final class MapReduceKeysToLongTask<K,V>
+        extends BulkTask<K,V,Long> {
+        final ToLongFunction<? super K> transformer;
+        final LongBinaryOperator reducer;
+        final long basis;
+        long result;
+        MapReduceKeysToLongTask<K,V> rights, nextRight;
+        MapReduceKeysToLongTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceKeysToLongTask<K,V> nextRight,
+             ToLongFunction<? super K> transformer,
+             long basis,
+             LongBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Long getRawResult() { return result; }
+        public final void compute() {
+            final ToLongFunction<? super K> transformer;
+            final LongBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                long r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceKeysToLongTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsLong(r, transformer.applyAsLong((K)p.key));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    MapReduceKeysToLongTask<K,V>
+                        t = (MapReduceKeysToLongTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsLong(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    static final class MapReduceValuesToLongTask<K,V>
+        extends BulkTask<K,V,Long> {
+        final ToLongFunction<? super V> transformer;
+        final LongBinaryOperator reducer;
+        final long basis;
+        long result;
+        MapReduceValuesToLongTask<K,V> rights, nextRight;
+        MapReduceValuesToLongTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceValuesToLongTask<K,V> nextRight,
+             ToLongFunction<? super V> transformer,
+             long basis,
+             LongBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Long getRawResult() { return result; }
+        public final void compute() {
+            final ToLongFunction<? super V> transformer;
+            final LongBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                long r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceValuesToLongTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsLong(r, transformer.applyAsLong(p.val));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    MapReduceValuesToLongTask<K,V>
+                        t = (MapReduceValuesToLongTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsLong(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    static final class MapReduceEntriesToLongTask<K,V>
+        extends BulkTask<K,V,Long> {
+        final ToLongFunction<Map.Entry<K,V>> transformer;
+        final LongBinaryOperator reducer;
+        final long basis;
+        long result;
+        MapReduceEntriesToLongTask<K,V> rights, nextRight;
+        MapReduceEntriesToLongTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceEntriesToLongTask<K,V> nextRight,
+             ToLongFunction<Map.Entry<K,V>> transformer,
+             long basis,
+             LongBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Long getRawResult() { return result; }
+        public final void compute() {
+            final ToLongFunction<Map.Entry<K,V>> transformer;
+            final LongBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                long r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceEntriesToLongTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsLong(r, transformer.applyAsLong(p));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    MapReduceEntriesToLongTask<K,V>
+                        t = (MapReduceEntriesToLongTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsLong(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    static final class MapReduceMappingsToLongTask<K,V>
+        extends BulkTask<K,V,Long> {
+        final ToLongBiFunction<? super K, ? super V> transformer;
+        final LongBinaryOperator reducer;
+        final long basis;
+        long result;
+        MapReduceMappingsToLongTask<K,V> rights, nextRight;
+        MapReduceMappingsToLongTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceMappingsToLongTask<K,V> nextRight,
+             ToLongBiFunction<? super K, ? super V> transformer,
+             long basis,
+             LongBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Long getRawResult() { return result; }
+        public final void compute() {
+            final ToLongBiFunction<? super K, ? super V> transformer;
+            final LongBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                long r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceMappingsToLongTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsLong(r, transformer.applyAsLong((K)p.key, p.val));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    MapReduceMappingsToLongTask<K,V>
+                        t = (MapReduceMappingsToLongTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsLong(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    static final class MapReduceKeysToIntTask<K,V>
+        extends BulkTask<K,V,Integer> {
+        final ToIntFunction<? super K> transformer;
+        final IntBinaryOperator reducer;
+        final int basis;
+        int result;
+        MapReduceKeysToIntTask<K,V> rights, nextRight;
+        MapReduceKeysToIntTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceKeysToIntTask<K,V> nextRight,
+             ToIntFunction<? super K> transformer,
+             int basis,
+             IntBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Integer getRawResult() { return result; }
+        public final void compute() {
+            final ToIntFunction<? super K> transformer;
+            final IntBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                int r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceKeysToIntTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsInt(r, transformer.applyAsInt((K)p.key));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    MapReduceKeysToIntTask<K,V>
+                        t = (MapReduceKeysToIntTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsInt(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    static final class MapReduceValuesToIntTask<K,V>
+        extends BulkTask<K,V,Integer> {
+        final ToIntFunction<? super V> transformer;
+        final IntBinaryOperator reducer;
+        final int basis;
+        int result;
+        MapReduceValuesToIntTask<K,V> rights, nextRight;
+        MapReduceValuesToIntTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceValuesToIntTask<K,V> nextRight,
+             ToIntFunction<? super V> transformer,
+             int basis,
+             IntBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Integer getRawResult() { return result; }
+        public final void compute() {
+            final ToIntFunction<? super V> transformer;
+            final IntBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                int r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceValuesToIntTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsInt(r, transformer.applyAsInt(p.val));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    MapReduceValuesToIntTask<K,V>
+                        t = (MapReduceValuesToIntTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsInt(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    static final class MapReduceEntriesToIntTask<K,V>
+        extends BulkTask<K,V,Integer> {
+        final ToIntFunction<Map.Entry<K,V>> transformer;
+        final IntBinaryOperator reducer;
+        final int basis;
+        int result;
+        MapReduceEntriesToIntTask<K,V> rights, nextRight;
+        MapReduceEntriesToIntTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceEntriesToIntTask<K,V> nextRight,
+             ToIntFunction<Map.Entry<K,V>> transformer,
+             int basis,
+             IntBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Integer getRawResult() { return result; }
+        public final void compute() {
+            final ToIntFunction<Map.Entry<K,V>> transformer;
+            final IntBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                int r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceEntriesToIntTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsInt(r, transformer.applyAsInt(p));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    MapReduceEntriesToIntTask<K,V>
+                        t = (MapReduceEntriesToIntTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsInt(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    static final class MapReduceMappingsToIntTask<K,V>
+        extends BulkTask<K,V,Integer> {
+        final ToIntBiFunction<? super K, ? super V> transformer;
+        final IntBinaryOperator reducer;
+        final int basis;
+        int result;
+        MapReduceMappingsToIntTask<K,V> rights, nextRight;
+        MapReduceMappingsToIntTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceMappingsToIntTask<K,V> nextRight,
+             ToIntBiFunction<? super K, ? super V> transformer,
+             int basis,
+             IntBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Integer getRawResult() { return result; }
+        public final void compute() {
+            final ToIntBiFunction<? super K, ? super V> transformer;
+            final IntBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                int r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceMappingsToIntTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsInt(r, transformer.applyAsInt((K)p.key, p.val));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    MapReduceMappingsToIntTask<K,V>
+                        t = (MapReduceMappingsToIntTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsInt(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
         }
     }
 
     // Unsafe mechanics
-    private static final sun.misc.Unsafe UNSAFE;
-    private static final long SBASE;
-    private static final int SSHIFT;
-    private static final long TBASE;
-    private static final int TSHIFT;
-    private static final long HASHSEED_OFFSET;
-    private static final long SEGSHIFT_OFFSET;
-    private static final long SEGMASK_OFFSET;
-    private static final long SEGMENTS_OFFSET;
+    private static final sun.misc.Unsafe U;
+    private static final long SIZECTL;
+    private static final long TRANSFERINDEX;
+    private static final long TRANSFERORIGIN;
+    private static final long BASECOUNT;
+    private static final long CELLSBUSY;
+    private static final long CELLVALUE;
+    private static final long ABASE;
+    private static final int ASHIFT;
 
     static {
-        int ss, ts;
         try {
-            UNSAFE = sun.misc.Unsafe.getUnsafe();
-            Class<?> tc = HashEntry[].class;
-            Class<?> sc = Segment[].class;
-            TBASE = UNSAFE.arrayBaseOffset(tc);
-            SBASE = UNSAFE.arrayBaseOffset(sc);
-            ts = UNSAFE.arrayIndexScale(tc);
-            ss = UNSAFE.arrayIndexScale(sc);
-            HASHSEED_OFFSET = UNSAFE.objectFieldOffset(
-                ConcurrentHashMap.class.getDeclaredField("hashSeed"));
-            SEGSHIFT_OFFSET = UNSAFE.objectFieldOffset(
-                ConcurrentHashMap.class.getDeclaredField("segmentShift"));
-            SEGMASK_OFFSET = UNSAFE.objectFieldOffset(
-                ConcurrentHashMap.class.getDeclaredField("segmentMask"));
-            SEGMENTS_OFFSET = UNSAFE.objectFieldOffset(
-                ConcurrentHashMap.class.getDeclaredField("segments"));
+            U = sun.misc.Unsafe.getUnsafe();
+            Class<?> k = ConcurrentHashMap.class;
+            SIZECTL = U.objectFieldOffset
+                (k.getDeclaredField("sizeCtl"));
+            TRANSFERINDEX = U.objectFieldOffset
+                (k.getDeclaredField("transferIndex"));
+            TRANSFERORIGIN = U.objectFieldOffset
+                (k.getDeclaredField("transferOrigin"));
+            BASECOUNT = U.objectFieldOffset
+                (k.getDeclaredField("baseCount"));
+            CELLSBUSY = U.objectFieldOffset
+                (k.getDeclaredField("cellsBusy"));
+            Class<?> ck = Cell.class;
+            CELLVALUE = U.objectFieldOffset
+                (ck.getDeclaredField("value"));
+            Class<?> sc = Node[].class;
+            ABASE = U.arrayBaseOffset(sc);
+            int scale = U.arrayIndexScale(sc);
+            if ((scale & (scale - 1)) != 0)
+                throw new Error("data type scale not a power of two");
+            ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
         } catch (Exception e) {
             throw new Error(e);
         }
-        if ((ss & (ss-1)) != 0 || (ts & (ts-1)) != 0)
-            throw new Error("data type scale not a power of two");
-        SSHIFT = 31 - Integer.numberOfLeadingZeros(ss);
-        TSHIFT = 31 - Integer.numberOfLeadingZeros(ts);
     }
-
 }
--- a/jdk/src/share/classes/java/util/function/BiConsumer.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/BiConsumer.java	Mon Jun 10 10:38:33 2013 +0100
@@ -24,14 +24,16 @@
  */
 package java.util.function;
 
+import java.util.Objects;
+
 /**
  * An operation which accepts two input arguments and returns no result. This is
  * the two-arity specialization of {@link Consumer}. Unlike most other
  * functional interfaces, {@code BiConsumer} is expected to operate via
  * side-effects.
  *
- * @param <T> the type of the first argument to the {@code accept} operation.
- * @param <U> the type of the second argument to the {@code accept} operation.
+ * @param <T> the type of the first argument to the {@code accept} operation
+ * @param <U> the type of the second argument to the {@code accept} operation
  *
  * @see Consumer
  * @since 1.8
@@ -47,4 +49,28 @@
      * @param u an input object
      */
     void accept(T t, U u);
+
+    /**
+     * Returns a {@code BiConsumer} which performs, in sequence, the operation
+     * represented by this object followed by the operation represented by
+     * the other {@code BiConsumer}.
+     *
+     * <p>Any exceptions thrown by either {@code accept} method are relayed
+     * to the caller; if performing this operation throws an exception, the
+     * other operation will not be performed.
+     *
+     * @param other a BiConsumer which will be chained after this BiConsumer
+     * @return a BiConsumer which performs in sequence the {@code accept} method
+     * of this BiConsumer and the {@code accept} method of the specified
+     * BiConsumer operation
+     * @throws NullPointerException if other is null
+     */
+    default BiConsumer<T, U> chain(BiConsumer<? super T, ? super U> other) {
+        Objects.requireNonNull(other);
+
+        return (l, r) -> {
+            accept(l, r);
+            other.accept(l, r);
+        };
+    }
 }
--- a/jdk/src/share/classes/java/util/function/BiFunction.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/BiFunction.java	Mon Jun 10 10:38:33 2013 +0100
@@ -24,15 +24,17 @@
  */
 package java.util.function;
 
+import java.util.Objects;
+
 /**
  * Apply a function to the input arguments, yielding an appropriate result. This
  * is the two-arity specialization of {@link Function}. A function may
  * variously provide a mapping between types, object instances or keys and
  * values or any other form of transformation upon the input.
  *
- * @param <T> the type of the first argument to the {@code apply} operation.
- * @param <U> the type of the second argument to the {@code apply} operation.
- * @param <R> the type of results returned by the {@code apply} operation.
+ * @param <T> the type of the first argument to the {@code apply} operation
+ * @param <U> the type of the second argument to the {@code apply} operation
+ * @param <R> the type of results returned by the {@code apply} operation
  *
  * @see Function
  * @since 1.8
@@ -48,4 +50,22 @@
      * @return the function result
      */
     R apply(T t, U u);
+
+    /**
+     * Returns a new function which applies this function followed by the
+     * provided function.  If either function throws an exception, it is relayed
+     * to the caller.
+     *
+     * @param <V> Type of output objects to the combined function. May be the
+     * same type as {@code <T>}, {@code <U>} or {@code <R>}
+     * @param after An additional function to be applied after this function is
+     * applied
+     * @return A function which performs this function followed by the provided
+     * function
+     * @throws NullPointerException if after is null
+     */
+    default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
+        Objects.requireNonNull(after);
+        return (T t, U u) -> after.apply(apply(t, u));
+    }
 }
--- a/jdk/src/share/classes/java/util/function/BiPredicate.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/BiPredicate.java	Mon Jun 10 10:38:33 2013 +0100
@@ -30,8 +30,8 @@
  * Determines if the input objects match some criteria. This is the two-arity
  * specialization of {@link Predicate}.
  *
- * @param <T> the type of the first argument to {@code test}.
- * @param <U> the type of the second argument to {@code test}.
+ * @param <T> the type of the first argument to {@code test}
+ * @param <U> the type of the second argument to {@code test}
  *
  * @see Predicate
  * @since 1.8
@@ -42,9 +42,9 @@
     /**
      * Return {@code true} if the inputs match some criteria.
      *
-     * @param t an input object.
-     * @param u an input object.
-     * @return {@code true} if the inputs match some criteria.
+     * @param t an input object
+     * @param u an input object
+     * @return {@code true} if the inputs match some criteria
      */
     boolean test(T t, U u);
 
@@ -54,11 +54,12 @@
      * this predicate returns {@code false} then the remaining predicate is not
      * evaluated.
      *
-     * @param p a predicate which will be logically-ANDed with this predicate.
+     * @param p a predicate which will be logically-ANDed with this predicate
      * @return a new predicate which returns {@code true} only if both
-     * predicates return {@code true}.
+     * predicates return {@code true}
+     * @throws NullPointerException if p is null
      */
-    public default BiPredicate<T, U> and(BiPredicate<? super T, ? super U> p) {
+    default BiPredicate<T, U> and(BiPredicate<? super T, ? super U> p) {
         Objects.requireNonNull(p);
         return (T t, U u) -> test(t, u) && p.test(t, u);
     }
@@ -67,9 +68,9 @@
      * Returns a predicate which negates the result of this predicate.
      *
      * @return a new predicate who's result is always the opposite of this
-     * predicate.
+     * predicate
      */
-    public default BiPredicate<T, U> negate() {
+    default BiPredicate<T, U> negate() {
         return (T t, U u) -> !test(t, u);
     }
 
@@ -79,25 +80,13 @@
      * predicate returns {@code true} then the remaining predicate is not
      * evaluated.
      *
-     * @param p a predicate which will be logically-ORed with this predicate.
+     * @param p a predicate which will be logically-ORed with this predicate
      * @return a new predicate which returns {@code true} if either predicate
-     * returns {@code true}.
+     * returns {@code true}
+     * @throws NullPointerException if p is null
      */
-    public default BiPredicate<T, U> or(BiPredicate<? super T, ? super U> p) {
+    default BiPredicate<T, U> or(BiPredicate<? super T, ? super U> p) {
         Objects.requireNonNull(p);
         return (T t, U u) -> test(t, u) || p.test(t, u);
     }
-
-    /**
-     * Returns a predicate that evaluates to {@code true} if both or neither of
-     * the component predicates evaluate to {@code true}.
-     *
-     * @param p a predicate which will be logically-XORed with this predicate.
-     * @return a predicate that evaluates to {@code true} if both or neither of
-     * the component predicates evaluate to {@code true}.
-     */
-    public default BiPredicate<T, U> xor(BiPredicate<? super T, ? super U> p) {
-        Objects.requireNonNull(p);
-        return (T t, U u) -> test(t, u) ^ p.test(t, u);
-    }
 }
--- a/jdk/src/share/classes/java/util/function/BooleanSupplier.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/BooleanSupplier.java	Mon Jun 10 10:38:33 2013 +0100
@@ -40,5 +40,5 @@
      *
      * @return a {@code boolean} value
      */
-    public boolean getAsBoolean();
+    boolean getAsBoolean();
 }
--- a/jdk/src/share/classes/java/util/function/Consumer.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/Consumer.java	Mon Jun 10 10:38:33 2013 +0100
@@ -24,6 +24,8 @@
  */
 package java.util.function;
 
+import java.util.Objects;
+
 /**
  * An operation which accepts a single input argument and returns no result.
  * Unlike most other functional interfaces, {@code Consumer} is expected to
@@ -41,5 +43,25 @@
      *
      * @param t the input object
      */
-    public void accept(T t);
+    void accept(T t);
+
+    /**
+     * Returns a {@code Consumer} which performs, in sequence, the operation
+     * represented by this object followed by the operation represented by
+     * the other {@code Consumer}.
+     *
+     * <p>Any exceptions thrown by either {@code accept} method are relayed
+     * to the caller; if performing this operation throws an exception, the
+     * other operation will not be performed.
+     *
+     * @param other a Consumer which will be chained after this Consumer
+     * @return a Consumer which performs in sequence the {@code accept} method
+     * of this Consumer and the {@code accept} method of the specified Consumer
+     * operation
+     * @throws NullPointerException if other is null
+     */
+    default Consumer<T> chain(Consumer<? super T> other) {
+        Objects.requireNonNull(other);
+        return (T t) -> { accept(t); other.accept(t); };
+    }
 }
--- a/jdk/src/share/classes/java/util/function/DoubleBinaryOperator.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/DoubleBinaryOperator.java	Mon Jun 10 10:38:33 2013 +0100
@@ -43,5 +43,5 @@
      * @param right the right operand value
      * @return the result of the operation
      */
-    public double applyAsDouble(double left, double right);
+    double applyAsDouble(double left, double right);
 }
--- a/jdk/src/share/classes/java/util/function/DoubleConsumer.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/DoubleConsumer.java	Mon Jun 10 10:38:33 2013 +0100
@@ -24,6 +24,8 @@
  */
 package java.util.function;
 
+import java.util.Objects;
+
 /**
  * An operation which accepts a single double argument and returns no result.
  * This is the primitive type specialization of {@link Consumer} for
@@ -41,5 +43,26 @@
      *
      * @param value the input value
      */
-    public void accept(double value);
+    void accept(double value);
+
+    /**
+     * Returns a {@code DoubleConsumer} which performs, in sequence, the operation
+     * represented by this object followed by the operation represented by
+     * another {@code DoubleConsumer}.
+     *
+     * <p>Any exceptions thrown by either {@code accept} method are relayed
+     * to the caller; if performing this operation throws an exception, the
+     * other operation will not be performed.
+     *
+     * @param other a DoubleConsumer which will be chained after this
+     * DoubleConsumer
+     * @return an DoubleConsumer which performs in sequence the {@code accept} method
+     * of this DoubleConsumer and the {@code accept} method of the specified IntConsumer
+     * operation
+     * @throws NullPointerException if other is null
+     */
+    default DoubleConsumer chain(DoubleConsumer other) {
+        Objects.requireNonNull(other);
+        return (double t) -> { accept(t); other.accept(t); };
+    }
 }
--- a/jdk/src/share/classes/java/util/function/DoubleFunction.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/DoubleFunction.java	Mon Jun 10 10:38:33 2013 +0100
@@ -43,5 +43,5 @@
      * @param value the input value
      * @return the function result
      */
-    public R apply(double value);
+    R apply(double value);
 }
--- a/jdk/src/share/classes/java/util/function/DoublePredicate.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/DoublePredicate.java	Mon Jun 10 10:38:33 2013 +0100
@@ -40,11 +40,11 @@
     /**
      * Returns {@code true} if the input value matches some criteria.
      *
-     * @param value the value to be tested.
+     * @param value the value to be tested
      * @return {@code true} if the input value matches some criteria, otherwise
-     * {@code false}.
+     * {@code false}
      */
-    public boolean test(double value);
+    boolean test(double value);
 
     /**
      * Returns a predicate which evaluates to {@code true} only if this
@@ -52,11 +52,16 @@
      * this predicate returns {@code false} then the remaining predicate is not
      * evaluated.
      *
-     * @param p a predicate which will be logically-ANDed with this predicate.
+     * <p>Any exceptions thrown by either {@code test} method are relayed
+     * to the caller; if performing first operation throws an exception, the
+     * second operation will not be performed.
+     *
+     * @param p a predicate which will be logically-ANDed with this predicate
      * @return a new predicate which returns {@code true} only if both
-     * predicates return {@code true}.
+     * predicates return {@code true}
+     * @throws NullPointerException if p is null
      */
-    public default DoublePredicate and(DoublePredicate p) {
+    default DoublePredicate and(DoublePredicate p) {
         Objects.requireNonNull(p);
         return (value) -> test(value) && p.test(value);
     }
@@ -65,9 +70,9 @@
      * Returns a predicate which negates the result of this predicate.
      *
      * @return a new predicate who's result is always the opposite of this
-     * predicate.
+     * predicate
      */
-    public default DoublePredicate negate() {
+    default DoublePredicate negate() {
         return (value) -> !test(value);
     }
 
@@ -77,25 +82,17 @@
      * predicate returns {@code true} then the remaining predicate is not
      * evaluated.
      *
-     * @param p a predicate which will be logically-ANDed with this predicate.
+     * <p>Any exceptions thrown by either {@code test} method are relayed
+     * to the caller; if performing first operation throws an exception, the
+     * second operation will not be performed.
+     *
+     * @param p a predicate which will be logically-ANDed with this predicate
      * @return a new predicate which returns {@code true} if either predicate
-     * returns {@code true}.
+     * returns {@code true}
+     * @throws NullPointerException if p is null
      */
-    public default DoublePredicate or(DoublePredicate p) {
+    default DoublePredicate or(DoublePredicate p) {
         Objects.requireNonNull(p);
         return (value) -> test(value) || p.test(value);
     }
-
-    /**
-     * Returns a predicate that evaluates to {@code true} if both or neither of
-     * the component predicates evaluate to {@code true}.
-     *
-     * @param p a predicate which will be logically-XORed with this predicate.
-     * @return a predicate that evaluates to {@code true} if all or none of the
-     * component predicates evaluate to {@code true}.
-     */
-    public default DoublePredicate xor(DoublePredicate p) {
-        Objects.requireNonNull(p);
-        return (value) -> test(value) ^ p.test(value);
-    }
 }
--- a/jdk/src/share/classes/java/util/function/DoubleSupplier.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/DoubleSupplier.java	Mon Jun 10 10:38:33 2013 +0100
@@ -39,5 +39,5 @@
      *
      * @return a {@code double} value
      */
-    public double getAsDouble();
+    double getAsDouble();
 }
--- a/jdk/src/share/classes/java/util/function/DoubleUnaryOperator.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/DoubleUnaryOperator.java	Mon Jun 10 10:38:33 2013 +0100
@@ -24,6 +24,8 @@
  */
 package java.util.function;
 
+import java.util.Objects;
+
 /**
  * An operation on a {@code double} operand yielding a {@code double}
  * result. This is the primitive type specialization of {@link UnaryOperator}
@@ -42,5 +44,46 @@
      * @param operand the operand value
      * @return the operation result value
      */
-    public double applyAsDouble(double operand);
+    double applyAsDouble(double operand);
+
+    /**
+     * Compose a new function which applies the provided function followed by
+     * this function.  If either function throws an exception, it is relayed
+     * to the caller.
+     *
+     * @param before An additional function to be applied before this function
+     * is applied
+     * @return A function which performs the provided function followed by this
+     * function
+     * @throws NullPointerException if before is null
+     */
+    default DoubleUnaryOperator compose(DoubleUnaryOperator before) {
+        Objects.requireNonNull(before);
+        return (double v) -> applyAsDouble(before.applyAsDouble(v));
+    }
+
+    /**
+     * Compose a new function which applies this function followed by the
+     * provided function.  If either function throws an exception, it is relayed
+     * to the caller.
+     *
+     * @param after An additional function to be applied after this function is
+     * applied
+     * @return A function which performs this function followed by the provided
+     * function followed
+     * @throws NullPointerException if after is null
+     */
+    default DoubleUnaryOperator andThen(DoubleUnaryOperator after) {
+        Objects.requireNonNull(after);
+        return (double t) -> after.applyAsDouble(applyAsDouble(t));
+    }
+
+    /**
+     * Returns a unary operator that provides its input value as the result.
+     *
+     * @return a unary operator that provides its input value as the result
+     */
+    static DoubleUnaryOperator identity() {
+        return t -> t;
+    }
 }
--- a/jdk/src/share/classes/java/util/function/Function.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/Function.java	Mon Jun 10 10:38:33 2013 +0100
@@ -24,14 +24,15 @@
  */
 package java.util.function;
 
+import java.util.Objects;
 
 /**
  * Apply a function to the input argument, yielding an appropriate result.  A
  * function may variously provide a mapping between types, object instances or
  * keys and values or any other form of transformation upon the input.
  *
- * @param <T> the type of the input to the {@code apply} operation.
- * @param <R> the type of the result of the {@code apply} operation.
+ * @param <T> the type of the input to the {@code apply} operation
+ * @param <R> the type of the result of the {@code apply} operation
  *
  * @since 1.8
  */
@@ -44,5 +45,50 @@
      * @param t the input object
      * @return the function result
      */
-    public R apply(T t);
+    R apply(T t);
+
+    /**
+     * Returns a new function which applies the provided function followed by
+     * this function.  If either function throws an exception, it is relayed
+     * to the caller.
+     *
+     * @param <V> type of input objects to the combined function. May be the
+     * same type as {@code <T>} or {@code <R>}
+     * @param before an additional function to be applied before this function
+     * is applied
+     * @return a function which performs the provided function followed by this
+     * function
+     * @throws NullPointerException if before is null
+     */
+    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
+        Objects.requireNonNull(before);
+        return (V v) -> apply(before.apply(v));
+    }
+
+    /**
+     * Returns a new function which applies this function followed by the
+     * provided function.  If either function throws an exception, it is relayed
+     * to the caller.
+     *
+     * @param <V> type of output objects to the combined function. May be the
+     * same type as {@code <T>} or {@code <R>}
+     * @param after an additional function to be applied after this function is
+     * applied
+     * @return a function which performs this function followed by the provided
+     * function
+     * @throws NullPointerException if after is null
+     */
+    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
+        Objects.requireNonNull(after);
+        return (T t) -> after.apply(apply(t));
+    }
+
+    /**
+     * Returns a {@code Function} whose {@code apply} method returns its input.
+     *
+     * @param <T> the type of the input and output objects to the function
+     */
+    static <T> Function<T, T> identity() {
+        return t -> t;
+    }
 }
--- a/jdk/src/share/classes/java/util/function/IntBinaryOperator.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/IntBinaryOperator.java	Mon Jun 10 10:38:33 2013 +0100
@@ -44,5 +44,5 @@
      * @param right  the right operand value
      * @return the result of the operation
      */
-    public int applyAsInt(int left, int right);
+    int applyAsInt(int left, int right);
 }
--- a/jdk/src/share/classes/java/util/function/IntConsumer.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/IntConsumer.java	Mon Jun 10 10:38:33 2013 +0100
@@ -24,6 +24,8 @@
  */
 package java.util.function;
 
+import java.util.Objects;
+
 /**
  * An operation which accepts a single integer argument and returns no result.
  * This is the primitive type specialization of {@link Consumer} for {@code int}.
@@ -41,5 +43,26 @@
      *
      * @param value the input value
      */
-    public void accept(int value);
+    void accept(int value);
+
+    /**
+     * Returns an {@code IntConsumer} which performs, in sequence, the operation
+     * represented by this object followed by the operation represented by
+     * another {@code IntConsumer}.
+     *
+     * <p>Any exceptions thrown by either {@code accept} method are relayed
+     * to the caller; if performing this operation throws an exception, the
+     * other operation will not be performed.
+     *
+     * @param other an IntConsumer which will be chained after this
+     * IntConsumer
+     * @return an IntConsumer which performs in sequence the {@code accept} method
+     * of this IntConsumer and the {@code accept} method of the specified IntConsumer
+     * operation
+     * @throws NullPointerException if other is null
+     */
+    default IntConsumer chain(IntConsumer other) {
+        Objects.requireNonNull(other);
+        return (int t) -> { accept(t); other.accept(t); };
+    }
 }
--- a/jdk/src/share/classes/java/util/function/IntFunction.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/IntFunction.java	Mon Jun 10 10:38:33 2013 +0100
@@ -43,5 +43,5 @@
      * @param value the input value
      * @return the function result
      */
-    public R apply(int value);
+    R apply(int value);
 }
--- a/jdk/src/share/classes/java/util/function/IntPredicate.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/IntPredicate.java	Mon Jun 10 10:38:33 2013 +0100
@@ -39,11 +39,11 @@
     /**
      * Returns {@code true} if the input value matches some criteria.
      *
-     * @param value the value to be tested.
+     * @param value the value to be tested
      * @return {@code true} if the input value matches some criteria, otherwise
      * {@code false}
      */
-    public boolean test(int value);
+    boolean test(int value);
 
     /**
      * Returns a predicate which evaluates to {@code true} only if this
@@ -51,11 +51,16 @@
      * this predicate returns {@code false} then the remaining predicate is not
      * evaluated.
      *
-     * @param p a predicate which will be logically-ANDed with this predicate.
+     * <p>Any exceptions thrown by either {@code test} method are relayed
+     * to the caller; if performing first operation throws an exception, the
+     * second operation will not be performed.
+     *
+     * @param p a predicate which will be logically-ANDed with this predicate
      * @return a new predicate which returns {@code true} only if both
-     * predicates return {@code true}.
+     * predicates return {@code true}
+     * @throws NullPointerException if p is null
      */
-    public default IntPredicate and(IntPredicate p) {
+    default IntPredicate and(IntPredicate p) {
         Objects.requireNonNull(p);
         return (value) -> test(value) && p.test(value);
     }
@@ -64,9 +69,9 @@
      * Returns a predicate which negates the result of this predicate.
      *
      * @return a new predicate who's result is always the opposite of this
-     * predicate.
+     * predicate
      */
-    public default IntPredicate negate() {
+    default IntPredicate negate() {
         return (value) -> !test(value);
     }
 
@@ -76,25 +81,17 @@
      * predicate returns {@code true} then the remaining predicate is not
      * evaluated.
      *
-     * @param p a predicate which will be logically-ORed with this predicate.
+     * <p>Any exceptions thrown by either {@code test} method are relayed
+     * to the caller; if performing first operation throws an exception, the
+     * second operation will not be performed.
+     *
+     * @param p a predicate which will be logically-ORed with this predicate
      * @return a new predicate which returns {@code true} if either predicate
-     * returns {@code true}.
+     * returns {@code true}
+     * @throws NullPointerException if p is null
      */
-    public default IntPredicate or(IntPredicate p) {
+    default IntPredicate or(IntPredicate p) {
         Objects.requireNonNull(p);
         return (value) -> test(value) || p.test(value);
     }
-
-    /**
-     * Returns a predicate that evaluates to {@code true} if both or neither of
-     * the component predicates evaluate to {@code true}.
-     *
-     * @param p a predicate which will be logically-XORed with this predicate.
-     * @return a predicate that evaluates to {@code true} if both or neither of
-     * the component predicates evaluate to {@code true}
-     */
-    public default IntPredicate xor(IntPredicate p) {
-        Objects.requireNonNull(p);
-        return (value) -> test(value) ^ p.test(value);
-    }
 }
--- a/jdk/src/share/classes/java/util/function/IntSupplier.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/IntSupplier.java	Mon Jun 10 10:38:33 2013 +0100
@@ -39,5 +39,5 @@
      *
      * @return an {@code int} value
      */
-    public int getAsInt();
+    int getAsInt();
 }
--- a/jdk/src/share/classes/java/util/function/IntUnaryOperator.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/IntUnaryOperator.java	Mon Jun 10 10:38:33 2013 +0100
@@ -24,6 +24,8 @@
  */
 package java.util.function;
 
+import java.util.Objects;
+
 /**
  * An operation on a single {@code int} operand yielding an {@code int} result.
  * This is the primitive type specialization of {@link UnaryOperator} for
@@ -37,10 +39,51 @@
 
     /**
      * Returns the {@code int} value result of the operation upon the
-     * {@code int}  operand.
+     * {@code int} operand.
      *
      * @param operand the operand value
      * @return the operation result value
      */
-    public int applyAsInt(int operand);
+    int applyAsInt(int operand);
+
+    /**
+     * Compose a new function which applies the provided function followed by
+     * this function.  If either function throws an exception, it is relayed
+     * to the caller.
+     *
+     * @param before an additional function to be applied before this function
+     * is applied
+     * @return a function which performs the provided function followed by this
+     * function
+     * @throws NullPointerException if before is null
+     */
+    default IntUnaryOperator compose(IntUnaryOperator before) {
+        Objects.requireNonNull(before);
+        return (int v) -> applyAsInt(before.applyAsInt(v));
+    }
+
+    /**
+     * Compose a new function which applies this function followed by the
+     * provided function.  If either function throws an exception, it is relayed
+     * to the caller.
+     *
+     * @param after an additional function to be applied after this function is
+     * applied
+     * @return a function which performs this function followed by the provided
+     * function followed
+     * @throws NullPointerException if after is null
+     */
+    default IntUnaryOperator andThen(IntUnaryOperator after) {
+        Objects.requireNonNull(after);
+        return (int t) -> after.applyAsInt(applyAsInt(t));
+    }
+
+    /**
+     * Returns a unary operator that provides its input value as the result.
+     *
+     * @return a unary operator that provides its input value as the result
+     */
+    static IntUnaryOperator identity() {
+        return t -> t;
+    }
 }
--- a/jdk/src/share/classes/java/util/function/LongBinaryOperator.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/LongBinaryOperator.java	Mon Jun 10 10:38:33 2013 +0100
@@ -44,5 +44,5 @@
      * @param right  the right operand value
      * @return the result of the operation
      */
-    public long applyAsLong(long left, long right);
+    long applyAsLong(long left, long right);
 }
--- a/jdk/src/share/classes/java/util/function/LongConsumer.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/LongConsumer.java	Mon Jun 10 10:38:33 2013 +0100
@@ -24,6 +24,8 @@
  */
 package java.util.function;
 
+import java.util.Objects;
+
 /**
  * An operation which accepts a single long argument and returns no result.
  * This is the {@code long}-consuming primitive type specialization of
@@ -41,5 +43,26 @@
      *
      * @param value the input value
      */
-    public void accept(long value);
+    void accept(long value);
+
+    /**
+     * Returns a {@code LongConsumer} which performs, in sequence, the operation
+     * represented by this object followed by the operation represented by
+     * another {@code LongConsumer}.
+     *
+     * <p>Any exceptions thrown by either {@code accept} method are relayed
+     * to the caller; if performing this operation throws an exception, the
+     * other operation will not be performed.
+     *
+     * @param other a LongConsumer which will be chained after this
+     * LongConsumer
+     * @return a LongConsumer which performs in sequence the {@code accept} method
+     * of this LongConsumer and the {@code accept} method of the specified LongConsumer
+     * operation
+     * @throws NullPointerException if other is null
+     */
+    default LongConsumer chain(LongConsumer other) {
+        Objects.requireNonNull(other);
+        return (long t) -> { accept(t); other.accept(t); };
+    }
 }
--- a/jdk/src/share/classes/java/util/function/LongFunction.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/LongFunction.java	Mon Jun 10 10:38:33 2013 +0100
@@ -43,5 +43,5 @@
      * @param value the input value
      * @return the function result
      */
-    public R apply(long value);
+    R apply(long value);
 }
--- a/jdk/src/share/classes/java/util/function/LongPredicate.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/LongPredicate.java	Mon Jun 10 10:38:33 2013 +0100
@@ -39,11 +39,11 @@
     /**
      * Returns {@code true} if the input value matches some criteria.
      *
-     * @param value the value to be tested.
+     * @param value the value to be tested
      * @return {@code true} if the input value matches some criteria, otherwise
-     * {@code false}.
+     * {@code false}
      */
-    public boolean test(long value);
+    boolean test(long value);
 
     /**
      * Returns a predicate which evaluates to {@code true} only if this
@@ -51,11 +51,15 @@
      * this predicate returns {@code false} then the remaining predicate is not
      * evaluated.
      *
-     * @param p a predicate which will be logically-ANDed with this predicate.
+     * <p>Any exceptions thrown by either {@code test} method are relayed
+     * to the caller; if performing first operation throws an exception, the
+     * second operation will not be performed.
+     *
+     * @param p a predicate which will be logically-ANDed with this predicate
      * @return a new predicate which returns {@code true} only if both
-     * predicates return {@code true}.
+     * predicates return {@code true}
      */
-    public default LongPredicate and(LongPredicate p) {
+    default LongPredicate and(LongPredicate p) {
         Objects.requireNonNull(p);
         return (value) -> test(value) && p.test(value);
     }
@@ -64,9 +68,9 @@
      * Returns a predicate which negates the result of this predicate.
      *
      * @return a new predicate who's result is always the opposite of this
-     * predicate.
+     * predicate
      */
-    public default LongPredicate negate() {
+    default LongPredicate negate() {
         return (value) -> !test(value);
     }
 
@@ -76,25 +80,17 @@
      * predicate returns {@code true} then the remaining predicate is not
      * evaluated.
      *
-     * @param p a predicate which will be logically-ORed with this predicate.
+     * <p>Any exceptions thrown by either {@code test} method are relayed
+     * to the caller; if performing first operation throws an exception, the
+     * second operation will not be performed.
+     *
+     * @param p a predicate which will be logically-ORed with this predicate
      * @return a new predicate which returns {@code true} if either predicate
-     * returns {@code true}.
+     * returns {@code true}
+     * @throws NullPointerException if p is null
      */
-    public default LongPredicate or(LongPredicate p) {
+    default LongPredicate or(LongPredicate p) {
         Objects.requireNonNull(p);
         return (value) -> test(value) || p.test(value);
     }
-
-    /**
-     * Returns a predicate that evaluates to {@code true} if both or neither of
-     * the component predicates evaluate to {@code true}.
-     *
-     * @param p a predicate which will be logically-XORed with this predicate.
-     * @return a predicate that evaluates to {@code true} if both or neither of
-     * the component predicates evaluate to {@code true}.
-     */
-    public default LongPredicate xor(LongPredicate p) {
-        Objects.requireNonNull(p);
-        return (value) -> test(value) ^ p.test(value);
-    }
 }
--- a/jdk/src/share/classes/java/util/function/LongSupplier.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/LongSupplier.java	Mon Jun 10 10:38:33 2013 +0100
@@ -39,5 +39,5 @@
      *
      * @return a {@code long} value
      */
-    public long getAsLong();
+    long getAsLong();
 }
--- a/jdk/src/share/classes/java/util/function/LongUnaryOperator.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/LongUnaryOperator.java	Mon Jun 10 10:38:33 2013 +0100
@@ -24,6 +24,8 @@
  */
 package java.util.function;
 
+import java.util.Objects;
+
 /**
  * An operation on a single {@code long} operand yielding a {@code long} result.
  * This is the primitive type specialization of {@link UnaryOperator} for
@@ -42,5 +44,46 @@
      * @param operand the operand value
      * @return the operation result value
      */
-    public long applyAsLong(long operand);
+    long applyAsLong(long operand);
+
+    /**
+     * Compose a new function which applies the provided function followed by
+     * this function.  If either function throws an exception, it is relayed
+     * to the caller.
+     *
+     * @param before An additional function to be applied before this function
+     * is applied
+     * @return A function which performs the provided function followed by this
+     * function
+     * @throws NullPointerException if before is null
+     */
+    default LongUnaryOperator compose(LongUnaryOperator before) {
+        Objects.requireNonNull(before);
+        return (long v) -> applyAsLong(before.applyAsLong(v));
+    }
+
+    /**
+     * Compose a new function which applies this function followed by the
+     * provided function.  If either function throws an exception, it is relayed
+     * to the caller.
+     *
+     * @param after An additional function to be applied after this function is
+     * applied
+     * @return A function which performs this function followed by the provided
+     * function followed
+     * @throws NullPointerException if after is null
+     */
+    default LongUnaryOperator andThen(LongUnaryOperator after) {
+        Objects.requireNonNull(after);
+        return (long t) -> after.applyAsLong(applyAsLong(t));
+    }
+
+    /**
+     * Returns a unary operator that provides its input value as the result.
+     *
+     * @return a unary operator that provides its input value as the result
+     */
+    static LongUnaryOperator identity() {
+        return t -> t;
+    }
 }
--- a/jdk/src/share/classes/java/util/function/ObjDoubleConsumer.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/ObjDoubleConsumer.java	Mon Jun 10 10:38:33 2013 +0100
@@ -44,5 +44,5 @@
      * @param t an input object
      * @param value an input value
      */
-    public void accept(T t, double value);
+    void accept(T t, double value);
 }
--- a/jdk/src/share/classes/java/util/function/ObjIntConsumer.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/ObjIntConsumer.java	Mon Jun 10 10:38:33 2013 +0100
@@ -30,7 +30,7 @@
  * {@link BiConsumer}. Unlike most other functional interfaces,
  * {@code ObjIntConsumer} is expected to operate via side-effects.
  *
- * @param <T> Type of reference argument to {@code accept()}.
+ * @param <T> Type of reference argument to {@code accept()}
  *
  * @see BiConsumer
  * @since 1.8
@@ -44,5 +44,5 @@
      * @param t an input object
      * @param value an input value
      */
-    public void accept(T t, int value);
+    void accept(T t, int value);
 }
--- a/jdk/src/share/classes/java/util/function/ObjLongConsumer.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/ObjLongConsumer.java	Mon Jun 10 10:38:33 2013 +0100
@@ -30,7 +30,7 @@
  * {@link BiConsumer}. Unlike most other functional interfaces,
  * {@code ObjLongConsumer} is expected to operate via side-effects.
  *
- * @param <T> Type of reference argument to {@code accept()}.
+ * @param <T> Type of reference argument to {@code accept()}
  *
  * @see BiConsumer
  * @since 1.8
@@ -44,5 +44,5 @@
      * @param t an input object
      * @param value an input value
      */
-    public void accept(T t, long value);
+    void accept(T t, long value);
 }
--- a/jdk/src/share/classes/java/util/function/Predicate.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/Predicate.java	Mon Jun 10 10:38:33 2013 +0100
@@ -43,7 +43,7 @@
      * @return {@code true} if the input object matches some criteria, otherwise
      * {@code false}
      */
-    public boolean test(T t);
+    boolean test(T t);
 
     /**
      * Returns a predicate which evaluates to {@code true} only if this
@@ -51,11 +51,16 @@
      * this predicate returns {@code false} then the remaining predicate is not
      * evaluated.
      *
-     * @param p a predicate which will be logically-ANDed with this predicate.
+     * <p>Any exceptions thrown by either {@code test} method are relayed
+     * to the caller; if performing first operation throws an exception, the
+     * second operation will not be performed.
+     *
+     * @param p a predicate which will be logically-ANDed with this predicate
      * @return a new predicate which returns {@code true} only if both
-     * predicates return {@code true}.
+     * predicates return {@code true}
+     * @throws NullPointerException if p is null
      */
-    public default Predicate<T> and(Predicate<? super T> p) {
+    default Predicate<T> and(Predicate<? super T> p) {
         Objects.requireNonNull(p);
         return (t) -> test(t) && p.test(t);
     }
@@ -66,7 +71,7 @@
      * @return a new predicate who's result is always the opposite of this
      * predicate.
      */
-    public default Predicate<T> negate() {
+    default Predicate<T> negate() {
         return (t) -> !test(t);
     }
 
@@ -76,25 +81,32 @@
      * predicate returns {@code true} then the remaining predicate is not
      * evaluated.
      *
-     * @param p a predicate which will be logically-ORed with this predicate.
+     * <p>Any exceptions thrown by either {@code test} method are relayed
+     * to the caller; if performing first operation throws an exception, the
+     * second operation will not be performed.
+     *
+     * @param p a predicate which will be logically-ORed with this predicate
      * @return a new predicate which returns {@code true} if either predicate
-     * returns {@code true}.
+     * returns {@code true}
+     * @throws NullPointerException if p is null
      */
-    public default Predicate<T> or(Predicate<? super T> p) {
+    default Predicate<T> or(Predicate<? super T> p) {
         Objects.requireNonNull(p);
         return (t) -> test(t) || p.test(t);
     }
 
     /**
-     * Returns a predicate that evaluates to {@code true} if both or neither of
-     * the component predicates evaluate to {@code true}.
+     * Returns a predicate who's result matches
+     * {@code Objects.equals(target, t)}.
      *
-     * @param p a predicate which will be logically-XORed with this predicte.
-     * @return a predicate that evaluates to {@code true} if both or neither of
-     * the component predicates evaluate to {@code true}.
+     * @param <T> the type of values evaluated by the predicate
+     * @param target the target value to be compared for equality
+     * @return a predicate who's result matches
+     * {@code Objects.equals(target, t)}
      */
-    public default Predicate<T> xor(Predicate<? super T> p) {
-        Objects.requireNonNull(p);
-        return (t) -> test(t) ^ p.test(t);
+    static <T> Predicate<T> isEqual(Object target) {
+        return (null == target)
+                ? Objects::isNull
+                : object -> target.equals(object);
     }
 }
--- a/jdk/src/share/classes/java/util/function/Supplier.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/Supplier.java	Mon Jun 10 10:38:33 2013 +0100
@@ -40,5 +40,5 @@
      *
      * @return an object
      */
-    public T get();
+    T get();
 }
--- a/jdk/src/share/classes/java/util/function/ToDoubleBiFunction.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/ToDoubleBiFunction.java	Mon Jun 10 10:38:33 2013 +0100
@@ -46,5 +46,5 @@
      * @param u an input object
      * @return the function result value
      */
-    public double applyAsDouble(T t, U u);
+    double applyAsDouble(T t, U u);
 }
--- a/jdk/src/share/classes/java/util/function/ToDoubleFunction.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/ToDoubleFunction.java	Mon Jun 10 10:38:33 2013 +0100
@@ -42,5 +42,5 @@
      * @param t the input object
      * @return the function result value
      */
-    public double applyAsDouble(T t);
+    double applyAsDouble(T t);
 }
--- a/jdk/src/share/classes/java/util/function/ToIntBiFunction.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/ToIntBiFunction.java	Mon Jun 10 10:38:33 2013 +0100
@@ -28,10 +28,10 @@
  * Apply a function to the input arguments, yielding an appropriate result.
  * This is the {@code int}-bearing specialization for {@link BiFunction}.
  *
- * @param <T> the type of the first argument to the {@code applyAsLong}
- * operation.
- * @param <U> the type of the second argument to the {@code applyAsLong}
- * operation.
+ * @param <T> the type of the first argument to the {@code applyAsInt}
+ * operation
+ * @param <U> the type of the second argument to the {@code applyAsInt}
+ * operation
  *
  * @see BiFunction
  * @since 1.8
@@ -46,5 +46,5 @@
      * @param u an input object
      * @return the function result value
      */
-    public int applyAsInt(T t, U u);
+    int applyAsInt(T t, U u);
 }
--- a/jdk/src/share/classes/java/util/function/ToIntFunction.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/ToIntFunction.java	Mon Jun 10 10:38:33 2013 +0100
@@ -42,5 +42,5 @@
      * @param t the input object
      * @return the function result value
      */
-    public int applyAsInt(T t);
+    int applyAsInt(T t);
 }
--- a/jdk/src/share/classes/java/util/function/ToLongBiFunction.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/ToLongBiFunction.java	Mon Jun 10 10:38:33 2013 +0100
@@ -46,5 +46,5 @@
      * @param u an input object
      * @return the function result value
      */
-    public long applyAsLong(T t, U u);
+    long applyAsLong(T t, U u);
 }
--- a/jdk/src/share/classes/java/util/function/ToLongFunction.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/ToLongFunction.java	Mon Jun 10 10:38:33 2013 +0100
@@ -42,5 +42,5 @@
      * @param t the input object
      * @return the function result value
      */
-    public long applyAsLong(T t);
+    long applyAsLong(T t);
 }
--- a/jdk/src/share/classes/java/util/function/UnaryOperator.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/UnaryOperator.java	Mon Jun 10 10:38:33 2013 +0100
@@ -36,4 +36,13 @@
  */
 @FunctionalInterface
 public interface UnaryOperator<T> extends Function<T, T> {
+
+    /**
+     * Returns a unary operator that provides its input value as the result.
+     *
+     * @return a unary operator that provides its input value as the result
+     */
+    static <T> UnaryOperator<T> identity() {
+        return t -> t;
+    }
 }
--- a/jdk/src/share/classes/java/util/spi/LocaleServiceProvider.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/spi/LocaleServiceProvider.java	Mon Jun 10 10:38:33 2013 +0100
@@ -128,6 +128,14 @@
  * installed SPI providers, and "JRE" represents the locale sensitive services
  * in the Java Runtime Environment, the locale sensitive services in the SPI
  * providers are looked up first.
+ * <p>
+ * There are two other possible locale sensitive service providers, i.e., "CLDR"
+ * which is a provider based on Unicode Consortium's
+ * <a href="http://cldr.unicode.org/">CLDR Project</a>, and "HOST" which is a
+ * provider that reflects the user's custom settings in the underlying operating
+ * system. These two providers may not be available, depending on the Java Runtime
+ * Environment implementation. Specifying "JRE,SPI" is identical to the default
+ * behavior, which is compatibile with the prior releases.
  *
  * @since        1.6
  */
--- a/jdk/src/share/classes/java/util/stream/DoubleStream.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/stream/DoubleStream.java	Mon Jun 10 10:38:33 2013 +0100
@@ -603,7 +603,7 @@
     /**
      * Returns an {@link OptionalDouble} describing the first element of this
      * stream (in the encounter order), or an empty {@code OptionalDouble} if
-     * the stream is empty.  If the stream has no encounter order, than any
+     * the stream is empty.  If the stream has no encounter order, then any
      * element may be returned.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
--- a/jdk/src/share/classes/java/util/stream/IntStream.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/stream/IntStream.java	Mon Jun 10 10:38:33 2013 +0100
@@ -588,7 +588,7 @@
     /**
      * Returns an {@link OptionalInt} describing the first element of this
      * stream (in the encounter order), or an empty {@code OptionalInt} if the
-     * stream is empty.  If the stream has no encounter order, than any element
+     * stream is empty.  If the stream has no encounter order, then any element
      * may be returned.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
--- a/jdk/src/share/classes/java/util/stream/LongStream.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/stream/LongStream.java	Mon Jun 10 10:38:33 2013 +0100
@@ -588,7 +588,7 @@
     /**
      * Returns an {@link OptionalLong} describing the first element of this
      * stream (in the encounter order), or an empty {@code OptionalLong} if the
-     * stream is empty.  If the stream has no encounter order, than any element
+     * stream is empty.  If the stream has no encounter order, then any element
      * may be returned.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
--- a/jdk/src/share/classes/java/util/stream/Stream.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/stream/Stream.java	Mon Jun 10 10:38:33 2013 +0100
@@ -754,7 +754,7 @@
     /**
      * Returns an {@link Optional} describing the first element of this stream
      * (in the encounter order), or an empty {@code Optional} if the stream is
-     * empty.  If the stream has no encounter order, than any element may be
+     * empty.  If the stream has no encounter order, then any element may be
      * returned.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
--- a/jdk/src/share/classes/java/util/stream/StreamBuilder.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/stream/StreamBuilder.java	Mon Jun 10 10:38:33 2013 +0100
@@ -38,7 +38,7 @@
  * <p>A {@code StreamBuilder} has a lifecycle, where it starts in a building
  * phase, during which elements can be added, and then transitions to a built
  * phase, after which elements may not be added.  The built phase begins
- * when the {@link #build()}} method is called, which creates an ordered
+ * when the {@link #build()} method is called, which creates an ordered
  * {@code Stream} whose elements are the elements that were added to the stream
  * builder, in the order they were added.
  *
@@ -98,7 +98,7 @@
      * <p>A stream builder has a lifecycle, where it starts in a building
      * phase, during which elements can be added, and then transitions to a
      * built phase, after which elements may not be added.  The built phase
-     * begins when the {@link #build()}} method is called, which creates an
+     * begins when the {@link #build()} method is called, which creates an
      * ordered stream whose elements are the elements that were added to the
      * stream builder, in the order they were added.
      *
@@ -155,7 +155,7 @@
      * <p>A stream builder has a lifecycle, where it starts in a building
      * phase, during which elements can be added, and then transitions to a
      * built phase, after which elements may not be added.  The built phase
-     * begins when the {@link #build()}} method is called, which creates an
+     * begins when the {@link #build()} method is called, which creates an
      * ordered stream whose elements are the elements that were added to the
      * stream builder, in the order they were added.
      *
@@ -209,6 +209,13 @@
     /**
      * A mutable builder for a {@code DoubleStream}.
      *
+     * <p>A stream builder has a lifecycle, where it starts in a building
+     * phase, during which elements can be added, and then transitions to a
+     * built phase, after which elements may not be added.  The built phase
+     * begins when the {@link #build()} method is called, which creates an
+     * ordered stream whose elements are the elements that were added to the
+     * stream builder, in the order they were added.
+     *
      * @see LongStream#builder()
      * @since 1.8
      */
@@ -217,13 +224,6 @@
         /**
          * Adds an element to the stream being built.
          *
-         * <p>A stream builder  has a lifecycle, where it starts in a building
-         * phase, during which elements can be added, and then transitions to a
-         * built phase, after which elements may not be added.  The built phase
-         * begins when the {@link #build()}} method is called, which creates an
-         * ordered stream whose elements are the elements that were added to the
-         * stream builder, in the order they were added.
-         *
          * @throws IllegalStateException if the builder has already transitioned
          * to the built state
          */
--- a/jdk/src/share/classes/java/util/stream/StreamSupport.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/stream/StreamSupport.java	Mon Jun 10 10:38:33 2013 +0100
@@ -41,7 +41,11 @@
  *
  * @since 1.8
  */
-public class StreamSupport {
+public final class StreamSupport {
+
+    // Suppresses default constructor, ensuring non-instantiability.
+    private StreamSupport() {}
+
     /**
      * Creates a new sequential {@code Stream} from a {@code Spliterator}.
      *
@@ -50,7 +54,7 @@
      *
      * <p>It is strongly recommended the spliterator report a characteristic of
      * {@code IMMUTABLE} or {@code CONCURRENT}, or be
-     * <a href="Spliterator.html#binding">late-binding</a>.  Otherwise,
+     * <a href="../Spliterator.html#binding">late-binding</a>.  Otherwise,
      * {@link #stream(Supplier, int)} should be used to
      * reduce the scope of potential interference with the source.  See
      * <a href="package-summary.html#Non-Interference">Non-Interference</a> for
@@ -75,7 +79,7 @@
      *
      * <p>It is strongly recommended the spliterator report a characteristic of
      * {@code IMMUTABLE} or {@code CONCURRENT}, or be
-     * <a href="Spliterator.html#binding">late-binding</a>.  Otherwise,
+     * <a href="../Spliterator.html#binding">late-binding</a>.  Otherwise,
      * {@link #stream(Supplier, int)} should be used to
      * reduce the scope of potential interference with the source.  See
      * <a href="package-summary.html#Non-Interference">Non-Interference</a> for
@@ -102,7 +106,7 @@
      *
      * <p>For spliterators that report a characteristic of {@code IMMUTABLE}
      * or {@code CONCURRENT}, or that are
-     * <a href="Spliterator.html#binding">late-binding</a>, it is likely
+     * <a href="../Spliterator.html#binding">late-binding</a>, it is likely
      * more efficient to use {@link #stream(java.util.Spliterator)} instead.
      * The use of a {@code Supplier} in this form provides a level of
      * indirection that reduces the scope of potential interference with the
@@ -138,7 +142,7 @@
      *
      * <p>For spliterators that report a characteristic of {@code IMMUTABLE}
      * or {@code CONCURRENT}, or that are
-     * <a href="Spliterator.html#binding">late-binding</a>, it is likely
+     * <a href="../Spliterator.html#binding">late-binding</a>, it is likely
      * more efficient to use {@link #stream(Spliterator)} instead.
      * The use of a {@code Supplier} in this form provides a level of
      * indirection that reduces the scope of potential interference with the
@@ -172,7 +176,7 @@
      *
      * <p>It is strongly recommended the spliterator report a characteristic of
      * {@code IMMUTABLE} or {@code CONCURRENT}, or be
-     * <a href="Spliterator.html#binding">late-binding</a>.  Otherwise,
+     * <a href="../Spliterator.html#binding">late-binding</a>.  Otherwise,
      * {@link #stream(Supplier, int)}} should be used to
      * reduce the scope of potential interference with the source.  See
      * <a href="package-summary.html#Non-Interference">Non-Interference</a> for
@@ -195,7 +199,7 @@
      *
      * <p>It is strongly recommended the spliterator report a characteristic of
      * {@code IMMUTABLE} or {@code CONCURRENT}, or be
-     * <a href="Spliterator.html#binding">late-binding</a>.  Otherwise,
+     * <a href="../Spliterator.html#binding">late-binding</a>.  Otherwise,
      * {@link #stream(Supplier, int)}} should be used to
      * reduce the scope of potential interference with the source.  See
      * <a href="package-summary.html#Non-Interference">Non-Interference</a> for
@@ -220,7 +224,7 @@
      *
      * <p>For spliterators that report a characteristic of {@code IMMUTABLE}
      * or {@code CONCURRENT}, or that are
-     * <a href="Spliterator.html#binding">late-binding</a>, it is likely
+     * <a href="../Spliterator.html#binding">late-binding</a>, it is likely
      * more efficient to use {@link #intStream(Spliterator.OfInt)} instead.
      * The use of a {@code Supplier} in this form provides a level of
      * indirection that reduces the scope of potential interference with the
@@ -254,7 +258,7 @@
      *
      * <p>For spliterators that report a characteristic of {@code IMMUTABLE}
      * or {@code CONCURRENT}, or that are
-     * <a href="Spliterator.html#binding">late-binding</a>, it is likely
+     * <a href="../Spliterator.html#binding">late-binding</a>, it is likely
      * more efficient to use {@link #intStream(Spliterator.OfInt)} instead.
      * The use of a {@code Supplier} in this form provides a level of
      * indirection that reduces the scope of potential interference with the
@@ -286,7 +290,7 @@
      *
      * <p>It is strongly recommended the spliterator report a characteristic of
      * {@code IMMUTABLE} or {@code CONCURRENT}, or be
-     * <a href="Spliterator.html#binding">late-binding</a>.  Otherwise,
+     * <a href="../Spliterator.html#binding">late-binding</a>.  Otherwise,
      * {@link #stream(Supplier, int)} should be used to
      * reduce the scope of potential interference with the source.  See
      * <a href="package-summary.html#Non-Interference">Non-Interference</a> for
@@ -310,7 +314,7 @@
      *
      * <p>It is strongly recommended the spliterator report a characteristic of
      * {@code IMMUTABLE} or {@code CONCURRENT}, or be
-     * <a href="Spliterator.html#binding">late-binding</a>.  Otherwise,
+     * <a href="../Spliterator.html#binding">late-binding</a>.  Otherwise,
      * {@link #stream(Supplier, int)} should be used to
      * reduce the scope of potential interference with the source.  See
      * <a href="package-summary.html#Non-Interference">Non-Interference</a> for
@@ -335,7 +339,7 @@
      *
      * <p>For spliterators that report a characteristic of {@code IMMUTABLE}
      * or {@code CONCURRENT}, or that are
-     * <a href="Spliterator.html#binding">late-binding</a>, it is likely
+     * <a href="../Spliterator.html#binding">late-binding</a>, it is likely
      * more efficient to use {@link #longStream(Spliterator.OfLong)} instead.
      * The use of a {@code Supplier} in this form provides a level of
      * indirection that reduces the scope of potential interference with the
@@ -369,7 +373,7 @@
      *
      * <p>For spliterators that report a characteristic of {@code IMMUTABLE}
      * or {@code CONCURRENT}, or that are
-     * <a href="Spliterator.html#binding">late-binding</a>, it is likely
+     * <a href="../Spliterator.html#binding">late-binding</a>, it is likely
      * more efficient to use {@link #longStream(Spliterator.OfLong)} instead.
      * The use of a {@code Supplier} in this form provides a level of
      * indirection that reduces the scope of potential interference with the
@@ -402,7 +406,7 @@
      *
      * <p>It is strongly recommended the spliterator report a characteristic of
      * {@code IMMUTABLE} or {@code CONCURRENT}, or be
-     * <a href="Spliterator.html#binding">late-binding</a>.  Otherwise,
+     * <a href="../Spliterator.html#binding">late-binding</a>.  Otherwise,
      * {@link #stream(Supplier, int)} should be used to
      * reduce the scope of potential interference with the source.  See
      * <a href="package-summary.html#Non-Interference">Non-Interference</a> for
@@ -426,7 +430,7 @@
      *
      * <p>It is strongly recommended the spliterator report a characteristic of
      * {@code IMMUTABLE} or {@code CONCURRENT}, or be
-     * <a href="Spliterator.html#binding">late-binding</a>.  Otherwise,
+     * <a href="../Spliterator.html#binding">late-binding</a>.  Otherwise,
      * {@link #stream(Supplier, int)} should be used to
      * reduce the scope of potential interference with the source.  See
      * <a href="package-summary.html#Non-Interference">Non-Interference</a> for
@@ -451,7 +455,7 @@
      * <p>
      * For spliterators that report a characteristic of {@code IMMUTABLE}
      * or {@code CONCURRENT}, or that are
-     * <a href="Spliterator.html#binding">late-binding</a>, it is likely
+     * <a href="../Spliterator.html#binding">late-binding</a>, it is likely
      * more efficient to use {@link #doubleStream(Spliterator.OfDouble)} instead.
      * The use of a {@code Supplier} in this form provides a level of
      * indirection that reduces the scope of potential interference with the
@@ -485,7 +489,7 @@
      *
      * <p>For spliterators that report a characteristic of {@code IMMUTABLE}
      * or {@code CONCURRENT}, or that are
-     * <a href="Spliterator.html#binding">late-binding</a>, it is likely
+     * <a href="../Spliterator.html#binding">late-binding</a>, it is likely
      * more efficient to use {@link #doubleStream(Spliterator.OfDouble)} instead.
      * The use of a {@code Supplier} in this form provides a level of
      * indirection that reduces the scope of potential interference with the
--- a/jdk/src/share/classes/java/util/zip/ZipConstants.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/zip/ZipConstants.java	Mon Jun 10 10:38:33 2013 +0100
@@ -69,6 +69,14 @@
     static final int EXTLEN = 12;       // uncompressed size
 
     /*
+     * Extra field header ID
+     */
+    static final int  EXTID_ZIP64 = 0x0001;      // Zip64
+    static final int  EXTID_NTFS  = 0x000a;      // NTFS
+    static final int  EXTID_UNIX  = 0x000d;      // UNIX
+    static final int  EXTID_EXTT  = 0x5455;      // Info-ZIP Extended Timestamp
+
+    /*
      * Central directory (CEN) header field offsets
      */
     static final int CENVEM = 4;        // version made by
--- a/jdk/src/share/classes/java/util/zip/ZipEntry.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/zip/ZipEntry.java	Mon Jun 10 10:38:33 2013 +0100
@@ -25,8 +25,6 @@
 
 package java.util.zip;
 
-import java.util.Date;
-
 /**
  * This class is used to represent a ZIP file entry.
  *
@@ -35,7 +33,7 @@
 public
 class ZipEntry implements ZipConstants, Cloneable {
     String name;        // entry name
-    long time = -1;     // modification time (in DOS time)
+    long mtime = -1;    // last modification time
     long crc = -1;      // crc-32 of entry data
     long size = -1;     // uncompressed size of entry data
     long csize = -1;    // compressed size of entry data
@@ -79,7 +77,7 @@
      */
     public ZipEntry(ZipEntry e) {
         name = e.name;
-        time = e.time;
+        mtime = e.mtime;
         crc = e.crc;
         size = e.size;
         csize = e.csize;
@@ -89,7 +87,7 @@
         comment = e.comment;
     }
 
-    /*
+    /**
      * Creates a new un-initialized zip entry
      */
     ZipEntry() {}
@@ -103,22 +101,26 @@
     }
 
     /**
-     * Sets the modification time of the entry.
-     * @param time the entry modification time in number of milliseconds
-     *             since the epoch
+     * Sets the last modification time of the entry.
+     *
+     * @param time the last modification time of the entry in milliseconds since the epoch
      * @see #getTime()
      */
     public void setTime(long time) {
-        this.time = javaToDosTime(time);
+        this.mtime = time;
     }
 
     /**
-     * Returns the modification time of the entry, or -1 if not specified.
-     * @return the modification time of the entry, or -1 if not specified
+     * Returns the last modification time of the entry.
+     * <p> The last modificatin time may come from zip entry's extensible
+     * data field {@code NTFS} or {@code Info-ZIP Extended Timestamp}, if
+     * the entry is read from {@link ZipInputStream} or {@link ZipFile}.
+     *
+     * @return the last modification time of the entry, or -1 if not specified
      * @see #setTime(long)
      */
     public long getTime() {
-        return time != -1 ? dosToJavaTime(time) : -1;
+        return mtime;
     }
 
     /**
@@ -277,35 +279,6 @@
         return getName();
     }
 
-    /*
-     * Converts DOS time to Java time (number of milliseconds since epoch).
-     */
-    private static long dosToJavaTime(long dtime) {
-        @SuppressWarnings("deprecation") // Use of date constructor.
-        Date d = new Date((int)(((dtime >> 25) & 0x7f) + 80),
-                          (int)(((dtime >> 21) & 0x0f) - 1),
-                          (int)((dtime >> 16) & 0x1f),
-                          (int)((dtime >> 11) & 0x1f),
-                          (int)((dtime >> 5) & 0x3f),
-                          (int)((dtime << 1) & 0x3e));
-        return d.getTime();
-    }
-
-    /*
-     * Converts Java time to DOS time.
-     */
-    @SuppressWarnings("deprecation") // Use of date methods
-    private static long javaToDosTime(long time) {
-        Date d = new Date(time);
-        int year = d.getYear() + 1900;
-        if (year < 1980) {
-            return (1 << 21) | (1 << 16);
-        }
-        return (year - 1980) << 25 | (d.getMonth() + 1) << 21 |
-               d.getDate() << 16 | d.getHours() << 11 | d.getMinutes() << 5 |
-               d.getSeconds() >> 1;
-    }
-
     /**
      * Returns the hash code value for this entry.
      */
--- a/jdk/src/share/classes/java/util/zip/ZipFile.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/zip/ZipFile.java	Mon Jun 10 10:38:33 2013 +0100
@@ -46,6 +46,7 @@
 import java.util.stream.StreamSupport;
 
 import static java.util.zip.ZipConstants64.*;
+import static java.util.zip.ZipUtils.*;
 
 /**
  * This class is used to read entries from a zip file.
@@ -566,12 +567,44 @@
                 e.name = zc.toString(bname, bname.length);
             }
         }
-        e.time = getEntryTime(jzentry);
         e.crc = getEntryCrc(jzentry);
         e.size = getEntrySize(jzentry);
         e. csize = getEntryCSize(jzentry);
         e.method = getEntryMethod(jzentry);
         e.extra = getEntryBytes(jzentry, JZENTRY_EXTRA);
+        if (e.extra != null) {
+            byte[] extra = e.extra;
+            int len = e.extra.length;
+            int off = 0;
+            while (off + 4 < len) {
+                int pos = off;
+                int tag = get16(extra, pos);
+                int sz = get16(extra, pos + 2);
+                pos += 4;
+                if (pos + sz > len)         // invalid data
+                    break;
+                switch (tag) {
+                case EXTID_NTFS:
+                    pos += 4;    // reserved 4 bytes
+                    if (get16(extra, pos) !=  0x0001 || get16(extra, pos + 2) != 24)
+                        break;
+                    e.mtime  = winToJavaTime(get64(extra, pos + 4));
+                    break;
+                case EXTID_EXTT:
+                    int flag = Byte.toUnsignedInt(extra[pos++]);
+                    if ((flag & 0x1) != 0) {
+                        e.mtime = unixToJavaTime(get32(extra, pos));
+                        pos += 4;
+                    }
+                    break;
+                default:    // unknown tag
+                }
+                off += (sz + 4);
+            }
+        }
+        if (e.mtime == -1) {
+            e.mtime = dosToJavaTime(getEntryTime(jzentry));
+        }
         byte[] bcomm = getEntryBytes(jzentry, JZENTRY_COMMENT);
         if (bcomm == null) {
             e.comment = null;
--- a/jdk/src/share/classes/java/util/zip/ZipInputStream.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/zip/ZipInputStream.java	Mon Jun 10 10:38:33 2013 +0100
@@ -32,6 +32,7 @@
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 import static java.util.zip.ZipConstants64.*;
+import static java.util.zip.ZipUtils.*;
 
 /**
  * This class implements an input stream filter for reading files in the
@@ -302,7 +303,7 @@
             throw new ZipException("encrypted ZIP entry not supported");
         }
         e.method = get16(tmpbuf, LOCHOW);
-        e.time = get32(tmpbuf, LOCTIM);
+        e.mtime = dosToJavaTime(get32(tmpbuf, LOCTIM));
         if ((flag & 8) == 8) {
             /* "Data Descriptor" present */
             if (e.method != DEFLATED) {
@@ -316,32 +317,51 @@
         }
         len = get16(tmpbuf, LOCEXT);
         if (len > 0) {
-            byte[] bb = new byte[len];
-            readFully(bb, 0, len);
-            e.setExtra(bb);
+            byte[] extra = new byte[len];
+            readFully(extra, 0, len);
+            e.setExtra(extra);
             // extra fields are in "HeaderID(2)DataSize(2)Data... format
-            if (e.csize == ZIP64_MAGICVAL || e.size == ZIP64_MAGICVAL) {
-                int off = 0;
-                while (off + 4 < len) {
-                    int sz = get16(bb, off + 2);
-                    if (get16(bb, off) == ZIP64_EXTID) {
-                        off += 4;
-                        // LOC extra zip64 entry MUST include BOTH original and
-                        // compressed file size fields
-                        if (sz < 16 || (off + sz) > len ) {
-                            // Invalid zip64 extra fields, simply skip. Even it's
-                            // rare, it's possible the entry size happens to be
-                            // the magic value and it "accidnetly" has some bytes
-                            // in extra match the id.
-                            return e;
-                        }
-                        e.size = get64(bb, off);
-                        e.csize = get64(bb, off + 8);
+            int off = 0;
+            while (off + 4 < len) {
+                int pos = off;
+                int tag = get16(extra, pos);
+                int sz = get16(extra, pos + 2);
+                pos += 4;
+                if (pos + sz > len)         // invalid data
+                    break;
+                switch (tag) {
+                case EXTID_ZIP64 :
+                    // LOC extra zip64 entry MUST include BOTH original and
+                    // compressed file size fields.
+                    //
+                    // If invalid zip64 extra fields, simply skip. Even it's
+                    // rare, it's possible the entry size happens to be
+                    // the magic value and it "accidently" has some bytes
+                    // in extra match the id.
+                    if (sz >= 16 && (pos + sz) <= len ) {
+                        e.size = get64(extra, pos);
+                        e.csize = get64(extra, pos + 8);
+                    }
+                    break;
+                case EXTID_NTFS:
+                    pos += 4;    // reserved 4 bytes
+                    if (get16(extra, pos) !=  0x0001 || get16(extra, pos + 2) != 24)
                         break;
+                    // override the loc field, NTFS time has 'microsecond' granularity
+                    e.mtime  = winToJavaTime(get64(extra, pos + 4));
+                    break;
+                case EXTID_EXTT:
+                    int flag = Byte.toUnsignedInt(extra[pos++]);
+                    if ((flag & 0x1) != 0) {
+                        e.mtime = unixToJavaTime(get32(extra, pos));
+                        pos += 4;
                     }
-                    off += (sz + 4);
+                    break;
+                default:    // unknown tag
                 }
+                off += (sz + 4);
             }
+
         }
         return e;
     }
@@ -430,27 +450,4 @@
         }
     }
 
-    /*
-     * Fetches unsigned 16-bit value from byte array at specified offset.
-     * The bytes are assumed to be in Intel (little-endian) byte order.
-     */
-    private static final int get16(byte b[], int off) {
-        return Byte.toUnsignedInt(b[off]) | (Byte.toUnsignedInt(b[off+1]) << 8);
-    }
-
-    /*
-     * Fetches unsigned 32-bit value from byte array at specified offset.
-     * The bytes are assumed to be in Intel (little-endian) byte order.
-     */
-    private static final long get32(byte b[], int off) {
-        return (get16(b, off) | ((long)get16(b, off+2) << 16)) & 0xffffffffL;
-    }
-
-    /*
-     * Fetches signed 64-bit value from byte array at specified offset.
-     * The bytes are assumed to be in Intel (little-endian) byte order.
-     */
-    private static final long get64(byte b[], int off) {
-        return get32(b, off) | (get32(b, off+4) << 32);
-    }
 }
--- a/jdk/src/share/classes/java/util/zip/ZipOutputStream.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/zip/ZipOutputStream.java	Mon Jun 10 10:38:33 2013 +0100
@@ -32,6 +32,7 @@
 import java.util.Vector;
 import java.util.HashSet;
 import static java.util.zip.ZipConstants64.*;
+import static java.util.zip.ZipUtils.*;
 
 /**
  * This class implements an output stream filter for writing files in the
@@ -190,7 +191,7 @@
         if (current != null) {
             closeEntry();       // close previous entry
         }
-        if (e.time == -1) {
+        if (e.mtime == -1) {
             e.setTime(System.currentTimeMillis());
         }
         if (e.method == -1) {
@@ -382,16 +383,25 @@
     private void writeLOC(XEntry xentry) throws IOException {
         ZipEntry e = xentry.entry;
         int flag = e.flag;
+        boolean hasZip64 = false;
         int elen = (e.extra != null) ? e.extra.length : 0;
-        boolean hasZip64 = false;
-
+        int eoff = 0;
+        boolean foundEXTT = false;      // if EXTT already present
+                                        // do nothing.
+        while (eoff + 4 < elen) {
+            int tag = get16(e.extra, eoff);
+            int sz = get16(e.extra, eoff + 2);
+            if (tag == EXTID_EXTT) {
+                foundEXTT = true;
+            }
+            eoff += (4 + sz);
+        }
         writeInt(LOCSIG);               // LOC header signature
-
         if ((flag & 8) == 8) {
             writeShort(version(e));     // version needed to extract
             writeShort(flag);           // general purpose bit flag
             writeShort(e.method);       // compression method
-            writeInt(e.time);           // last modification time
+            writeInt(javaToDosTime(e.mtime)); // last modification time
 
             // store size, uncompressed size, and crc-32 in data descriptor
             // immediately following compressed entry data
@@ -407,7 +417,7 @@
             }
             writeShort(flag);           // general purpose bit flag
             writeShort(e.method);       // compression method
-            writeInt(e.time);           // last modification time
+            writeInt(javaToDosTime(e.mtime)); // last modification time
             writeInt(e.crc);            // crc-32
             if (hasZip64) {
                 writeInt(ZIP64_MAGICVAL);
@@ -420,6 +430,8 @@
         }
         byte[] nameBytes = zc.getBytes(e.name);
         writeShort(nameBytes.length);
+        if (!foundEXTT)
+            elen += 9;              // use Info-ZIP's ext time in extra
         writeShort(elen);
         writeBytes(nameBytes, 0, nameBytes.length);
         if (hasZip64) {
@@ -428,6 +440,12 @@
             writeLong(e.size);
             writeLong(e.csize);
         }
+        if (!foundEXTT) {
+            writeShort(EXTID_EXTT);
+            writeShort(5);          // size for the folowing data block
+            writeByte(0x1);         // flags byte, mtime only
+            writeInt(javaToUnixTime(e.mtime));
+        }
         if (e.extra != null) {
             writeBytes(e.extra, 0, e.extra.length);
         }
@@ -457,25 +475,25 @@
         ZipEntry e  = xentry.entry;
         int flag = e.flag;
         int version = version(e);
-
         long csize = e.csize;
         long size = e.size;
         long offset = xentry.offset;
-        int e64len = 0;
+        int elenZIP64 = 0;
         boolean hasZip64 = false;
+
         if (e.csize >= ZIP64_MAGICVAL) {
             csize = ZIP64_MAGICVAL;
-            e64len += 8;              // csize(8)
+            elenZIP64 += 8;              // csize(8)
             hasZip64 = true;
         }
         if (e.size >= ZIP64_MAGICVAL) {
             size = ZIP64_MAGICVAL;    // size(8)
-            e64len += 8;
+            elenZIP64 += 8;
             hasZip64 = true;
         }
         if (xentry.offset >= ZIP64_MAGICVAL) {
             offset = ZIP64_MAGICVAL;
-            e64len += 8;              // offset(8)
+            elenZIP64 += 8;              // offset(8)
             hasZip64 = true;
         }
         writeInt(CENSIG);           // CEN header signature
@@ -488,18 +506,32 @@
         }
         writeShort(flag);           // general purpose bit flag
         writeShort(e.method);       // compression method
-        writeInt(e.time);           // last modification time
+        writeInt(javaToDosTime(e.mtime)); // last modification time
         writeInt(e.crc);            // crc-32
         writeInt(csize);            // compressed size
         writeInt(size);             // uncompressed size
         byte[] nameBytes = zc.getBytes(e.name);
         writeShort(nameBytes.length);
+
+        int elen = (e.extra != null) ? e.extra.length : 0;
+        int eoff = 0;
+        boolean foundEXTT = false;  // if EXTT already present
+                                    // do nothing.
+        while (eoff + 4 < elen) {
+            int tag = get16(e.extra, eoff);
+            int sz = get16(e.extra, eoff + 2);
+            if (tag == EXTID_EXTT) {
+                foundEXTT = true;
+            }
+            eoff += (4 + sz);
+        }
         if (hasZip64) {
             // + headid(2) + datasize(2)
-            writeShort(e64len + 4 + (e.extra != null ? e.extra.length : 0));
-        } else {
-            writeShort(e.extra != null ? e.extra.length : 0);
+            elen += (elenZIP64 + 4);
         }
+        if (!foundEXTT)
+            elen += 9;              // Info-ZIP's Extended Timestamp
+        writeShort(elen);
         byte[] commentBytes;
         if (e.comment != null) {
             commentBytes = zc.getBytes(e.comment);
@@ -515,7 +547,7 @@
         writeBytes(nameBytes, 0, nameBytes.length);
         if (hasZip64) {
             writeShort(ZIP64_EXTID);// Zip64 extra
-            writeShort(e64len);
+            writeShort(elenZIP64);
             if (size == ZIP64_MAGICVAL)
                 writeLong(e.size);
             if (csize == ZIP64_MAGICVAL)
@@ -523,6 +555,12 @@
             if (offset == ZIP64_MAGICVAL)
                 writeLong(xentry.offset);
         }
+        if (!foundEXTT) {
+            writeShort(EXTID_EXTT);
+            writeShort(5);
+            writeByte(0x1);            // flags byte
+            writeInt(javaToUnixTime(e.mtime));
+        }
         if (e.extra != null) {
             writeBytes(e.extra, 0, e.extra.length);
         }
@@ -589,6 +627,15 @@
     }
 
     /*
+     * Writes a 8-bit byte to the output stream.
+     */
+    private void writeByte(int v) throws IOException {
+        OutputStream out = this.out;
+        out.write(v & 0xff);
+        written += 1;
+    }
+
+    /*
      * Writes a 16-bit short to the output stream in little-endian byte order.
      */
     private void writeShort(int v) throws IOException {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/util/zip/ZipUtils.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
+
+class ZipUtils {
+
+    // used to adjust values between Windows and java epoch
+    private static final long WINDOWS_EPOCH_IN_MICROSECONDS = -11644473600000000L;
+
+    /**
+     * Converts Windows time (in microseconds, UTC/GMT) time to Java time.
+     */
+    public static final long winToJavaTime(long wtime) {
+        return TimeUnit.MILLISECONDS.convert(
+               wtime / 10 + WINDOWS_EPOCH_IN_MICROSECONDS, TimeUnit.MICROSECONDS);
+    }
+
+    /**
+     * Converts Java time to Windows time.
+     */
+    public static final long javaToWinTime(long time) {
+        return (TimeUnit.MICROSECONDS.convert(time, TimeUnit.MILLISECONDS)
+               - WINDOWS_EPOCH_IN_MICROSECONDS) * 10;
+    }
+
+    /**
+     * Converts "standard Unix time"(in seconds, UTC/GMT) to Java time
+     */
+    public static final long unixToJavaTime(long utime) {
+        return TimeUnit.MILLISECONDS.convert(utime, TimeUnit.SECONDS);
+    }
+
+    /**
+     * Converts Java time to "standard Unix time".
+     */
+    public static final long javaToUnixTime(long time) {
+        return TimeUnit.SECONDS.convert(time, TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * Converts DOS time to Java time (number of milliseconds since epoch).
+     */
+    public static long dosToJavaTime(long dtime) {
+        @SuppressWarnings("deprecation") // Use of date constructor.
+        Date d = new Date((int)(((dtime >> 25) & 0x7f) + 80),
+                          (int)(((dtime >> 21) & 0x0f) - 1),
+                          (int)((dtime >> 16) & 0x1f),
+                          (int)((dtime >> 11) & 0x1f),
+                          (int)((dtime >> 5) & 0x3f),
+                          (int)((dtime << 1) & 0x3e));
+        return d.getTime();
+    }
+
+    /**
+     * Converts Java time to DOS time.
+     */
+    @SuppressWarnings("deprecation") // Use of date methods
+    public static long javaToDosTime(long time) {
+        Date d = new Date(time);
+        int year = d.getYear() + 1900;
+        if (year < 1980) {
+            return (1 << 21) | (1 << 16);
+        }
+        return (year - 1980) << 25 | (d.getMonth() + 1) << 21 |
+               d.getDate() << 16 | d.getHours() << 11 | d.getMinutes() << 5 |
+               d.getSeconds() >> 1;
+    }
+
+
+    /**
+     * Fetches unsigned 16-bit value from byte array at specified offset.
+     * The bytes are assumed to be in Intel (little-endian) byte order.
+     */
+    public static final int get16(byte b[], int off) {
+        return Byte.toUnsignedInt(b[off]) | (Byte.toUnsignedInt(b[off+1]) << 8);
+    }
+
+    /**
+     * Fetches unsigned 32-bit value from byte array at specified offset.
+     * The bytes are assumed to be in Intel (little-endian) byte order.
+     */
+    public static final long get32(byte b[], int off) {
+        return (get16(b, off) | ((long)get16(b, off+2) << 16)) & 0xffffffffL;
+    }
+
+    /**
+     * Fetches signed 64-bit value from byte array at specified offset.
+     * The bytes are assumed to be in Intel (little-endian) byte order.
+     */
+    public static final long get64(byte b[], int off) {
+        return get32(b, off) | (get32(b, off+4) << 32);
+    }
+
+}
--- a/jdk/src/share/classes/javax/crypto/Cipher.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/javax/crypto/Cipher.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1158,6 +1158,9 @@
      * determined from the given key, or if the given key has a keysize that
      * exceeds the maximum allowable keysize (as determined from the
      * configured jurisdiction policy files).
+     * @throws UnsupportedOperationException if (@code opmode} is
+     * {@code WRAP_MODE} or {@code UNWRAP_MODE} but the mode is not implemented
+     * by the underlying {@code CipherSpi}.
      */
     public final void init(int opmode, Key key) throws InvalidKeyException {
         init(opmode, key, JceSecurity.RANDOM);
@@ -1208,6 +1211,9 @@
      * determined from the given key, or if the given key has a keysize that
      * exceeds the maximum allowable keysize (as determined from the
      * configured jurisdiction policy files).
+     * @throws UnsupportedOperationException if (@code opmode} is
+     * {@code WRAP_MODE} or {@code UNWRAP_MODE} but the mode is not implemented
+     * by the underlying {@code CipherSpi}.
      */
     public final void init(int opmode, Key key, SecureRandom random)
             throws InvalidKeyException
@@ -1285,6 +1291,9 @@
      * algorithm parameters imply a cryptographic strength that would exceed
      * the legal limits (as determined from the configured jurisdiction
      * policy files).
+     * @throws UnsupportedOperationException if (@code opmode} is
+     * {@code WRAP_MODE} or {@code UNWRAP_MODE} but the mode is not implemented
+     * by the underlying {@code CipherSpi}.
      */
     public final void init(int opmode, Key key, AlgorithmParameterSpec params)
             throws InvalidKeyException, InvalidAlgorithmParameterException
@@ -1343,6 +1352,9 @@
      * algorithm parameters imply a cryptographic strength that would exceed
      * the legal limits (as determined from the configured jurisdiction
      * policy files).
+     * @throws UnsupportedOperationException if (@code opmode} is
+     * {@code WRAP_MODE} or {@code UNWRAP_MODE} but the mode is not implemented
+     * by the underlying {@code CipherSpi}.
      */
     public final void init(int opmode, Key key, AlgorithmParameterSpec params,
                            SecureRandom random)
@@ -1416,6 +1428,9 @@
      * algorithm parameters imply a cryptographic strength that would exceed
      * the legal limits (as determined from the configured jurisdiction
      * policy files).
+     * @throws UnsupportedOperationException if (@code opmode} is
+     * {@code WRAP_MODE} or {@code UNWRAP_MODE} but the mode is not implemented
+     * by the underlying {@code CipherSpi}.
      */
     public final void init(int opmode, Key key, AlgorithmParameters params)
             throws InvalidKeyException, InvalidAlgorithmParameterException
@@ -1474,6 +1489,9 @@
      * algorithm parameters imply a cryptographic strength that would exceed
      * the legal limits (as determined from the configured jurisdiction
      * policy files).
+     * @throws UnsupportedOperationException if (@code opmode} is
+     * {@code WRAP_MODE} or {@code UNWRAP_MODE} but the mode is not implemented
+     * by the underlying {@code CipherSpi}.
      */
     public final void init(int opmode, Key key, AlgorithmParameters params,
                            SecureRandom random)
@@ -1552,6 +1570,9 @@
      * in the given certificate has a keysize that exceeds the maximum
      * allowable keysize (as determined by the configured jurisdiction policy
      * files).
+     * @throws UnsupportedOperationException if (@code opmode} is
+     * {@code WRAP_MODE} or {@code UNWRAP_MODE} but the mode is not implemented
+     * by the underlying {@code CipherSpi}.
      */
     public final void init(int opmode, Certificate certificate)
             throws InvalidKeyException
@@ -1619,6 +1640,9 @@
      * in the given certificate has a keysize that exceeds the maximum
      * allowable keysize (as determined by the configured jurisdiction policy
      * files).
+     * @throws UnsupportedOperationException if (@code opmode} is
+     * {@code WRAP_MODE} or {@code UNWRAP_MODE} but the mode is not implemented
+     * by the underlying {@code CipherSpi}.
      */
     public final void init(int opmode, Certificate certificate,
                            SecureRandom random)
@@ -2410,6 +2434,9 @@
      * @exception InvalidKeyException if it is impossible or unsafe to
      * wrap the key with this cipher (e.g., a hardware protected key is
      * being passed to a software-only cipher).
+     *
+     * @throws UnsupportedOperationException if the corresponding method in the
+     * {@code CipherSpi} is not supported.
      */
     public final byte[] wrap(Key key)
             throws IllegalBlockSizeException, InvalidKeyException {
@@ -2451,6 +2478,9 @@
      * @exception InvalidKeyException if <code>wrappedKey</code> does not
      * represent a wrapped key of type <code>wrappedKeyType</code> for
      * the <code>wrappedKeyAlgorithm</code>.
+     *
+     * @throws UnsupportedOperationException if the corresponding method in the
+     * {@code CipherSpi} is not supported.
      */
     public final Key unwrap(byte[] wrappedKey,
                             String wrappedKeyAlgorithm,
--- a/jdk/src/share/classes/javax/crypto/CipherInputStream.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/javax/crypto/CipherInputStream.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -86,6 +86,8 @@
     private int ostart = 0;
     // the offset pointing to the last "new" byte
     private int ofinish = 0;
+    // stream status
+    private boolean closed = false;
 
     /**
      * private convenience function.
@@ -293,14 +295,17 @@
      * @since JCE1.2
      */
     public void close() throws IOException {
+        if (closed) {
+            return;
+        }
+
+        closed = true;
         input.close();
         try {
             // throw away the unprocessed data
             cipher.doFinal();
         }
-        catch (BadPaddingException ex) {
-        }
-        catch (IllegalBlockSizeException ex) {
+        catch (BadPaddingException | IllegalBlockSizeException ex) {
         }
         ostart = 0;
         ofinish = 0;
--- a/jdk/src/share/classes/javax/crypto/CipherOutputStream.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/javax/crypto/CipherOutputStream.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -74,6 +74,9 @@
     // the buffer holding data ready to be written out
     private byte[] obuffer;
 
+    // stream status
+    private boolean closed = false;
+
     /**
      *
      * Constructs a CipherOutputStream from an OutputStream and a
@@ -198,11 +201,14 @@
      * @since      JCE1.2
      */
     public void close() throws IOException {
+        if (closed) {
+            return;
+        }
+
+        closed = true;
         try {
             obuffer = cipher.doFinal();
-        } catch (IllegalBlockSizeException e) {
-            obuffer = null;
-        } catch (BadPaddingException e) {
+        } catch (IllegalBlockSizeException | BadPaddingException e) {
             obuffer = null;
         }
         try {
--- a/jdk/src/share/classes/javax/crypto/CipherSpi.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/javax/crypto/CipherSpi.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -347,6 +347,9 @@
      * initializing this cipher, or requires
      * algorithm parameters that cannot be
      * determined from the given key.
+     * @throws UnsupportedOperationException if {@code opmode} is
+     * {@code WRAP_MODE} or {@code UNWRAP_MODE} is not implemented
+     * by the cipher.
      */
     protected abstract void engineInit(int opmode, Key key,
                                        SecureRandom random)
@@ -399,6 +402,9 @@
      * parameters are inappropriate for this cipher,
      * or if this cipher requires
      * algorithm parameters and <code>params</code> is null.
+     * @throws UnsupportedOperationException if {@code opmode} is
+     * {@code WRAP_MODE} or {@code UNWRAP_MODE} is not implemented
+     * by the cipher.
      */
     protected abstract void engineInit(int opmode, Key key,
                                        AlgorithmParameterSpec params,
@@ -452,6 +458,9 @@
      * parameters are inappropriate for this cipher,
      * or if this cipher requires
      * algorithm parameters and <code>params</code> is null.
+     * @throws UnsupportedOperationException if {@code opmode} is
+     * {@code WRAP_MODE} or {@code UNWRAP_MODE} is not implemented
+     * by the cipher.
      */
     protected abstract void engineInit(int opmode, Key key,
                                        AlgorithmParameters params,
@@ -863,6 +872,8 @@
      * @exception InvalidKeyException if it is impossible or unsafe to
      * wrap the key with this cipher (e.g., a hardware protected key is
      * being passed to a software-only cipher).
+     *
+     * @throws UnsupportedOperationException if this method is not supported.
      */
     protected byte[] engineWrap(Key key)
         throws IllegalBlockSizeException, InvalidKeyException
@@ -899,6 +910,8 @@
      * @exception InvalidKeyException if <code>wrappedKey</code> does not
      * represent a wrapped key of type <code>wrappedKeyType</code> for
      * the <code>wrappedKeyAlgorithm</code>.
+     *
+     * @throws UnsupportedOperationException if this method is not supported.
      */
     protected Key engineUnwrap(byte[] wrappedKey,
                                String wrappedKeyAlgorithm,
--- a/jdk/src/share/classes/javax/sql/rowset/serial/SerialRef.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/javax/sql/rowset/serial/SerialRef.java	Mon Jun 10 10:38:33 2013 +0100
@@ -202,7 +202,7 @@
     }
 
     /**
-     * Returns a clone of this {@code SerialRef}. .
+     * Returns a clone of this {@code SerialRef}.
      * The underlying {@code Ref} object will be set to null.
      *
      * @return  a clone of this SerialRef
--- a/jdk/src/share/classes/javax/sql/rowset/serial/SerialStruct.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/javax/sql/rowset/serial/SerialStruct.java	Mon Jun 10 10:38:33 2013 +0100
@@ -87,6 +87,7 @@
      * object for custom mapping the SQL structured type or any of its
      * attributes that are SQL structured types.
      *
+     * @param in an instance of {@code Struct}
      * @param map a <code>java.util.Map</code> object in which
      *        each entry consists of 1) a <code>String</code> object
      *        giving the fully qualified name of a UDT and 2) the
--- a/jdk/src/share/classes/javax/swing/JToolTip.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/javax/swing/JToolTip.java	Mon Jun 10 10:38:33 2013 +0100
@@ -31,6 +31,7 @@
 import java.io.ObjectOutputStream;
 import java.io.ObjectInputStream;
 import java.io.IOException;
+import java.util.Objects;
 
 
 /**
@@ -128,6 +129,11 @@
         String oldValue = this.tipText;
         this.tipText = tipText;
         firePropertyChange("tiptext", oldValue, tipText);
+
+        if (!Objects.equals(oldValue, tipText)) {
+            revalidate();
+            repaint();
+        }
     }
 
     /**
--- a/jdk/src/share/classes/javax/swing/text/View.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/javax/swing/text/View.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -1174,6 +1174,7 @@
         // formed by added elements (i.e. they will be updated
         // by initialization.
         index0 = Math.max(index0, 0);
+        index1 = getViewIndex(elem.getDocument().getLength(), Position.Bias.Forward);
         for (int i = index0; i <= index1; i++) {
             if (! ((i >= hole0) && (i <= hole1))) {
                 v = getView(i);
--- a/jdk/src/share/classes/javax/swing/text/html/parser/Parser.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/javax/swing/text/html/parser/Parser.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -1980,11 +1980,12 @@
 
     void parseScript() throws IOException {
         char[] charsToAdd = new char[SCRIPT_END_TAG.length];
+        boolean insideComment = false;
 
         /* Here, ch should be the first character after <script> */
         while (true) {
             int i = 0;
-            while (i < SCRIPT_END_TAG.length
+            while (!insideComment && i < SCRIPT_END_TAG.length
                        && (SCRIPT_END_TAG[i] == ch
                            || SCRIPT_END_TAG_UPPER_CASE[i] == ch)) {
                 charsToAdd[i] = (char) ch;
@@ -2025,6 +2026,13 @@
                     break;
                 default:
                     addString(ch);
+                    String str = new String(getChars(0, strpos));
+                    if (!insideComment && str.endsWith(START_COMMENT)) {
+                        insideComment = true;
+                    }
+                    if (insideComment && str.endsWith(END_COMMENT)) {
+                        insideComment = false;
+                    }
                     ch = readCh();
                     break;
                 } // switch
--- a/jdk/src/share/classes/sun/management/Agent.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/management/Agent.java	Mon Jun 10 10:38:33 2013 +0100
@@ -77,7 +77,7 @@
     private static final String SNMP_ADAPTOR_BOOTSTRAP_CLASS_NAME =
             "sun.management.snmp.AdaptorBootstrap";
 
-    private static final String JDP_DEFAULT_ADDRESS = "239.255.255.225";
+    private static final String JDP_DEFAULT_ADDRESS = "224.0.23.178";
     private static final int JDP_DEFAULT_PORT = 7095;
 
     // The only active agent allowed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/management/DiagnosticCommandArgumentInfo.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,159 @@
+/*
+ * 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.management;
+
+/**
+ * Diagnostic Command Argument information. It contains the description
+ * of one parameter of the diagnostic command. A parameter can either be an
+ * option or an argument. Options are identified by the option name while
+ * arguments are identified by their position in the command line. The generic
+ * syntax of a diagnostic command is:
+ *  <blockquote>
+ *    &lt;command name&gt; [&lt;option&gt;=&lt;value&gt;] [&lt;argument_value&gt;]
+ * </blockquote>
+ * Example:
+ * <blockquote>
+ * command_name option1=value1 option2=value argumentA argumentB argumentC
+ * </blockquote>
+ * In this command line, the diagnostic command receives five parameters, two
+ * options named {@code option1} and {@code option2}, and three arguments.
+ * argumentA's position is 0, argumentB's position is 1 and argumentC's
+ * position is 2.
+ *
+ * @since 8
+ */
+
+class DiagnosticCommandArgumentInfo {
+    private final String name;
+    private final String description;
+    private final String type;
+    private final String defaultValue;
+    private final boolean mandatory;
+    private final boolean option;
+    private final boolean multiple;
+    private final int position;
+
+    /**
+     * Returns the argument name.
+     *
+     * @return the argument name
+     */
+    String getName() {
+        return name;
+    }
+
+   /**
+     * Returns the argument description.
+     *
+     * @return the argument description
+     */
+    String getDescription() {
+        return description;
+    }
+
+    /**
+     * Returns the argument type.
+     *
+     * @return the argument type
+     */
+    String getType() {
+        return type;
+    }
+
+    /**
+     * Returns the default value as a String if a default value
+     * is defined, null otherwise.
+     *
+     * @return the default value as a String if a default value
+     * is defined, null otherwise.
+     */
+    String getDefault() {
+        return defaultValue;
+    }
+
+    /**
+     * Returns {@code true} if the argument is mandatory,
+     *         {@code false} otherwise.
+     *
+     * @return {@code true} if the argument is mandatory,
+     *         {@code false} otherwise
+     */
+    boolean isMandatory() {
+        return mandatory;
+    }
+
+    /**
+     * Returns {@code true} if the argument is an option,
+     *         {@code false} otherwise. Options have to be specified using the
+     *         &lt;key&gt;=&lt;value&gt; syntax on the command line, while other
+     *         arguments are specified with a single &lt;value&gt; field and are
+     *         identified by their position on command line.
+     *
+     * @return {@code true} if the argument is an option,
+     *         {@code false} otherwise
+     */
+    boolean isOption() {
+        return option;
+    }
+
+    /**
+     * Returns {@code true} if the argument can be specified multiple times,
+     *         {@code false} otherwise.
+     *
+     * @return {@code true} if the argument can be specified multiple times,
+     *         {@code false} otherwise
+     */
+    boolean isMultiple() {
+        return multiple;
+    }
+
+    /**
+     * Returns the expected position of this argument if it is not an option,
+     *         -1 otherwise. Argument position if defined from left to right,
+     *         starting at zero and ignoring the diagnostic command name and
+     *         options.
+     *
+     * @return the expected position of this argument if it is not an option,
+     *         -1 otherwise.
+     */
+    int getPosition() {
+        return position;
+    }
+
+    DiagnosticCommandArgumentInfo(String name, String description,
+                                         String type, String defaultValue,
+                                         boolean mandatory, boolean option,
+                                         boolean multiple, int position) {
+        this.name = name;
+        this.description = description;
+        this.type = type;
+        this.defaultValue = defaultValue;
+        this.mandatory = mandatory;
+        this.option = option;
+        this.multiple = multiple;
+        this.position = position;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/management/DiagnosticCommandImpl.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,380 @@
+/*
+ * 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.management;
+
+import com.sun.management.DiagnosticCommandMBean;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.security.Permission;
+import java.util.*;
+import javax.management.*;
+
+/**
+ * Implementation class for the diagnostic commands subsystem.
+ *
+ * @since 8
+ */
+class DiagnosticCommandImpl extends NotificationEmitterSupport
+    implements DiagnosticCommandMBean {
+
+    private final VMManagement jvm;
+    private volatile Map<String, Wrapper> wrappers = null;
+    private static final String strClassName = "".getClass().getName();
+    private static final String strArrayClassName = String[].class.getName();
+    private final boolean isSupported;
+
+    @Override
+    public Object getAttribute(String attribute) throws AttributeNotFoundException,
+        MBeanException, ReflectionException {
+        throw new AttributeNotFoundException(attribute);
+    }
+
+    @Override
+    public void setAttribute(Attribute attribute) throws AttributeNotFoundException,
+        InvalidAttributeValueException, MBeanException, ReflectionException {
+        throw new AttributeNotFoundException(attribute.getName());
+    }
+
+    @Override
+    public AttributeList getAttributes(String[] attributes) {
+        return new AttributeList();
+    }
+
+    @Override
+    public AttributeList setAttributes(AttributeList attributes) {
+        return new AttributeList();
+    }
+
+    private class Wrapper {
+
+        String name;
+        String cmd;
+        DiagnosticCommandInfo info;
+        Permission permission;
+
+        Wrapper(String name, String cmd, DiagnosticCommandInfo info)
+                throws InstantiationException {
+            this.name = name;
+            this.cmd = cmd;
+            this.info = info;
+            this.permission = null;
+            Exception cause = null;
+            if (info.getPermissionClass() != null) {
+                try {
+                    Class c = Class.forName(info.getPermissionClass());
+                    if (info.getPermissionAction() == null) {
+                        try {
+                            Constructor constructor = c.getConstructor(String.class);
+                            permission = (Permission) constructor.newInstance(info.getPermissionName());
+
+                        } catch (InstantiationException | IllegalAccessException
+                                | IllegalArgumentException | InvocationTargetException
+                                | NoSuchMethodException | SecurityException ex) {
+                            cause = ex;
+                        }
+                    }
+                    if (permission == null) {
+                        try {
+                            Constructor constructor = c.getConstructor(String.class, String.class);
+                            permission = (Permission) constructor.newInstance(
+                                    info.getPermissionName(),
+                                    info.getPermissionAction());
+                        } catch (InstantiationException | IllegalAccessException
+                                | IllegalArgumentException | InvocationTargetException
+                                | NoSuchMethodException | SecurityException ex) {
+                            cause = ex;
+                        }
+                    }
+                } catch (ClassNotFoundException ex) { }
+                if (permission == null) {
+                    InstantiationException iex =
+                            new InstantiationException("Unable to instantiate required permission");
+                    iex.initCause(cause);
+                }
+            }
+        }
+
+        public String execute(String[] args) {
+            if (permission != null) {
+                SecurityManager sm = System.getSecurityManager();
+                if (sm != null) {
+                    sm.checkPermission(permission);
+                }
+            }
+            if(args == null) {
+                return executeDiagnosticCommand(cmd);
+            } else {
+                StringBuilder sb = new StringBuilder();
+                sb.append(cmd);
+                for(int i=0; i<args.length; i++) {
+                    if(args[i] == null) {
+                        throw new IllegalArgumentException("Invalid null argument");
+                    }
+                    sb.append(" ");
+                    sb.append(args[i]);
+                }
+                return executeDiagnosticCommand(sb.toString());
+            }
+        }
+    }
+
+    DiagnosticCommandImpl(VMManagement jvm) {
+        this.jvm = jvm;
+        isSupported = jvm.isRemoteDiagnosticCommandsSupported();
+    }
+
+    private static class OperationInfoComparator implements Comparator<MBeanOperationInfo> {
+        @Override
+        public int compare(MBeanOperationInfo o1, MBeanOperationInfo o2) {
+            return o1.getName().compareTo(o2.getName());
+        }
+    }
+
+    @Override
+    public MBeanInfo getMBeanInfo() {
+        SortedSet<MBeanOperationInfo> operations = new TreeSet<>(new OperationInfoComparator());
+        Map<String, Wrapper> wrappersmap;
+        if (!isSupported) {
+            wrappersmap = (Map<String, Wrapper>) Collections.EMPTY_MAP;
+        } else {
+            try {
+                String[] command = getDiagnosticCommands();
+                DiagnosticCommandInfo[] info = getDiagnosticCommandInfo(command);
+                MBeanParameterInfo stringArgInfo[] = new MBeanParameterInfo[]{
+                    new MBeanParameterInfo("arguments", strArrayClassName,
+                    "Array of Diagnostic Commands Arguments and Options")
+                };
+                wrappersmap = new HashMap<>();
+                for (int i = 0; i < command.length; i++) {
+                    String name = transform(command[i]);
+                    try {
+                        Wrapper w = new Wrapper(name, command[i], info[i]);
+                        wrappersmap.put(name, w);
+                        operations.add(new MBeanOperationInfo(
+                                w.name,
+                                w.info.getDescription(),
+                                (w.info.getArgumentsInfo() == null
+                                    || w.info.getArgumentsInfo().isEmpty())
+                                    ? null : stringArgInfo,
+                                strClassName,
+                                MBeanOperationInfo.ACTION_INFO,
+                                commandDescriptor(w)));
+                    } catch (InstantiationException ex) {
+                        // If for some reasons the creation of a diagnostic command
+                        // wrappers fails, the diagnostic command is just ignored
+                        // and won't appear in the DynamicMBean
+                    }
+                }
+            } catch (IllegalArgumentException | UnsupportedOperationException e) {
+                wrappersmap = (Map<String, Wrapper>) Collections.EMPTY_MAP;
+            }
+        }
+        wrappers =  Collections.unmodifiableMap(wrappersmap);
+        HashMap<String, Object> map = new HashMap<>();
+        map.put("immutableInfo", "false");
+        map.put("interfaceClassName","com.sun.management.DiagnosticCommandMBean");
+        map.put("mxbean", "false");
+        Descriptor desc = new ImmutableDescriptor(map);
+        return new MBeanInfo(
+                this.getClass().getName(),
+                "Diagnostic Commands",
+                null, // attributes
+                null, // constructors
+                operations.toArray(new MBeanOperationInfo[operations.size()]), // operations
+                getNotificationInfo(), // notifications
+                desc);
+    }
+
+    @Override
+    public Object invoke(String actionName, Object[] params, String[] signature)
+            throws MBeanException, ReflectionException {
+        if (!isSupported) {
+            throw new UnsupportedOperationException();
+        }
+        if (wrappers == null) {
+            getMBeanInfo();
+        }
+        Wrapper w = wrappers.get(actionName);
+        if (w != null) {
+            if (w.info.getArgumentsInfo().isEmpty()
+                    && (params == null || params.length == 0)
+                    && (signature == null || signature.length == 0)) {
+                return w.execute(null);
+            } else if((params != null && params.length == 1)
+                    && (signature != null && signature.length == 1
+                    && signature[0] != null
+                    && signature[0].compareTo(strArrayClassName) == 0)) {
+                return w.execute((String[]) params[0]);
+            }
+        }
+        throw new ReflectionException(new NoSuchMethodException(actionName));
+    }
+
+    private static String transform(String name) {
+        StringBuilder sb = new StringBuilder();
+        boolean toLower = true;
+        boolean toUpper = false;
+        for (int i = 0; i < name.length(); i++) {
+            char c = name.charAt(i);
+            if (c == '.' || c == '_') {
+                toLower = false;
+                toUpper = true;
+            } else {
+                if (toUpper) {
+                    toUpper = false;
+                    sb.append(Character.toUpperCase(c));
+                } else if(toLower) {
+                    sb.append(Character.toLowerCase(c));
+                } else {
+                    sb.append(c);
+                }
+            }
+        }
+        return sb.toString();
+    }
+
+    private Descriptor commandDescriptor(Wrapper w) throws IllegalArgumentException {
+        HashMap<String, Object> map = new HashMap<>();
+        map.put("dcmd.name", w.info.getName());
+        map.put("dcmd.description", w.info.getDescription());
+        map.put("dcmd.vmImpact", w.info.getImpact());
+        map.put("dcmd.permissionClass", w.info.getPermissionClass());
+        map.put("dcmd.permissionName", w.info.getPermissionName());
+        map.put("dcmd.permissionAction", w.info.getPermissionAction());
+        map.put("dcmd.enabled", w.info.isEnabled());
+        StringBuilder sb = new StringBuilder();
+        sb.append("help ");
+        sb.append(w.info.getName());
+        map.put("dcmd.help", executeDiagnosticCommand(sb.toString()));
+        if (w.info.getArgumentsInfo() != null && !w.info.getArgumentsInfo().isEmpty()) {
+            HashMap<String, Object> allargmap = new HashMap<>();
+            for (DiagnosticCommandArgumentInfo arginfo : w.info.getArgumentsInfo()) {
+                HashMap<String, Object> argmap = new HashMap<>();
+                argmap.put("dcmd.arg.name", arginfo.getName());
+                argmap.put("dcmd.arg.type", arginfo.getType());
+                argmap.put("dcmd.arg.description", arginfo.getDescription());
+                argmap.put("dcmd.arg.isMandatory", arginfo.isMandatory());
+                argmap.put("dcmd.arg.isMultiple", arginfo.isMultiple());
+                boolean isOption = arginfo.isOption();
+                argmap.put("dcmd.arg.isOption", isOption);
+                if(!isOption) {
+                    argmap.put("dcmd.arg.position", arginfo.getPosition());
+                } else {
+                    argmap.put("dcmd.arg.position", -1);
+                }
+                allargmap.put(arginfo.getName(), new ImmutableDescriptor(argmap));
+            }
+            map.put("dcmd.arguments", new ImmutableDescriptor(allargmap));
+        }
+        return new ImmutableDescriptor(map);
+    }
+
+    private final static String notifName =
+        "javax.management.Notification";
+
+    private final static String[] diagFramNotifTypes = {
+        "jmx.mbean.info.changed"
+    };
+
+    private MBeanNotificationInfo[] notifInfo = null;
+
+    @Override
+    public MBeanNotificationInfo[] getNotificationInfo() {
+        synchronized (this) {
+            if (notifInfo == null) {
+                 notifInfo = new MBeanNotificationInfo[1];
+                 notifInfo[0] =
+                         new MBeanNotificationInfo(diagFramNotifTypes,
+                                                   notifName,
+                                                   "Diagnostic Framework Notification");
+            }
+        }
+        return notifInfo;
+    }
+
+    private static long seqNumber = 0;
+    private static long getNextSeqNumber() {
+        return ++seqNumber;
+    }
+
+    private void createDiagnosticFrameworkNotification() {
+
+        if (!hasListeners()) {
+            return;
+        }
+        ObjectName on = null;
+        try {
+            on = ObjectName.getInstance(ManagementFactoryHelper.HOTSPOT_DIAGNOSTIC_COMMAND_MBEAN_NAME);
+        } catch (MalformedObjectNameException e) { }
+        Notification notif = new Notification("jmx.mbean.info.changed",
+                                              on,
+                                              getNextSeqNumber());
+        notif.setUserData(getMBeanInfo());
+        sendNotification(notif);
+    }
+
+    @Override
+    public synchronized void addNotificationListener(NotificationListener listener,
+            NotificationFilter filter,
+            Object handback) {
+        boolean before = hasListeners();
+        super.addNotificationListener(listener, filter, handback);
+        boolean after = hasListeners();
+        if (!before && after) {
+            setNotificationEnabled(true);
+        }
+    }
+
+    @Override
+    public synchronized void removeNotificationListener(NotificationListener listener)
+            throws ListenerNotFoundException {
+        boolean before = hasListeners();
+        super.removeNotificationListener(listener);
+        boolean after = hasListeners();
+        if (before && !after) {
+            setNotificationEnabled(false);
+        }
+    }
+
+    @Override
+    public synchronized void removeNotificationListener(NotificationListener listener,
+            NotificationFilter filter,
+            Object handback)
+            throws ListenerNotFoundException {
+        boolean before = hasListeners();
+        super.removeNotificationListener(listener, filter, handback);
+        boolean after = hasListeners();
+        if (before && !after) {
+            setNotificationEnabled(false);
+        }
+    }
+
+    private native void setNotificationEnabled(boolean enabled);
+    private native String[] getDiagnosticCommands();
+    private native DiagnosticCommandInfo[] getDiagnosticCommandInfo(String[] commands);
+    private native String executeDiagnosticCommand(String command);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/management/DiagnosticCommandInfo.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,151 @@
+/*
+ * 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.management;
+
+import java.util.List;
+
+/**
+ * Diagnostic command information. It contains the description of a
+ * diagnostic command.
+ *
+ * @since 8
+ */
+
+class DiagnosticCommandInfo {
+    private final String name;
+    private final String description;
+    private final String impact;
+    private final String permissionClass;
+    private final String permissionName;
+    private final String permissionAction;
+    private final boolean enabled;
+    private final List<DiagnosticCommandArgumentInfo> arguments;
+
+    /**
+     * Returns the diagnostic command name.
+     *
+     * @return the diagnostic command name
+     */
+    String getName() {
+        return name;
+    }
+
+   /**
+     * Returns the diagnostic command description.
+     *
+     * @return the diagnostic command description
+     */
+    String getDescription() {
+        return description;
+    }
+
+    /**
+     * Returns the potential impact of the diagnostic command execution
+     *         on the Java virtual machine behavior.
+     *
+     * @return the potential impact of the diagnostic command execution
+     *         on the Java virtual machine behavior
+     */
+    String getImpact() {
+        return impact;
+    }
+
+    /**
+     * Returns the name of the permission class required to be allowed
+     *         to invoke the diagnostic command, or null if no permission
+     *         is required.
+     *
+     * @return the name of the permission class name required to be allowed
+     *         to invoke the diagnostic command, or null if no permission
+     *         is required
+     */
+    String getPermissionClass() {
+        return permissionClass;
+    }
+
+    /**
+     * Returns the permission name required to be allowed to invoke the
+     *         diagnostic command, or null if no permission is required.
+     *
+     * @return the permission name required to be allowed to invoke the
+     *         diagnostic command, or null if no permission is required
+     */
+    String getPermissionName() {
+        return permissionName;
+    }
+
+    /**
+     * Returns the permission action required to be allowed to invoke the
+     *         diagnostic command, or null if no permission is required or
+     *         if the permission has no action specified.
+     *
+     * @return the permission action required to be allowed to invoke the
+     *         diagnostic command, or null if no permission is required or
+     *         if the permission has no action specified
+     */
+    String getPermissionAction() {
+        return permissionAction;
+    }
+
+    /**
+     * Returns {@code true} if the diagnostic command is enabled,
+     *         {@code false} otherwise. The enabled/disabled
+     *         status of a diagnostic command can evolve during
+     *         the lifetime of the Java virtual machine.
+     *
+     * @return {@code true} if the diagnostic command is enabled,
+     *         {@code false} otherwise
+     */
+    boolean isEnabled() {
+        return enabled;
+    }
+
+    /**
+     * Returns the list of the diagnostic command arguments description.
+     * If the diagnostic command has no arguments, it returns an empty list.
+     *
+     * @return a list of the diagnostic command arguments description
+     */
+    List<DiagnosticCommandArgumentInfo> getArgumentsInfo() {
+        return arguments;
+    }
+
+    DiagnosticCommandInfo(String name, String description,
+                                    String impact, String permissionClass,
+                                    String permissionName, String permissionAction,
+                                    boolean enabled,
+                                    List<DiagnosticCommandArgumentInfo> arguments)
+    {
+        this.name = name;
+        this.description = description;
+        this.impact = impact;
+        this.permissionClass = permissionClass;
+        this.permissionName = permissionName;
+        this.permissionAction = permissionAction;
+        this.enabled = enabled;
+        this.arguments = arguments;
+    }
+}
--- a/jdk/src/share/classes/sun/management/ManagementFactoryHelper.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/management/ManagementFactoryHelper.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -27,6 +27,7 @@
 
 import java.lang.management.*;
 
+import javax.management.DynamicMBean;
 import javax.management.InstanceAlreadyExistsException;
 import javax.management.InstanceNotFoundException;
 import javax.management.MBeanServer;
@@ -42,7 +43,9 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import com.sun.management.DiagnosticCommandMBean;
 import com.sun.management.OSMBeanFactory;
 import com.sun.management.HotSpotDiagnosticMXBean;
 
@@ -263,6 +266,7 @@
     private static HotspotThread hsThreadMBean = null;
     private static HotspotCompilation hsCompileMBean = null;
     private static HotspotMemory hsMemoryMBean = null;
+    private static DiagnosticCommandImpl hsDiagCommandMBean = null;
 
     public static synchronized HotSpotDiagnosticMXBean getDiagnosticMXBean() {
         if (hsDiagMBean == null) {
@@ -311,6 +315,14 @@
         return hsMemoryMBean;
     }
 
+    public static synchronized DiagnosticCommandMBean getDiagnosticCommandMBean() {
+        // Remote Diagnostic Commands may not be supported
+        if (hsDiagCommandMBean == null && jvm.isRemoteDiagnosticCommandsSupported()) {
+            hsDiagCommandMBean = new DiagnosticCommandImpl(jvm);
+        }
+        return hsDiagCommandMBean;
+    }
+
     /**
      * This method is for testing only.
      */
@@ -365,6 +377,18 @@
     private final static String HOTSPOT_THREAD_MBEAN_NAME =
         "sun.management:type=HotspotThreading";
 
+    final static String HOTSPOT_DIAGNOSTIC_COMMAND_MBEAN_NAME =
+        "com.sun.management:type=DiagnosticCommand";
+
+    public static HashMap<ObjectName, DynamicMBean> getPlatformDynamicMBeans() {
+        HashMap<ObjectName, DynamicMBean> map = new HashMap<>();
+        DiagnosticCommandMBean diagMBean = getDiagnosticCommandMBean();
+        if (diagMBean != null) {
+            map.put(Util.newObjectName(HOTSPOT_DIAGNOSTIC_COMMAND_MBEAN_NAME), diagMBean);
+        }
+        return map;
+    }
+
     static void registerInternalMBeans(MBeanServer mbs) {
         // register all internal MBeans if not registered
         // No exception is thrown if a MBean with that object name
--- a/jdk/src/share/classes/sun/management/VMManagement.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/management/VMManagement.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -46,6 +46,7 @@
     public boolean isThreadAllocatedMemorySupported();
     public boolean isThreadAllocatedMemoryEnabled();
     public boolean isGcNotificationSupported();
+    public boolean isRemoteDiagnosticCommandsSupported();
 
     // Class Loading Subsystem
     public long    getTotalClassCount();
--- a/jdk/src/share/classes/sun/management/VMManagementImpl.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/management/VMManagementImpl.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -57,6 +57,7 @@
     private static boolean synchronizerUsageSupport;
     private static boolean threadAllocatedMemorySupport;
     private static boolean gcNotificationSupport;
+    private static boolean remoteDiagnosticCommandsSupport;
 
 
     static {
@@ -106,6 +107,10 @@
         return gcNotificationSupport;
     }
 
+    public boolean isRemoteDiagnosticCommandsSupported() {
+        return remoteDiagnosticCommandsSupport;
+    }
+
     public native boolean isThreadContentionMonitoringEnabled();
     public native boolean isThreadCpuTimeEnabled();
     public native boolean isThreadAllocatedMemoryEnabled();
--- a/jdk/src/share/classes/sun/management/jdp/JdpPacketWriter.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/management/jdp/JdpPacketWriter.java	Mon Jun 10 10:38:33 2013 +0100
@@ -60,9 +60,12 @@
      */
     public void addEntry(String entry)
             throws IOException {
-        pkt.writeShort(entry.length());
-        byte[] b = entry.getBytes("UTF-8");
-        pkt.write(b);
+        /* DataOutputStream.writeUTF() do essentially
+         *  the same as:
+         *    pkt.writeShort(entry.getBytes("UTF-8").length);
+         *    pkt.write(entry.getBytes("UTF-8"));
+         */
+        pkt.writeUTF(entry);
     }
 
     /**
--- a/jdk/src/share/classes/sun/management/jdp/package-info.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/management/jdp/package-info.java	Mon Jun 10 10:38:33 2013 +0100
@@ -60,7 +60,7 @@
  *
  * - `INSTANCE_NAME` -- The user-provided name of the running instance
  *
- * The protocol sends packets to 239.255.255.225:7095 by default.
+ * The protocol sends packets to 224.0.23.178:7095 by default.
  *
  * The protocol uses system properties to control it's behaviour:
  * - `com.sun.management.jdp.port` -- override default port
--- a/jdk/src/share/classes/sun/misc/Contended.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/misc/Contended.java	Mon Jun 10 10:38:33 2013 +0100
@@ -31,7 +31,42 @@
 import java.lang.annotation.Target;
 
 /**
- * This annotation marks classes and fields as considered to be contended.
+ * <p>An annotation expressing that objects and/or their fields are
+ * expected to encounter memory contention, generally in the form of
+ * "false sharing". This annotation serves as a hint that such objects
+ * and fields should reside in locations isolated from those of other
+ * objects or fields. Susceptibility to memory contention is a
+ * property of the intended usages of objects and fields, not their
+ * types or qualifiers. The effects of this annotation will nearly
+ * always add significant space overhead to objects. The use of
+ * {@code @Contended} is warranted only when the performance impact of
+ * this time/space tradeoff is intrinsically worthwhile; for example,
+ * in concurrent contexts in which each instance of the annotated
+ * class is often accessed by a different thread.
+ *
+ * <p>A {@code @Contended} field annotation may optionally include a
+ * <i>contention group</i> tag. A contention group defines a set of one
+ * or more fields that collectively must be isolated from all other
+ * contention groups. The fields in the same contention group may not be
+ * pairwise isolated. With no contention group tag (or with the default
+ * empty tag: "") each {@code @Contended} field resides in its own
+ * <i>distinct</i> and <i>anonymous</i> contention group.
+ *
+ * <p>When the annotation is used at the class level, the effect is
+ * equivalent to grouping all the declared fields not already having the
+ * {@code @Contended} annotation into the same anonymous group.
+ * With the class level annotation, implementations may choose different
+ * isolation techniques, such as isolating the entire object, rather than
+ * isolating distinct fields. A contention group tag has no meaning
+ * in a class level {@code @Contended} annotation, and is ignored.
+ *
+ * <p>The class level {@code @Contended} annotation is not inherited and has
+ * no effect on the fields declared in any sub-classes. The effects of all
+ * {@code @Contended} annotations, however, remain in force for all
+ * subclass instances, providing isolation of all the defined contention
+ * groups. Contention group tags are not inherited, and the same tag used
+ * in a superclass and subclass, represent distinct contention groups.
+ *
  * @since 1.8
  */
 @Retention(RetentionPolicy.RUNTIME)
@@ -39,7 +74,10 @@
 public @interface Contended {
 
     /**
-      Defines the contention group tag.
+     * The (optional) contention group tag.
+     * This tag is only meaningful for field level annotations.
+     *
+     * @return contention group tag.
      */
     String value() default "";
 }
--- a/jdk/src/share/classes/sun/misc/FDBigInt.java	Fri May 31 10:34:25 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,493 +0,0 @@
-/*
- * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact 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 FDBigInt {
-    int nWords; // number of words used
-    int data[]; // value: data[0] is least significant
-
-
-    public FDBigInt( int v ){
-        nWords = 1;
-        data = new int[1];
-        data[0] = v;
-    }
-
-    public FDBigInt( long v ){
-        data = new int[2];
-        data[0] = (int)v;
-        data[1] = (int)(v>>>32);
-        nWords = (data[1]==0) ? 1 : 2;
-    }
-
-    public FDBigInt( FDBigInt other ){
-        data = new int[nWords = other.nWords];
-        System.arraycopy( other.data, 0, data, 0, nWords );
-    }
-
-    private FDBigInt( int [] d, int n ){
-        data = d;
-        nWords = n;
-    }
-
-    public FDBigInt( 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 FDBigInt by an int.
-     * Result is a new FDBigInt.
-     */
-    public FDBigInt
-    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 FDBigInt( r, nWords );
-        } else {
-            r[nWords] = (int)p;
-            return new FDBigInt( r, nWords+1 );
-        }
-    }
-
-    /*
-     * Multiply a FDBigInt 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 FDBigInt by another FDBigInt.
-     * Result is a new FDBigInt.
-     */
-    public FDBigInt
-    mult( FDBigInt 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 FDBigInt( r, i+1 );
-    }
-
-    /*
-     * Add one FDBigInt to another. Return a FDBigInt
-     */
-    public FDBigInt
-    add( FDBigInt 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 FDBigInt( s, i );
-        }
-        return new FDBigInt( r, i );
-    }
-
-    /*
-     * Subtract one FDBigInt from another. Return a FDBigInt
-     * Assert that the result is positive.
-     */
-    public FDBigInt
-    sub( FDBigInt 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 FDBigInt( r, n-nzeros );
-    }
-
-    private static boolean dataInRangeIsZero(int i, int m, FDBigInt other) {
-        while ( i < m )
-            if (other.data[i++] != 0)
-                return false;
-        return true;
-    }
-
-    /*
-     * Compare FDBigInt with another FDBigInt. Return an integer
-     * >0: this > other
-     *  0: this == other
-     * <0: this < other
-     */
-    public int
-    cmp( FDBigInt 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( FDBigInt 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/src/share/classes/sun/misc/FDBigInteger.java	Mon Jun 10 10:38:33 2013 +0100
@@ -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 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 final static 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</code>, but the next bit should be 1
+     * <code>(highestWord & 0x08000000) != 0</code>.
+     *
+     * @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, 0 <= q < 10.
+     *
+     * @param 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
+     */
+    /*@
+     @ 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, 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, 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>
+     * >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>
+     * >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>
+     * -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/share/classes/sun/misc/FloatingDecimal.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/misc/FloatingDecimal.java	Mon Jun 10 10:38:33 2013 +0100
@@ -25,602 +25,785 @@
 
 package sun.misc;
 
-import sun.misc.DoubleConsts;
-import sun.misc.FloatConsts;
+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{
-    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
+    //
+    // 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    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    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();
+    }
 
-    /*
-     * 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.
+    /**
+     * 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();
+    }
 
-    // True if the dtoa() binary to decimal conversion was exact.
-    boolean     exactDecimalConversion = false;
+    /**
+     * 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);
+    }
 
-    // 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;
+    /**
+     * 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);
+    }
 
-    private     FloatingDecimal( boolean negSign, int decExponent, char []digits, int n,  boolean e )
-    {
-        isNegative = negSign;
-        isExceptional = e;
-        this.decExponent = decExponent;
-        this.digits = digits;
-        this.nDigits = n;
+    /**
+     * 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();
     }
 
-    /*
-     * Constants of the implementation
-     * Most are IEEE-754 related.
-     * (There are more really boring constants at the end.)
+    /**
+     * A converter which can process single or double precision floating point
+     * values into an ASCII <code>String</code> representation.
      */
-    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)
+    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);
 
-    static final long   highbyte = 0xff00000000000000L;
-    static final long   highbit  = 0x8000000000000000L;
-    static final long   lowbytes = ~highbyte;
+        /**
+         * 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</code>.
+         */
+        public boolean isNegative();
 
-    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;
+        /**
+         * 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();
 
-    static final int    intDecimalDigits = 9;
-
+        /**
+         * 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();
 
-    /*
-     * count number of bits from high-order 1 bit to low-order 1 bit,
-     * inclusive.
+        /**
+         * 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 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;
+    private static class ExceptionalBinaryToASCIIBuffer implements BinaryToASCIIConverter {
+        final private String image;
+        private boolean isNegative;
 
-        while ( ( v & highbyte ) == 0L ){
-            v <<= 8;
-        }
-        while ( v > 0L ) { // i.e. while ((v&highbit) == 0L )
-            v <<= 1;
+        public ExceptionalBinaryToASCIIBuffer(String image, boolean isNegative) {
+            this.image = image;
+            this.isNegative = isNegative;
         }
 
-        int n = 0;
-        while (( v & lowbytes ) != 0L ){
-            v <<= 8;
-            n += 8;
+        @Override
+        public String toJavaFormatString() {
+            return image;
         }
-        while ( v != 0L ){
-            v <<= 1;
-            n += 1;
-        }
-        return n;
-    }
 
-    /*
-     * Keep big powers of 5 handy for future reference.
-     */
-    private static FDBigInt b5p[];
+        @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;
+            }
+        }
 
-    private static synchronized FDBigInt
-    big5pow( int p ){
-        assert p >= 0 : p; // negative power of 5
-        if ( b5p == null ){
-            b5p = new FDBigInt[ p+1 ];
-        }else if (b5p.length <= p ){
-            FDBigInt t[] = new FDBigInt[ p+1 ];
-            System.arraycopy( b5p, 0, t, 0, b5p.length );
-            b5p = t;
+        @Override
+        public int getDecimalExponent() {
+            throw new IllegalArgumentException("Exceptional value does not have an exponent");
         }
-        if ( b5p[p] != null )
-            return b5p[p];
-        else if ( p < small5pow.length )
-            return b5p[p] = new FDBigInt( small5pow[p] );
-        else if ( p < long5pow.length )
-            return b5p[p] = new FDBigInt( 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;
-            FDBigInt bigq =  b5p[q];
-            if ( bigq == null )
-                bigq = big5pow ( q );
-            if ( r < small5pow.length ){
-                return (b5p[p] = bigq.mult( small5pow[r] ) );
-            }else{
-                FDBigInt bigr = b5p[ r ];
-                if ( bigr == null )
-                    bigr = big5pow( r );
-                return (b5p[p] = bigq.mult( bigr ) );
-            }
+
+        @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");
         }
     }
 
-    //
-    // a common operation
-    //
-    private static FDBigInt
-    multPow52( FDBigInt 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;
-    }
+    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'});
 
-    //
-    // another common operation
-    //
-    private static FDBigInt
-    constructPow52( int p5, int p2 ){
-        FDBigInt v = new FDBigInt( big5pow( p5 ) );
-        if ( p2 != 0 ){
-            v.lshiftMe( p2 );
+    /**
+     * 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];
         }
-        return v;
-    }
+
+        /**
+         * 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;
+        }
 
-    /*
-     * Make a floating double into a FDBigInt.
-     * This could also be structured as a FDBigInt
-     * 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 FDBigInt
-    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;
+        @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;
             }
         }
-        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;
+
+        @Override
+        public int getDecimalExponent() {
+            return decExponent;
+        }
 
-        bigIntExp = binexp+1-nbits;
-        bigIntNBits = nbits;
-        return new FDBigInt( lbits );
-    }
+        @Override
+        public int getDigits(char[] digits) {
+            System.arraycopy(this.digits,firstDigitIndex,digits,0,this.nDigits);
+            return this.nDigits;
+        }
+
+        @Override
+        public boolean isNegative() {
+            return isNegative;
+        }
 
-    /*
-     * 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;
+        @Override
+        public boolean isExceptional() {
+            return false;
+        }
+
+        @Override
+        public boolean digitsRoundedUp() {
+            return decimalDigitsRoundedUp;
         }
-        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) );
+
+        @Override
+        public boolean decimalDigitsExact() {
+            return exactDecimalConversion;
         }
-        if ( subtracting ) ulpval = - ulpval;
 
-        return ulpval;
-    }
+        private void setSign(boolean isNegative) {
+            this.isNegative = isNegative;
+        }
 
-    /*
-     * 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++;
+        /**
+         * 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++;
+                }
             }
-        }
-        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++;
+            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 ( 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++;
+                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 ( 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;
+                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');
             }
-            // else fall through.
-        }
-        digits[i] = (char)(q+1);
-        decimalDigitsRoundedUp = true;
-    }
-
-    public boolean digitsRoundedUp() {
-        return decimalDigitsRoundedUp;
-    }
-
-    /*
-     * FIRST IMPORTANT CONSTRUCTOR: DOUBLE
-     */
-    public FloatingDecimal( 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;
+            this.decExponent = decExponent+1;
+            this.firstDigitIndex = digitno;
+            this.nDigits = this.digits.length - digitno;
         }
-        binExp -= expBias;
-        // call the routine that actually does all the hard work.
-        dtoa( binExp, fractBits, nSignificantBits );
-    }
 
-    /*
-     * SECOND IMPORTANT CONSTRUCTOR: SINGLE
-     */
-    public FloatingDecimal( float f )
-    {
-        int     fBits = Float.floatToIntBits( f );
-        int     fractBits;
-        int     binExp;
-        int     nSignificantBits;
+        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;
 
-        // 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!
+            // 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;
+                    // }
+                    //
+                }
             }
-            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;
+            //
+            // 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;
             }
-            while ( (fractBits&singleFractHOB) == 0 ){
-                fractBits <<= 1;
-                binExp -= 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;
             }
-            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 );
-    }
+            //
+            // 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;
 
-    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;
+            //
+            // 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 ));
 
-        // 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);
+            // 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 {
-                        halfULP = 0L;
+                        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);
                     }
-                    if ( binExp >= expShift ){
-                        fractBits <<= (binExp-expShift);
-                    } else {
-                        fractBits >>>= (expShift-binExp) ;
+                    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();
                     }
-                    developLongDigits( 0, fractBits, halfULP );
+                } 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;
                 }
-                /*
-                 * 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;
-                 * }
-                 */
+                // else fall through.
             }
+            digits[i] = (char) (q + 1);
+            decimalDigitsRoundedUp = true;
         }
-        /*
-         * 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.)
          *
@@ -630,324 +813,108 @@
          * 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.
-        FDBigInt 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
-         * FDBigInt. 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 FDBigInt arithmetic.
-         * We use the same algorithms, except that we "normalize"
-         * our FDBigInts 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 {
-            FDBigInt ZeroVal = new FDBigInt(0);
-            FDBigInt tenSval;
-            int  shiftBias;
-
-            /*
-             * We really must do FDBigInt arithmetic.
-             * Fist, construct our FDBigInt initial values.
-             */
-            Bval = multPow52( new FDBigInt( 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();
+        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;
+        }
 
-    public boolean decimalDigitsExact() {
-        return exactDecimalConversion;
-    }
+        /**
+         * 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
+        };
 
-    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);
-    }
+        // 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,
+        };
 
-    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 {
+        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, 0, result, i, charLength);
+                System.arraycopy(digits, firstDigitIndex, result, i, charLength);
                 i += charLength;
                 if (charLength < decExponent) {
-                    charLength = decExponent-charLength;
-                    System.arraycopy(zero, 0, result, i, charLength);
+                    charLength = decExponent - charLength;
+                    Arrays.fill(result,i,i+charLength,'0');
                     i += charLength;
                     result[i++] = '.';
                     result[i++] = '0';
@@ -955,27 +922,27 @@
                     result[i++] = '.';
                     if (charLength < nDigits) {
                         int t = nDigits - charLength;
-                        System.arraycopy(digits, charLength, result, i, t);
+                        System.arraycopy(digits, firstDigitIndex+charLength, result, i, t);
                         i += t;
                     } else {
                         result[i++] = '0';
                     }
                 }
-            } else if (decExponent <=0 && decExponent > -3) {
+            } else if (decExponent <= 0 && decExponent > -3) {
                 result[i++] = '0';
                 result[i++] = '.';
                 if (decExponent != 0) {
-                    System.arraycopy(zero, 0, result, i, -decExponent);
+                    Arrays.fill(result, i, i-decExponent, '0');
                     i -= decExponent;
                 }
-                System.arraycopy(digits, 0, result, i, nDigits);
+                System.arraycopy(digits, firstDigitIndex, result, i, nDigits);
                 i += nDigits;
             } else {
-                result[i++] = digits[0];
+                result[i++] = digits[firstDigitIndex];
                 result[i++] = '.';
                 if (nDigits > 1) {
-                    System.arraycopy(digits, 1, result, i, nDigits-1);
-                    i += nDigits-1;
+                    System.arraycopy(digits, firstDigitIndex+1, result, i, nDigits - 1);
+                    i += nDigits - 1;
                 } else {
                     result[i++] = '0';
                 }
@@ -983,48 +950,776 @@
                 int e;
                 if (decExponent <= 0) {
                     result[i++] = '-';
-                    e = -decExponent+1;
+                    e = -decExponent + 1;
                 } else {
-                    e = decExponent-1;
+                    e = decExponent - 1;
                 }
                 // decExponent has 1, 2, or 3, digits
                 if (e <= 9) {
-                    result[i++] = (char)(e+'0');
+                    result[i++] = (char) (e + '0');
                 } else if (e <= 99) {
-                    result[i++] = (char)(e/10 +'0');
-                    result[i++] = (char)(e%10 + '0');
+                    result[i++] = (char) (e / 10 + '0');
+                    result[i++] = (char) (e % 10 + '0');
                 } else {
-                    result[i++] = (char)(e/100+'0');
+                    result[i++] = (char) (e / 100 + '0');
                     e %= 100;
-                    result[i++] = (char)(e/10+'0');
-                    result[i++] = (char)(e%10 + '0');
+                    result[i++] = (char) (e / 10 + '0');
+                    result[i++] = (char) (e % 10 + '0');
                 }
             }
+            return i;
         }
-        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 {
+        final private double doubleVal;
+        private int roundDir = 0;
+
+        public PreparedASCIIToBinaryBuffer(double doubleVal) {
+            this.doubleVal = doubleVal;
+        }
+
+        public PreparedASCIIToBinaryBuffer(double doubleVal, int roundDir) {
+            this.doubleVal = doubleVal;
+            this.roundDir = roundDir;
+        }
+
+        @Override
+        public double doubleValue() {
+            return doubleVal;
+        }
+
+        @Override
+        public float floatValue() {
+            return stickyRound(doubleVal,roundDir);
+        }
     }
 
-    // Per-thread buffer for string/stringbuffer conversion
-    private static ThreadLocal<char[]> perThreadBuffer = new ThreadLocal<char[]>() {
-            protected synchronized char[] initialValue() {
-                return new char[26];
+    static final ASCIIToBinaryConverter A2BC_POSITIVE_INFINITY = new PreparedASCIIToBinaryBuffer(Double.POSITIVE_INFINITY);
+    static final ASCIIToBinaryConverter A2BC_NEGATIVE_INFINITY = new PreparedASCIIToBinaryBuffer(Double.NEGATIVE_INFINITY);
+    static final ASCIIToBinaryConverter A2BC_NOT_A_NUMBER  = new PreparedASCIIToBinaryBuffer(Double.NaN);
+    static final ASCIIToBinaryConverter A2BC_POSITIVE_ZERO = new PreparedASCIIToBinaryBuffer(0.0d);
+    static final ASCIIToBinaryConverter A2BC_NEGATIVE_ZERO = new PreparedASCIIToBinaryBuffer(-0.0d);
+
+    /**
+     * A buffered implementation of <code>ASCIIToBinaryConverter</code>.
+     */
+    static class ASCIIToBinaryBuffer implements ASCIIToBinaryConverter {
+        boolean     isNegative;
+        int         decExponent;
+        char        digits[];
+        int         nDigits;
+        int         roundDir = 0; // set by doubleValue
+
+        ASCIIToBinaryBuffer( boolean negSign, int decExponent, char[] digits, int n)
+        {
+            this.isNegative = negSign;
+            this.decExponent = decExponent;
+            this.digits = digits;
+            this.nDigits = n;
+        }
+
+        @Override
+        public double doubleValue() {
+            return doubleValue(false);
+        }
+
+        /**
+         * Computes 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) & ~DoubleConsts.SIGN_BIT_MASK;
+            int binexp = (int) (lbits >>> EXP_SHIFT);
+            double ulpval;
+            if (subtracting && (binexp >= EXP_SHIFT) && ((lbits & DoubleConsts.SIGNIF_BIT_MASK) == 0L)) {
+                // for subtraction from normalized, powers of 2,
+                // use next-smaller exponent
+                binexp -= 1;
+            }
+            if (binexp > EXP_SHIFT) {
+                ulpval = Double.longBitsToDouble(((long) (binexp - EXP_SHIFT)) << EXP_SHIFT);
+            } else if (binexp == 0) {
+                ulpval = Double.MIN_VALUE;
+            } else {
+                ulpval = Double.longBitsToDouble(1L << (binexp - 1));
+            }
+            if (subtracting) {
+                ulpval = -ulpval;
+            }
+
+            return ulpval;
+        }
+
+        /**
+         * 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.
+         */
+        private strictfp double doubleValue(boolean mustSetRoundDir) {
+            int kDigits = Math.min(nDigits, MAX_DECIMAL_DIGITS + 1);
+            long lValue;
+            double dValue;
+            double rValue;
+
+            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, INT_DECIMAL_DIGITS);
+            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 <= 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.
+                        //
+                        rValue = dValue * SMALL_10_POW[exp];
+                        if (mustSetRoundDir) {
+                            double tValue = rValue / SMALL_10_POW[exp];
+                            roundDir = (tValue == dValue) ? 0
+                                    : (tValue < dValue) ? 1
+                                    : -1;
+                        }
+                        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];
+                        rValue = dValue * SMALL_10_POW[exp - slop];
+
+                        if (mustSetRoundDir) {
+                            double tValue = rValue / SMALL_10_POW[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 >= -MAX_SMALL_TEN) {
+                        //
+                        // Can get the answer in one division.
+                        //
+                        rValue = dValue / SMALL_10_POW[-exp];
+                        if (mustSetRoundDir) {
+                            double tValue = rValue * SMALL_10_POW[-exp];
+                            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 > 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
+            //
+            FDBigInteger bigD0 = new FDBigInteger(lValue, digits, kDigits, nDigits);
+            exp = decExponent - nDigits;
+
+            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 dValue can't be NaN, Infinity or zero
+                long bigBbits = Double.doubleToRawLongBits(dValue) & ~DoubleConsts.SIGN_BIT_MASK;
+                int binexp = (int) (bigBbits >>> EXP_SHIFT);
+                bigBbits &= 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^-(expBias+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
+                    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;
+        }
+
+        /**
+         * 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 strictfp float floatValue() {
+            int kDigits = Math.min(nDigits, SINGLE_MAX_DECIMAL_DIGITS + 1);
+            int iValue;
+            float fValue;
+            //
+            // 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 <= 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 dValue 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 weeding out obviously out-of-range
+            // results, then convert to double and go to
+            // common hard-case code.
+            //
+            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;
+            } else 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;
+            }
+
+            //
+            // 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.
+            //
+            double dValue = doubleValue(true);
+            return stickyRound(dValue, roundDir);
+        }
+
+
+        /**
+         * 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
         };
 
-    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;
+        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")
-    public static FloatingDecimal
-    readJavaFormatString( String in ) throws NumberFormatException {
+    static ASCIIToBinaryConverter readJavaFormatString( String in ) throws NumberFormatException {
         boolean isNegative = false;
         boolean signSeen   = false;
         int     decExp;
@@ -1034,10 +1729,12 @@
         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 len = in.length();
+            if ( len == 0 ) {
+                throw new NumberFormatException("empty String");
+            }
             int i = 0;
-            switch ( c = in.charAt( i ) ){
+            switch (in.charAt(i)){
             case '-':
                 isNegative = true;
                 //FALLTHROUGH
@@ -1045,144 +1742,121 @@
                 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;
+            if(c == 'N') { // Check for NaN
+                if((len-i)==NAN_LENGTH && in.indexOf(NAN_REP,i)==i) {
+                    return A2BC_NOT_A_NUMBER;
                 }
-
-                // compare Input string to "NaN" or "Infinity"
-                int j = 0;
-                while(i < l && j < targetChars.length) {
-                    if(in.charAt(i) == targetChars[j]) {
-                        i++; j++;
+                // 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);
                     }
-                    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 FloatingDecimal(Double.NaN) // NaN has no sign
-                            : new FloatingDecimal(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 ];
+            char[] digits = new char[ len ];
             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 ){
+
+        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 ){
+                    if (signSeen) {
                         decPt -= 1;
                     }
                     decSeen = true;
-                    break; // out of switch.
-                default:
+                } 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++;
             }
-            /*
-             * 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
-                }
-
+            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.
-             */
+            //
+            // 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;
+                decExp = nDigits + nTrailZero;
             }
 
-            /*
-             * Look for 'e' or 'E' and an optionally signed integer.
-             */
-            if ( (i < l) &&  (((c = in.charAt(i) )=='e') || (c == 'E') ) ){
+            //
+            // 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;
@@ -1196,31 +1870,21 @@
                 }
                 int expAt = i;
             expLoop:
-                while ( i < l  ){
+                while ( i < len  ){
                     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':
+                    c = in.charAt(i++);
+                    if(c>='0' && c<='9') {
                         expVal = expVal*10 + ( (int)c - (int)'0' );
-                        continue;
-                    default:
+                    } else {
                         i--;           // back up.
                         break expLoop; // stop parsing exponent.
                     }
                 }
-                int expLimit = bigDecimalExponent+nDigits+nTrailZero;
+                int expLimit = BIG_DECIMAL_EXPONENT+nDigits+nTrailZero;
                 if ( expOverflow || ( expVal > expLimit ) ){
                     //
                     // The intent here is to end up with
@@ -1247,1182 +1911,588 @@
                 // but then some trailing garbage, that might be ok.
                 // so we just fall through in that case.
                 // HUMBUG
-                if ( i == expAt )
+                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) ||
+            //
+            // 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
             }
-
-            return new FloatingDecimal( isNegative, decExp, digits, nDigits,  false );
+            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 + "\"");
     }
 
-    /*
-     * 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.
+    /**
+     * Rounds 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.
      */
-
-    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;
-                }
+    static float stickyRound( double dval, int roundDirection ){
+        if(roundDirection!=0) {
+            long lbits = Double.doubleToRawLongBits( dval );
+            long binexp = lbits & DoubleConsts.EXP_BIT_MASK;
+            if ( binexp == 0L || binexp == DoubleConsts.EXP_BIT_MASK ){
+                // what we have here is special.
+                // don't worry, the right thing will happen.
+                return (float) dval;
             }
-
-            /*
-             * dValue is now approximately the result.
-             * The hard part is adjusting it, by comparison
-             * with FDBigInt arithmetic.
-             * Formulate the EXACT big-number result as
-             * bigD0 * 10^exp
-             */
-            FDBigInt bigD0 = new FDBigInt( lValue, digits, kDigits, nDigits );
-            exp   = decExponent - nDigits;
-
-            correctionLoop:
-            while(true){
-                /* AS A SIDE EFFECT, THIS METHOD WILL SET THE INSTANCE VARIABLES
-                 * bigIntExp and bigIntNBits
-                 */
-                FDBigInt 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 );
-                FDBigInt bigD = multPow52( new FDBigInt( 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.
-                //
-                FDBigInt 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;
-                }
-                FDBigInt 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 );
+            lbits += (long)roundDirection; // hack-o-matic.
+            return (float)Double.longBitsToDouble( lbits );
+        } else {
+            return (float)dval;
         }
     }
 
 
-    /*
-     * 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(
+    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]?"
                     );
-        }
-        return hexFloatPattern;
     }
 
-    /*
-     * Convert string s to a suitable floating decimal; uses the
-     * double constructor and set the roundDir variable appropriately
+    /**
+     * 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 FloatingDecimal 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 FloatingDecimal(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:
+   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.
                 //
-                //                      significand
-                //                      +               -
-                // exponent     +       +infinity       -infinity
-                //              -       +0.0            -0.0
-                return new FloatingDecimal(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);
+                // 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("-"));
 
-            /*
-             * 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;
+                //  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.
+                //
 
-                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 > DoubleConsts.MAX_EXPONENT) {         // Infinite result
-                // overflow to properly signed infinity
-                return new FloatingDecimal(sign * Double.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.
+                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();
 
-                    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)
+                        // fraction
+                        String group7 = m.group(7);
+                        rightDigits = group7.length();
 
-                    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 FloatingDecimal(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.
-                         */
+                        // Turn "integer.fraction" into "integer"+"fraction"
+                        significandString =
+                                ((group6 == null) ? "" : group6) + // is the null
+                                        // check necessary?
+                                        group7;
+                    }
 
-                        sticky = sticky || round;
-                        round = false;
+                    significandString = stripLeadingZeros(significandString);
+                    signifLength = significandString.length();
 
-                        // 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;
+                    //
+                    // 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);
+                    }
 
-                        // 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 ) ;
-                        }
+                    // If the significand is zero, the exponent doesn't
+                    // matter; return a properly signed zero.
 
-                        // 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);
+                    if (signifLength == 0) { // Only zeros in input
+                        return isNegative ? A2BC_NEGATIVE_ZERO : A2BC_POSITIVE_ZERO;
                     }
                 }
 
-                // The significand variable now contains the currently
-                // appropriate exponent bits too.
+                //  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...
 
-                /*
-                 * 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++;
+                // 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;
                 }
 
-                FloatingDecimal fd = new FloatingDecimal(Math.copySign(
-                                                              Double.longBitsToDouble(significand),
-                                                              sign));
+                // 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.
 
-                /*
-                 * 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 <= FloatConsts.MAX_EXPONENT ) ){
-                    // Outside above exponent range, the float value
-                    // will be zero or infinity.
+                    // 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 > 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;
 
-                    /*
-                     * 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;
+                            // 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 );
+
+                    int roundDir = 0;
+                    //
+                    // 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 <= FloatConsts.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) {
+                                        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) {
+                                        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;
-                            }
                         }
                     }
+                    return new PreparedASCIIToBinaryBuffer(value,roundDir);
                 }
-
-                fd.fromHex = true;
-                return fd;
             }
-        }
     }
 
     /**
-     * Return <code>s</code> with any leading zeros removed.
+     * Returns <code>s</code> with any leading zeros removed.
      */
     static String stripLeadingZeros(String s) {
-        return  s.replaceFirst("^0+", "");
+//        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;
     }
 
     /**
-     * Extract a hexadecimal digit from position <code>position</code>
+     * Extracts a hexadecimal digit from position <code>position</code>
      * of string <code>s</code>.
      */
     static int getHexDigit(String s, int position) {
@@ -2433,6 +2503,4 @@
         }
         return value;
     }
-
-
 }
--- a/jdk/src/share/classes/sun/misc/FormattedFloatingDecimal.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/misc/FormattedFloatingDecimal.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -25,422 +25,118 @@
 
 package sun.misc;
 
-import sun.misc.DoubleConsts;
-import sun.misc.FloatConsts;
-import java.util.regex.*;
+import java.util.Arrays;
 
 public class FormattedFloatingDecimal{
-    boolean     isExceptional;
-    boolean     isNegative;
-    int         decExponent;  // value set at construction, then immutable
-    int         decExponentRounded;
-    char        digits[];
-    int         nDigits;
-    int         bigIntExp;
-    int         bigIntNBits;
-    boolean     mustSetRoundDir = false;
-    boolean     fromHex = false;
-    int         roundDir = 0; // set by doubleValue
-    int         precision;    // number of digits to the right of decimal
 
     public enum Form { SCIENTIFIC, COMPATIBLE, DECIMAL_FLOAT, GENERAL };
 
-    private Form form;
+
+    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     FormattedFloatingDecimal( boolean negSign, int decExponent, char []digits, int n, boolean e, int precision, Form form )
-    {
-        isNegative = negSign;
-        isExceptional = e;
-        this.decExponent = decExponent;
-        this.digits = digits;
-        this.nDigits = n;
-        this.precision = precision;
-        this.form = form;
+    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();
     }
 
-    /*
-     * 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;
+    private FormattedFloatingDecimal(int precision, Form form, FloatingDecimal.BinaryToASCIIConverter fdConverter) {
+        if (fdConverter.isExceptional()) {
+            this.mantissa = fdConverter.toJavaFormatString().toCharArray();
+            this.exponent = null;
+            return;
         }
-
-        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 FDBigInt b5p[];
-
-    private static synchronized FDBigInt
-    big5pow( int p ){
-        assert p >= 0 : p; // negative power of 5
-        if ( b5p == null ){
-            b5p = new FDBigInt[ p+1 ];
-        }else if (b5p.length <= p ){
-            FDBigInt t[] = new FDBigInt[ 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 FDBigInt( small5pow[p] );
-        else if ( p < long5pow.length )
-            return b5p[p] = new FDBigInt( 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;
-            FDBigInt bigq =  b5p[q];
-            if ( bigq == null )
-                bigq = big5pow ( q );
-            if ( r < small5pow.length ){
-                return (b5p[p] = bigq.mult( small5pow[r] ) );
-            }else{
-                FDBigInt bigr = b5p[ r ];
-                if ( bigr == null )
-                    bigr = big5pow( r );
-                return (b5p[p] = bigq.mult( bigr ) );
-            }
+        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;
         }
     }
 
-    //
-    // a common operation
-    //
-    private static FDBigInt
-    multPow52( FDBigInt 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 FDBigInt
-    constructPow52( int p5, int p2 ){
-        FDBigInt v = new FDBigInt( big5pow( p5 ) );
-        if ( p2 != 0 ){
-            v.lshiftMe( p2 );
-        }
-        return v;
+    // returns the exponent after rounding has been done by applyPrecision
+    public int getExponentRounded() {
+        return decExponentRounded - 1;
     }
 
-    /*
-     * Make a floating double into a FDBigInt.
-     * This could also be structured as a FDBigInt
-     * 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 FDBigInt
-    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 FDBigInt( 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 );
+    public char[] getMantissa(){
+        return mantissa;
     }
 
-
-    /*
-     * 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;
+    public char[] getExponent(){
+        return exponent;
     }
 
-    //
-    // 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.
+    /**
+     * 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;
         }
-        digits[i] = (char)(q+1);
-    }
-
-    // Given the desired number of digits predict the result's exponent.
-    private int checkExponent(int length) {
-        if (length >= nDigits || length < 0)
-            return decExponent;
-
-        for (int i = 0; i < length; i++)
-            if (digits[i] != '9')
-                // a '9' anywhere in digits will absorb the round
-                return decExponent;
-        return decExponent + (digits[length] >= '5' ? 1 : 0);
-    }
-
-    // Unlike roundup(), this method does not modify digits.  It also
-    // rounds at a particular precision.
-    private char [] applyPrecision(int length) {
-        char [] result = new char[nDigits];
-        for (int i = 0; i < result.length; i++) result[i] = '0';
-
-        if (length >= nDigits || length < 0) {
-            // no rounding necessary
-            System.arraycopy(digits, 0, result, 0, nDigits);
-            return result;
-        }
-        if (length == 0) {
+        if (prec == 0) {
             // only one digit (0 or 1) is returned because the precision
             // excludes all significant digits
             if (digits[0] >= '5') {
-                result[0] = '1';
+                digits[0] = '1';
+                Arrays.fill(digits, 1, nDigits, '0');
+                return decExp + 1;
+            } else {
+                Arrays.fill(digits, 0, nDigits, '0');
+                return decExp;
             }
-            return result;
         }
-
-        int i = length;
-        int q = digits[i];
-        if (q >= '5' && i > 0) {
+        int q = digits[prec];
+        if (q >= '5') {
+            int i = prec;
             q = digits[--i];
             if ( q == '9' ) {
                 while ( q == '9' && i > 0 ){
@@ -448,1319 +144,206 @@
                 }
                 if ( q == '9' ){
                     // carryout! High-order 1, rest 0s, larger exp.
-                    result[0] = '1';
-                    return result;
+                    digits[0] = '1';
+                    Arrays.fill(digits, 1, nDigits, '0');
+                    return decExp+1;
                 }
             }
-            result[i] = (char)(q + 1);
-        }
-        while (--i >= 0) {
-            result[i] = digits[i];
-        }
-        return result;
-    }
-
-    /*
-     * FIRST IMPORTANT CONSTRUCTOR: DOUBLE
-     */
-    public FormattedFloatingDecimal( double d )
-    {
-        this(d, Integer.MAX_VALUE, Form.COMPATIBLE);
-    }
-
-    public FormattedFloatingDecimal( double d, int precision, Form form )
-    {
-        long    dBits = Double.doubleToLongBits( d );
-        long    fractBits;
-        int     binExp;
-        int     nSignificantBits;
-
-        this.precision = precision;
-        this.form      = form;
-
-        // discover and delete sign
-        if ( (dBits&signMask) != 0 ){
-            isNegative = true;
-            dBits ^= signMask;
+            digits[i] = (char)(q + 1);
+            Arrays.fill(digits, i+1, nDigits, '0');
         } 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;
+            Arrays.fill(digits, prec, nDigits, '0');
         }
-        binExp -= expBias;
-        // call the routine that actually does all the hard work.
-        dtoa( binExp, fractBits, nSignificantBits );
-    }
-
-    /*
-     * SECOND IMPORTANT CONSTRUCTOR: SINGLE
-     */
-    public FormattedFloatingDecimal( float f )
-    {
-        this(f, Integer.MAX_VALUE, Form.COMPATIBLE);
-    }
-    public FormattedFloatingDecimal( float f, int precision, Form form )
-    {
-        int     fBits = Float.floatToIntBits( f );
-        int     fractBits;
-        int     binExp;
-        int     nSignificantBits;
-
-        this.precision = precision;
-        this.form      = form;
-
-        // 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 );
+        return decExp;
     }
 
-    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;
-                 * }
-                 */
+    /**
+     * 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';
             }
-        }
-        /*
-         * 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.
-        FDBigInt 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
-         * FDBigInt. 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 assymetry 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 FDBigInt arithmetic.
-         * We use the same algorithms, except that we "normalize"
-         * our FDBigInts 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 assymetry 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);
+        } 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);
                 }
-                /*
-                 * 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 (! (form == Form.COMPATIBLE && -3 < decExp && 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;
+            } 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 {
-                // 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 (! (form == Form.COMPATIBLE && -3 < decExp && 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;
+                this.mantissa = create(isNegative, 1);
+                this.mantissa[startIndex] = '0';
             }
         } else {
-            FDBigInt tenSval;
-            int  shiftBias;
-
-            /*
-             * We really must do FDBigInt arithmetic.
-             * Fist, construct our FDBigInt initial values.
-             */
-            Bval = multPow52( new FDBigInt( 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--;
+            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 {
-                digits[ndigit++] = (char)('0' + q);
+                mantissa = create(isNegative, 3);
+                mantissa[startIndex] = digits[0];
+                mantissa[startIndex + 1] = '.';
+                mantissa[startIndex + 2] = '0';
             }
-            /*
-             * 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 (! (form == Form.COMPATIBLE && -3 < decExp && 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);
+            int e, expStartIntex;
+            boolean isNegExp = (exp <= 0);
+            if (isNegExp) {
+                e = -exp + 1;
+                expStartIntex = 1;
+            } else {
+                e = exp - 1;
+                expStartIntex = 0;
             }
-            if ( high && low ){
-                Bval.lshiftMe(1);
-                lowDigitDifference = Bval.cmp(tenSval);
-            } else
-                lowDigitDifference = 0L; // this here only for flow analysis!
-        }
-        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();
-                }
+            // 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 {
-                roundup();
+                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');
             }
         }
     }
 
-    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);
-    }
-
-    // returns the exponent before rounding
-    public int getExponent() {
-        return decExponent - 1;
-    }
-
-    // returns the exponent after rounding has been done by applyPrecision
-    public int getExponentRounded() {
-        return decExponentRounded - 1;
-    }
-
-    public 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;
+    private static char[] create(boolean isNegative, int size) {
+        if(isNegative) {
+            char[] r = new char[size +1];
+            r[0] = '-';
+            return r;
         } else {
-            char digits [] = this.digits;
-            int exp = decExponent;
-            switch (form) {
-            case COMPATIBLE:
-                break;
-            case DECIMAL_FLOAT:
-                exp = checkExponent(decExponent + precision);
-                digits = applyPrecision(decExponent + precision);
-                break;
-            case SCIENTIFIC:
-                exp = checkExponent(precision + 1);
-                digits = applyPrecision(precision + 1);
-                break;
-            case GENERAL:
-                exp = checkExponent(precision);
-                digits = applyPrecision(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--;
-                } else {
-                    form = Form.DECIMAL_FLOAT;
-                    precision = precision - exp;
-                }
-                break;
-            default:
-                assert false;
-            }
-            decExponentRounded = exp;
-
-            if (exp > 0
-                && ((form == Form.COMPATIBLE && (exp < 8))
-                    || (form == Form.DECIMAL_FLOAT)))
-            {
-                // print digits.digits.
-                int charLength = Math.min(nDigits, exp);
-                System.arraycopy(digits, 0, result, i, charLength);
-                i += charLength;
-                if (charLength < exp) {
-                    charLength = exp-charLength;
-                    for (int nz = 0; nz < charLength; nz++)
-                        result[i++] = '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.
-                    if (form == Form.COMPATIBLE) {
-                        result[i++] = '.';
-                        result[i++] = '0';
-                    }
-                } else {
-                    // 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 (form == Form.COMPATIBLE) {
-                        result[i++] = '.';
-                        if (charLength < nDigits) {
-                            int t = Math.min(nDigits - charLength, precision);
-                            System.arraycopy(digits, charLength, result, i, t);
-                            i += t;
-                        } else {
-                            result[i++] = '0';
-                        }
-                    } else {
-                        int t = Math.min(nDigits - charLength, precision);
-                        if (t > 0) {
-                            result[i++] = '.';
-                            System.arraycopy(digits, charLength, result, i, t);
-                            i += t;
-                        }
-                    }
-                }
-            } else if (exp <= 0
-                       && ((form == Form.COMPATIBLE && exp > -3)
-                       || (form == Form.DECIMAL_FLOAT)))
-            {
-                // print 0.0* digits
-                result[i++] = '0';
-                if (exp != 0) {
-                    // write '0' s before the significant digits
-                    int t = Math.min(-exp, precision);
-                    if (t > 0) {
-                        result[i++] = '.';
-                        for (int nz = 0; nz < t; nz++)
-                            result[i++] = '0';
-                    }
-                }
-                int t = Math.min(digits.length, precision + exp);
-                if (t > 0) {
-                    if (i == 1)
-                        result[i++] = '.';
-                    // copy only when significant digits are within the precision
-                    System.arraycopy(digits, 0, result, i, t);
-                    i += t;
-                }
-            } else {
-                result[i++] = digits[0];
-                if (form == Form.COMPATIBLE) {
-                    result[i++] = '.';
-                    if (nDigits > 1) {
-                        System.arraycopy(digits, 1, result, i, nDigits-1);
-                        i += nDigits-1;
-                    } else {
-                        result[i++] = '0';
-                    }
-                    result[i++] = 'E';
-                } else {
-                    if (nDigits > 1) {
-                        int t = Math.min(nDigits -1, precision);
-                        if (t > 0) {
-                            result[i++] = '.';
-                            System.arraycopy(digits, 1, result, i, t);
-                            i += t;
-                        }
-                    }
-                    result[i++] = 'e';
-                }
-                int e;
-                if (exp <= 0) {
-                    result[i++] = '-';
-                    e = -exp+1;
-                } else {
-                    if (form != Form.COMPATIBLE)
-                        result[i++] = '+';
-                    e = exp-1;
-                }
-                // decExponent has 1, 2, or 3, digits
-                if (e <= 9) {
-                    if (form != Form.COMPATIBLE)
-                        result[i++] = '0';
-                    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];
-            }
-        };
-
-    /*
-     * Take a FormattedFloatingDecimal, 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 FDBigInt arithmetic.
-             * Formulate the EXACT big-number result as
-             * bigD0 * 10^exp
-             */
-            FDBigInt bigD0 = new FDBigInt( lValue, digits, kDigits, nDigits );
-            exp   = decExponent - nDigits;
-
-            correctionLoop:
-            while(true){
-                /* AS A SIDE EFFECT, THIS METHOD WILL SET THE INSTANCE VARIABLES
-                 * bigIntExp and bigIntNBits
-                 */
-                FDBigInt bigB = doubleToBigInt( dValue );
-
-                /*
-                 * Scale bigD, bigB appropriately for
-                 * big-integer operations.
-                 * Naively, we multipy 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 );
-                FDBigInt bigD = multPow52( new FDBigInt( 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.
-                //
-                FDBigInt 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) ){
-                        // 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 fequency
-                    break correctionLoop;
-                }
-                FDBigInt 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;
+            return new char[size];
         }
     }
 
     /*
-     * Take a FormattedFloatingDecimal, 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 converstion
-     * 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 ).
+     * Fills mantissa char arrays for DECIMAL_FLOAT format.
+     * Exponent should be equal to null.
      */
-
-    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';
+    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);
+                }
             }
-            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 (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 ( (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;
-
+            } 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';
             }
-            /*
-             * 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
-             * algorythm 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.
+    /**
+     * Fills mantissa and exponent char arrays for SCIENTIFIC format.
      */
-    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' };
+    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/share/classes/sun/misc/Hashing.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/misc/Hashing.java	Mon Jun 10 10:38:33 2013 +0100
@@ -24,7 +24,7 @@
  */
 package sun.misc;
 
-import java.util.Random;
+import java.util.concurrent.ThreadLocalRandom;
 
 /**
  * Hashing utilities.
@@ -207,28 +207,16 @@
     }
 
     /**
-     * Holds references to things that can't be initialized until after VM
-     * is fully booted.
+     * Return a non-zero 32-bit pseudo random value. The {@code instance} object
+     * may be used as part of the value.
+     *
+     * @param instance an object to use if desired in choosing value.
+     * @return a non-zero 32-bit pseudo random value.
      */
-    private static class Holder {
-
-        /**
-         * Used for generating per-instance hash seeds.
-         *
-         * We try to improve upon the default seeding.
-         */
-        static final Random SEED_MAKER = new Random(
-                Double.doubleToRawLongBits(Math.random())
-                ^ System.identityHashCode(Hashing.class)
-                ^ System.currentTimeMillis()
-                ^ System.nanoTime()
-                ^ Runtime.getRuntime().freeMemory());
-    }
-
     public static int randomHashSeed(Object instance) {
         int seed;
         if (sun.misc.VM.isBooted()) {
-            seed = Holder.SEED_MAKER.nextInt();
+            seed = ThreadLocalRandom.current().nextInt();
         } else {
             // lower quality "random" seed value--still better than zero and not
             // not practically reversible.
--- a/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java	Mon Jun 10 10:38:33 2013 +0100
@@ -3158,6 +3158,7 @@
         private boolean marked = false;
         private int inCache = 0;
         private int markCount = 0;
+        private boolean closed;  // false
 
         public HttpInputStream (InputStream is) {
             super (is);
@@ -3233,8 +3234,14 @@
             }
         }
 
+        private void ensureOpen() throws IOException {
+            if (closed)
+                throw new IOException("stream is closed");
+        }
+
         @Override
         public int read() throws IOException {
+            ensureOpen();
             try {
                 byte[] b = new byte[1];
                 int ret = read(b);
@@ -3254,6 +3261,7 @@
 
         @Override
         public int read(byte[] b, int off, int len) throws IOException {
+            ensureOpen();
             try {
                 int newLen = super.read(b, off, len);
                 int nWrite;
@@ -3291,7 +3299,7 @@
 
         @Override
         public long skip (long n) throws IOException {
-
+            ensureOpen();
             long remaining = n;
             int nr;
             if (skipBuffer == null)
@@ -3317,6 +3325,9 @@
 
         @Override
         public void close () throws IOException {
+            if (closed)
+                return;
+
             try {
                 if (outputStream != null) {
                     if (read() != -1) {
@@ -3332,6 +3343,7 @@
                 }
                 throw ioex;
             } finally {
+                closed = true;
                 HttpURLConnection.this.http = null;
                 checkResponseCredentials (true);
             }
--- a/jdk/src/share/classes/sun/nio/cs/UTF_8.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/nio/cs/UTF_8.java	Mon Jun 10 10:38:33 2013 +0100
@@ -682,6 +682,11 @@
                 return encodeBufferLoop(src, dst);
         }
 
+        private byte repl = (byte)'?';
+        protected void implReplaceWith(byte[] newReplacement) {
+            repl = newReplacement[0];
+        }
+
         // returns -1 if there is malformed char(s) and the
         // "action" for malformed input is not REPLACE.
         public int encode(char[] sa, int sp, int len, byte[] da) {
@@ -709,7 +714,7 @@
                     if (uc < 0) {
                         if (malformedInputAction() != CodingErrorAction.REPLACE)
                             return -1;
-                        da[dp++] = replacement()[0];
+                        da[dp++] = repl;
                     } else {
                         da[dp++] = (byte)(0xf0 | ((uc >> 18)));
                         da[dp++] = (byte)(0x80 | ((uc >> 12) & 0x3f));
--- a/jdk/src/share/classes/sun/nio/cs/ext/DoubleByte.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/nio/cs/ext/DoubleByte.java	Mon Jun 10 10:38:33 2013 +0100
@@ -610,6 +610,11 @@
                 return encodeBufferLoop(src, dst);
         }
 
+        protected byte[] repl = replacement();
+        protected void implReplaceWith(byte[] newReplacement) {
+            repl = newReplacement;
+        }
+
         public int encode(char[] src, int sp, int len, byte[] dst) {
             int dp = 0;
             int sl = sp + len;
@@ -622,7 +627,6 @@
                         Character.isLowSurrogate(src[sp])) {
                         sp++;
                     }
-                    byte[] repl = replacement();
                     dst[dp++] = repl[0];
                     if (repl.length > 1)
                         dst[dp++] = repl[1];
@@ -877,7 +881,6 @@
                         Character.isLowSurrogate(src[sp])) {
                         sp++;
                     }
-                    byte[] repl = replacement();
                     dst[dp++] = repl[0];
                     if (repl.length > 1)
                         dst[dp++] = repl[1];
--- a/jdk/src/share/classes/sun/nio/cs/ext/HKSCS.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/nio/cs/ext/HKSCS.java	Mon Jun 10 10:38:33 2013 +0100
@@ -356,6 +356,11 @@
                 return encodeBufferLoop(src, dst);
         }
 
+        private byte[] repl = replacement();
+        protected void implReplaceWith(byte[] newReplacement) {
+            repl = newReplacement;
+        }
+
         public int encode(char[] src, int sp, int len, byte[] dst) {
             int dp = 0;
             int sl = sp + len;
@@ -367,7 +372,6 @@
                         !Character.isLowSurrogate(src[sp]) ||
                         (bb = encodeSupp(Character.toCodePoint(c, src[sp++])))
                         == UNMAPPABLE_ENCODING) {
-                        byte[] repl = replacement();
                         dst[dp++] = repl[0];
                         if (repl.length > 1)
                             dst[dp++] = repl[1];
--- a/jdk/src/share/classes/sun/rmi/rmic/Main.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/rmi/rmic/Main.java	Mon Jun 10 10:38:33 2013 +0100
@@ -879,9 +879,9 @@
         }
 
         String[] args = new String[3];
-        args[0] = (arg0 != null ? arg0.toString() : "null");
-        args[1] = (arg1 != null ? arg1.toString() : "null");
-        args[2] = (arg2 != null ? arg2.toString() : "null");
+        args[0] = (arg0 != null ? arg0 : "null");
+        args[1] = (arg1 != null ? arg1 : "null");
+        args[2] = (arg2 != null ? arg2 : "null");
 
         return java.text.MessageFormat.format(format, (Object[]) args);
     }
--- a/jdk/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java	Mon Jun 10 10:38:33 2013 +0100
@@ -78,7 +78,7 @@
 
     private final String tabName;
     private long lastModified;
-    private int kt_vno;
+    private int kt_vno = KRB5_KT_VNO;
 
     private Vector<KeyTabEntry> entries = new Vector<>();
 
--- a/jdk/src/share/classes/sun/security/pkcs11/P11KeyAgreement.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/security/pkcs11/P11KeyAgreement.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -330,7 +330,7 @@
                 // as here we always retrieve the CKA_VALUE even for tokens
                 // that do not have that bug.
                 byte[] keyBytes = key.getEncoded();
-                byte[] newBytes = P11Util.trimZeroes(keyBytes);
+                byte[] newBytes = KeyUtil.trimZeroes(keyBytes);
                 if (keyBytes != newBytes) {
                     key = new SecretKeySpec(newBytes, algorithm);
                 }
--- a/jdk/src/share/classes/sun/security/pkcs11/P11Signature.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/security/pkcs11/P11Signature.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -41,6 +41,7 @@
 
 import sun.security.pkcs11.wrapper.*;
 import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
+import sun.security.util.KeyUtil;
 
 /**
  * Signature implementation class. This class currently supports the
@@ -697,8 +698,8 @@
             BigInteger r = values[0].getPositiveBigInteger();
             BigInteger s = values[1].getPositiveBigInteger();
             // trim leading zeroes
-            byte[] br = P11Util.trimZeroes(r.toByteArray());
-            byte[] bs = P11Util.trimZeroes(s.toByteArray());
+            byte[] br = KeyUtil.trimZeroes(r.toByteArray());
+            byte[] bs = KeyUtil.trimZeroes(s.toByteArray());
             int k = Math.max(br.length, bs.length);
             // r and s each occupy half the array
             byte[] res = new byte[k << 1];
--- a/jdk/src/share/classes/sun/security/pkcs11/P11Util.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/security/pkcs11/P11Util.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -131,20 +131,6 @@
         return b;
     }
 
-    // trim leading (most significant) zeroes from the result
-    static byte[] trimZeroes(byte[] b) {
-        int i = 0;
-        while ((i < b.length - 1) && (b[i] == 0)) {
-            i++;
-        }
-        if (i == 0) {
-            return b;
-        }
-        byte[] t = new byte[b.length - i];
-        System.arraycopy(b, i, t, 0, t.length);
-        return t;
-    }
-
     public static byte[] getMagnitude(BigInteger bi) {
         byte[] b = bi.toByteArray();
         if ((b.length > 1) && (b[0] == 0)) {
--- a/jdk/src/share/classes/sun/security/provider/certpath/OCSPResponse.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/security/provider/certpath/OCSPResponse.java	Mon Jun 10 10:38:33 2013 +0100
@@ -552,7 +552,7 @@
 
         try {
             Signature respSignature = Signature.getInstance(sigAlgId.getName());
-            respSignature.initVerify(cert);
+            respSignature.initVerify(cert.getPublicKey());
             respSignature.update(tbsResponseData);
 
             if (respSignature.verify(signature)) {
--- a/jdk/src/share/classes/sun/security/tools/policytool/PolicyTool.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/security/tools/policytool/PolicyTool.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1447,6 +1447,7 @@
         PERM_ARRAY.add(new AWTPerm());
         PERM_ARRAY.add(new DelegationPerm());
         PERM_ARRAY.add(new FilePerm());
+        PERM_ARRAY.add(new HttpURLPerm());
         PERM_ARRAY.add(new InqSecContextPerm());
         PERM_ARRAY.add(new LogPerm());
         PERM_ARRAY.add(new MgmtPerm());
@@ -3842,6 +3843,20 @@
     }
 }
 
+class HttpURLPerm extends Perm {
+    public HttpURLPerm() {
+        super("HttpURLPermission",
+                "java.net.HttpURLPermission",
+                new String[]    {
+                    "<"+ PolicyTool.rb.getString("url") + ">",
+                },
+                new String[]    {
+                    "<" + PolicyTool.rb.getString("method.list") + ">:<"
+                        + PolicyTool.rb.getString("request.headers.list") + ">",
+                });
+    }
+}
+
 class InqSecContextPerm extends Perm {
     public InqSecContextPerm() {
     super("InquireSecContextPermission",
--- a/jdk/src/share/classes/sun/security/tools/policytool/Resources.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/security/tools/policytool/Resources.java	Mon Jun 10 10:38:33 2013 +0100
@@ -139,6 +139,9 @@
         {"policy.type", "policy type"},
         {"property.name", "property name"},
         {"provider.name", "provider name"},
+        {"url", "url"},
+        {"method.list", "method list"},
+        {"request.headers.list", "request headers list"},
         {"Principal.List", "Principal List"},
         {"Permission.List", "Permission List"},
         {"Code.Base", "Code Base"},
--- a/jdk/src/share/classes/sun/security/util/KeyUtil.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/security/util/KeyUtil.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -200,5 +200,24 @@
 
         // Don't bother to check against the y^q mod p if safe primes are used.
     }
+
+    /**
+     * Trim leading (most significant) zeroes from the result.
+     *
+     * @throws NullPointerException if {@code b} is null
+     */
+    public static byte[] trimZeroes(byte[] b) {
+        int i = 0;
+        while ((i < b.length - 1) && (b[i] == 0)) {
+            i++;
+        }
+        if (i == 0) {
+            return b;
+        }
+        byte[] t = new byte[b.length - i];
+        System.arraycopy(b, i, t, 0, t.length);
+        return t;
+    }
+
 }
 
--- a/jdk/src/share/classes/sun/text/resources/mt/FormatData_mt.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/text/resources/mt/FormatData_mt.java	Mon Jun 10 10:38:33 2013 +0100
@@ -54,7 +54,7 @@
                     "Mejju",
                     "\u0120unju",
                     "Lulju",
-                    "Awissu",
+                    "Awwissu",
                     "Settembru",
                     "Ottubru",
                     "Novembru",
@@ -71,7 +71,7 @@
                     "Mej",
                     "\u0120un",
                     "Lul",
-                    "Awi",
+                    "Aww",
                     "Set",
                     "Ott",
                     "Nov",
--- a/jdk/src/share/classes/sun/tools/java/MemberDefinition.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/tools/java/MemberDefinition.java	Mon Jun 10 10:38:33 2013 +0100
@@ -256,8 +256,8 @@
         }
         String name = this.name.toString();
         return name.startsWith(prefixVal)
-            || name.toString().startsWith(prefixLoc)
-            || name.toString().startsWith(prefixThis);
+            || name.startsWith(prefixLoc)
+            || name.startsWith(prefixThis);
     }
 
     public boolean isAccessMethod() {
--- a/jdk/src/share/classes/sun/tools/jconsole/AboutDialog.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/tools/jconsole/AboutDialog.java	Mon Jun 10 10:38:33 2013 +0100
@@ -34,6 +34,7 @@
 import javax.swing.border.*;
 import javax.swing.event.*;
 
+import static sun.misc.Version.jdkMinorVersion;
 
 import static java.awt.BorderLayout.*;
 import static sun.tools.jconsole.Utilities.*;
@@ -73,7 +74,7 @@
         String jConsoleVersion = Version.getVersion();
         String vmName = System.getProperty("java.vm.name");
         String vmVersion = System.getProperty("java.vm.version");
-        String urlStr = Messages.HELP_ABOUT_DIALOG_USER_GUIDE_LINK_URL;
+        String urlStr = getOnlineDocUrl();
         if (isBrowseSupported()) {
             urlStr = "<a style='color:#35556b' href=\"" + urlStr + "\">" + urlStr + "</a>";
         }
@@ -86,8 +87,7 @@
                                 "<html><font color=#"+ colorStr + ">" +
                         Resources.format(Messages.HELP_ABOUT_DIALOG_JCONSOLE_VERSION, jConsoleVersion) +
                 "<p>" + Resources.format(Messages.HELP_ABOUT_DIALOG_JAVA_VERSION, (vmName +", "+ vmVersion)) +
-                "<p>" + Resources.format(Messages.HELP_ABOUT_DIALOG_USER_GUIDE_LINK, urlStr) +
-                                                 "</html>");
+                "<p>" + urlStr + "</html>");
         helpLink.setOpaque(false);
         helpLink.setEditable(false);
         helpLink.setForeground(textColor);
@@ -153,7 +153,7 @@
     }
 
     static void browseUserGuide(JConsole jConsole) {
-        getAboutDialog(jConsole).browse(Messages.HELP_ABOUT_DIALOG_USER_GUIDE_LINK_URL);
+        getAboutDialog(jConsole).browse(getOnlineDocUrl());
     }
 
     static boolean isBrowseSupported() {
@@ -182,6 +182,12 @@
         };
     }
 
+    private static String getOnlineDocUrl() {
+        String version = Integer.toString(jdkMinorVersion());
+        return Resources.format(Messages.HELP_ABOUT_DIALOG_USER_GUIDE_LINK_URL,
+                                version);
+    }
+
     private static class TPanel extends JPanel {
         TPanel(int hgap, int vgap) {
             super(new BorderLayout(hgap, vgap));
--- a/jdk/src/share/classes/sun/tools/jconsole/SummaryTab.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/tools/jconsole/SummaryTab.java	Mon Jun 10 10:38:33 2013 +0100
@@ -360,6 +360,8 @@
                     Math.min(99F,
                              elapsedCpu / (elapsedTime * 10000F * result.nCPUs));
 
+                cpuUsage = Math.max(0F, cpuUsage);
+
                 getPlotter().addValues(result.timeStamp,
                                 Math.round(cpuUsage * Math.pow(10.0, CPU_DECIMALS)));
                 getInfoLabel().setText(Resources.format(Messages.CPU_USAGE_FORMAT,
--- a/jdk/src/share/classes/sun/tools/jconsole/VMPanel.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/tools/jconsole/VMPanel.java	Mon Jun 10 10:38:33 2013 +0100
@@ -55,6 +55,7 @@
     private VMInternalFrame vmIF = null;
     private static ArrayList<TabInfo> tabInfos = new ArrayList<TabInfo>();
     private boolean wasConnected = false;
+    private boolean userDisconnected = false;
     private boolean shouldUseSSL = true;
 
     // The everConnected flag keeps track of whether the window can be
@@ -126,6 +127,7 @@
                 if (connectedIconBounds != null && (e.getModifiers() & MouseEvent.BUTTON1_MASK) != 0 && connectedIconBounds.contains(e.getPoint())) {
 
                     if (isConnected()) {
+                        userDisconnected = true;
                         disconnect();
                         wasConnected = false;
                     } else {
@@ -453,6 +455,11 @@
     private void vmPanelDied() {
         disconnect();
 
+        if (userDisconnected) {
+            userDisconnected = false;
+            return;
+        }
+
         JOptionPane optionPane;
         String msgTitle, msgExplanation, buttonStr;
 
--- a/jdk/src/share/classes/sun/tools/jconsole/inspector/Utils.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/tools/jconsole/inspector/Utils.java	Mon Jun 10 10:38:33 2013 +0100
@@ -352,7 +352,7 @@
             result = new Character(value.charAt(0));
         } else if (Number.class.isAssignableFrom(Utils.getClass(type))) {
             result = createNumberFromStringValue(value);
-        } else if (value == null || value.toString().equals("null")) {
+        } else if (value == null || value.equals("null")) {
             // hack for null value
             result = null;
         } else {
--- a/jdk/src/share/classes/sun/tools/jconsole/resources/messages.properties	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/tools/jconsole/resources/messages.properties	Mon Jun 10 10:38:33 2013 +0100
@@ -105,7 +105,7 @@
 HELP_ABOUT_DIALOG_MASTHEAD_TITLE=About JConsole
 HELP_ABOUT_DIALOG_TITLE=JConsole: About
 HELP_ABOUT_DIALOG_USER_GUIDE_LINK=JConsole &User Guide:<br>{0}
-HELP_ABOUT_DIALOG_USER_GUIDE_LINK_URL=http://java.sun.com/javase/6/docs/technotes/guides/management/jconsole.html
+HELP_ABOUT_DIALOG_USER_GUIDE_LINK_URL=http://docs.oracle.com/javase/{0}/docs/technotes/guides/management/jconsole.html
 HELP_MENU_ABOUT_TITLE=&About JConsole
 HELP_MENU_USER_GUIDE_TITLE=Online &User Guide
 HELP_MENU_TITLE=&Help
--- a/jdk/src/share/classes/sun/tools/jconsole/resources/messages_ja.properties	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/tools/jconsole/resources/messages_ja.properties	Mon Jun 10 10:38:33 2013 +0100
@@ -105,7 +105,7 @@
 HELP_ABOUT_DIALOG_MASTHEAD_TITLE=JConsole\u306B\u3064\u3044\u3066
 HELP_ABOUT_DIALOG_TITLE=JConsole: \u8A73\u7D30
 HELP_ABOUT_DIALOG_USER_GUIDE_LINK=JConsole\u30E6\u30FC\u30B6\u30FC\u30FB\u30AC\u30A4\u30C9(&U):<br>{0}
-HELP_ABOUT_DIALOG_USER_GUIDE_LINK_URL=http://java.sun.com/javase/6/docs/technotes/guides/management/jconsole.html
+HELP_ABOUT_DIALOG_USER_GUIDE_LINK_URL=http://docs.oracle.com/javase/{0}/docs/technotes/guides/management/jconsole.html
 HELP_MENU_ABOUT_TITLE=JConsole\u306B\u3064\u3044\u3066(&A)
 HELP_MENU_USER_GUIDE_TITLE=\u30AA\u30F3\u30E9\u30A4\u30F3\u30FB\u30E6\u30FC\u30B6\u30FC\u30FB\u30AC\u30A4\u30C9(&U)
 HELP_MENU_TITLE=\u30D8\u30EB\u30D7(&H)
--- a/jdk/src/share/classes/sun/tools/jconsole/resources/messages_zh_CN.properties	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/tools/jconsole/resources/messages_zh_CN.properties	Mon Jun 10 10:38:33 2013 +0100
@@ -105,7 +105,7 @@
 HELP_ABOUT_DIALOG_MASTHEAD_TITLE=\u5173\u4E8E JConsole
 HELP_ABOUT_DIALOG_TITLE=JConsole: \u5173\u4E8E
 HELP_ABOUT_DIALOG_USER_GUIDE_LINK=JConsole \u7528\u6237\u6307\u5357(&U):<br>{0}
-HELP_ABOUT_DIALOG_USER_GUIDE_LINK_URL=http://java.sun.com/javase/6/docs/technotes/guides/management/jconsole.html
+HELP_ABOUT_DIALOG_USER_GUIDE_LINK_URL=http://docs.oracle.com/javase/{0}/docs/technotes/guides/management/jconsole.html
 HELP_MENU_ABOUT_TITLE=\u5173\u4E8E JConsole(&A)
 HELP_MENU_USER_GUIDE_TITLE=\u8054\u673A\u7528\u6237\u6307\u5357(&U)
 HELP_MENU_TITLE=\u5E2E\u52A9(&H)
--- a/jdk/src/share/classes/sun/util/locale/provider/FallbackLocaleProviderAdapter.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/util/locale/provider/FallbackLocaleProviderAdapter.java	Mon Jun 10 10:38:33 2013 +0100
@@ -25,6 +25,11 @@
 
 package sun.util.locale.provider;
 
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Set;
+
 /**
  * FallbackProviderAdapter implementation.
  *
@@ -33,10 +38,32 @@
 public class FallbackLocaleProviderAdapter extends JRELocaleProviderAdapter {
 
     /**
+     * Supported language tag set.
+     */
+    private static final Set<String> rootTagSet =
+        Collections.singleton(Locale.ROOT.toLanguageTag());
+
+    /**
+     * Fallback provider only provides the ROOT locale data.
+     */
+    private final LocaleResources rootLocaleResources =
+        new LocaleResources(this, Locale.ROOT);
+
+    /**
      * Returns the type of this LocaleProviderAdapter
      */
     @Override
     public LocaleProviderAdapter.Type getAdapterType() {
         return Type.FALLBACK;
     }
+
+    @Override
+    public LocaleResources getLocaleResources(Locale locale) {
+        return rootLocaleResources;
+    }
+
+    @Override
+    protected Set<String> createLanguageTagSet(String category) {
+        return rootTagSet;
+    }
 }
--- a/jdk/src/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java	Mon Jun 10 10:38:33 2013 +0100
@@ -34,12 +34,10 @@
 import java.text.spi.DateFormatSymbolsProvider;
 import java.text.spi.DecimalFormatSymbolsProvider;
 import java.text.spi.NumberFormatProvider;
-import java.util.Calendar;
 import java.util.HashSet;
 import java.util.Locale;
 import java.util.Set;
 import java.util.StringTokenizer;
-import java.util.TimeZone;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.spi.CalendarDataProvider;
--- a/jdk/src/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java	Mon Jun 10 10:38:33 2013 +0100
@@ -120,6 +120,12 @@
     private static LocaleProviderAdapter fallbackLocaleProviderAdapter = null;
 
     /**
+     * Default fallback adapter type, which should return something meaningful in any case.
+     * This is either JRE or FALLBACK.
+     */
+    static LocaleProviderAdapter.Type defaultLocaleProviderAdapter = null;
+
+    /**
      * Adapter lookup cache.
      */
     private static ConcurrentMap<Class<? extends LocaleServiceProvider>, ConcurrentMap<Locale, LocaleProviderAdapter>>
@@ -140,13 +146,19 @@
                     // load adapter if necessary
                     switch (aType) {
                         case CLDR:
-                            cldrLocaleProviderAdapter = new CLDRLocaleProviderAdapter();
+                            if (cldrLocaleProviderAdapter == null) {
+                                cldrLocaleProviderAdapter = new CLDRLocaleProviderAdapter();
+                            }
                             break;
                         case HOST:
-                            hostLocaleProviderAdapter = new HostLocaleProviderAdapter();
+                            if (hostLocaleProviderAdapter == null) {
+                                hostLocaleProviderAdapter = new HostLocaleProviderAdapter();
+                            }
                             break;
                     }
-                    typeList.add(aType);
+                    if (!typeList.contains(aType)) {
+                        typeList.add(aType);
+                    }
                 } catch (IllegalArgumentException | UnsupportedOperationException e) {
                     // could be caused by the user specifying wrong
                     // provider name or format in the system property
@@ -160,11 +172,15 @@
                 // Append FALLBACK as the last resort.
                 fallbackLocaleProviderAdapter = new FallbackLocaleProviderAdapter();
                 typeList.add(Type.FALLBACK);
+                defaultLocaleProviderAdapter = Type.FALLBACK;
+            } else {
+                defaultLocaleProviderAdapter = Type.JRE;
             }
         } else {
             // Default preference list
             typeList.add(Type.JRE);
             typeList.add(Type.SPI);
+            defaultLocaleProviderAdapter = Type.JRE;
         }
 
         adapterPreference = Collections.unmodifiableList(typeList);
--- a/jdk/src/share/classes/sun/util/locale/provider/LocaleServiceProviderPool.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/classes/sun/util/locale/provider/LocaleServiceProviderPool.java	Mon Jun 10 10:38:33 2013 +0100
@@ -127,32 +127,13 @@
     private LocaleServiceProviderPool (final Class<? extends LocaleServiceProvider> c) {
         providerClass = c;
 
-        // Add the JRE Locale Data Adapter implementation.
-        providers.putIfAbsent(LocaleProviderAdapter.Type.JRE,
-            LocaleProviderAdapter.forJRE().getLocaleServiceProvider(c));
-
-        // Add the SPI Locale Data Adapter implementation.
-        LocaleProviderAdapter lda = LocaleProviderAdapter.forType(LocaleProviderAdapter.Type.SPI);
-        LocaleServiceProvider provider = lda.getLocaleServiceProvider(c);
-        if (provider != null) {
-            providers.putIfAbsent(LocaleProviderAdapter.Type.SPI, provider);
-        }
-
-        // Add the CLDR Locale Data Adapter implementation, if needed.
-        lda =  LocaleProviderAdapter.forType(LocaleProviderAdapter.Type.CLDR);
-        if (lda != null) {
-            provider = lda.getLocaleServiceProvider(c);
-            if (provider != null) {
-                providers.putIfAbsent(LocaleProviderAdapter.Type.CLDR, provider);
-            }
-        }
-
-        // Add the Host Locale Data Adapter implementation, if needed.
-        lda =  LocaleProviderAdapter.forType(LocaleProviderAdapter.Type.HOST);
-        if (lda != null) {
-            provider = lda.getLocaleServiceProvider(c);
-            if (provider != null) {
-                providers.putIfAbsent(LocaleProviderAdapter.Type.HOST, provider);
+        for (LocaleProviderAdapter.Type type : LocaleProviderAdapter.getAdapterPreference()) {
+            LocaleProviderAdapter lda = LocaleProviderAdapter.forType(type);
+            if (lda != null) {
+                LocaleServiceProvider provider = lda.getLocaleServiceProvider(c);
+                if (provider != null) {
+                    providers.putIfAbsent(type, provider);
+                }
             }
         }
     }
@@ -246,7 +227,8 @@
      */
     boolean hasProviders() {
         return providers.size() != 1 ||
-               providers.get(LocaleProviderAdapter.Type.JRE) == null;
+               (providers.get(LocaleProviderAdapter.Type.JRE) == null &&
+                providers.get(LocaleProviderAdapter.Type.FALLBACK) == null);
     }
 
     /**
@@ -296,9 +278,8 @@
         // Check whether JRE is the sole locale data provider or not,
         // and directly call it if it is.
         if (!hasProviders()) {
-            return getter.getObject(
-                (P)providers.get(LocaleProviderAdapter.Type.JRE),
-                locale, key, params);
+            return getter.getObject((P)providers.get(LocaleProviderAdapter.defaultLocaleProviderAdapter),
+                                    locale, key, params);
         }
 
         List<Locale> lookupLocales = getLookupLocales(locale);
--- a/jdk/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipFileSystem.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipFileSystem.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1085,13 +1085,13 @@
     }
 
     // Creates a new empty temporary file in the same directory as the
-    // specified file.  A variant of File.createTempFile.
+    // specified file.  A variant of Files.createTempFile.
     private Path createTempFileInSameDirectoryAs(Path path)
         throws IOException
     {
         Path parent = path.toAbsolutePath().getParent();
-        String dir = (parent == null)? "." : parent.toString();
-        Path tmpPath = File.createTempFile("zipfstmp", null, new File(dir)).toPath();
+        Path dir = (parent == null) ? path.getFileSystem().getPath(".") : parent;
+        Path tmpPath = Files.createTempFile(dir, "zipfstmp", null);
         tmppaths.add(tmpPath);
         return tmpPath;
     }
@@ -1818,7 +1818,7 @@
 
         Entry(byte[] name) {
             name(name);
-            this.mtime  = System.currentTimeMillis();
+            this.mtime  = this.ctime = this.atime = System.currentTimeMillis();
             this.crc    = 0;
             this.size   = 0;
             this.csize  = 0;
@@ -1912,17 +1912,18 @@
         {
             int written  = CENHDR;
             int version0 = version();
-
             long csize0  = csize;
             long size0   = size;
             long locoff0 = locoff;
             int elen64   = 0;                // extra for ZIP64
             int elenNTFS = 0;                // extra for NTFS (a/c/mtime)
             int elenEXTT = 0;                // extra for Extended Timestamp
+            boolean foundExtraTime = false;  // if time stamp NTFS, EXTT present
 
             // confirm size/length
             int nlen = (name != null) ? name.length : 0;
             int elen = (extra != null) ? extra.length : 0;
+            int eoff = 0;
             int clen = (comment != null) ? comment.length : 0;
             if (csize >= ZIP64_MINVAL) {
                 csize0 = ZIP64_MINVAL;
@@ -1936,14 +1937,23 @@
                 locoff0 = ZIP64_MINVAL;
                 elen64 += 8;                 // offset(8)
             }
-            if (elen64 != 0)
+            if (elen64 != 0) {
                 elen64 += 4;                 // header and data sz 4 bytes
-
-            if (atime != -1) {
-                if (isWindows)               // use NTFS
+            }
+            while (eoff + 4 < elen) {
+                int tag = SH(extra, eoff);
+                int sz = SH(extra, eoff + 2);
+                if (tag == EXTID_EXTT || tag == EXTID_NTFS) {
+                    foundExtraTime = true;
+                }
+                eoff += (4 + sz);
+            }
+            if (!foundExtraTime) {
+                if (isWindows) {             // use NTFS
                     elenNTFS = 36;           // total 36 bytes
-                else                         // Extended Timestamp otherwise
+                } else {                     // Extended Timestamp otherwise
                     elenEXTT = 9;            // only mtime in cen
+                }
             }
             writeInt(os, CENSIG);            // CEN header signature
             if (elen64 != 0) {
@@ -1984,7 +1994,6 @@
                     writeLong(os, locoff);
             }
             if (elenNTFS != 0) {
-                // System.out.println("writing NTFS:" + elenNTFS);
                 writeShort(os, EXTID_NTFS);
                 writeShort(os, elenNTFS - 4);
                 writeInt(os, 0);            // reserved
@@ -2092,11 +2101,13 @@
         {
             writeInt(os, LOCSIG);               // LOC header signature
             int version = version();
-
             int nlen = (name != null) ? name.length : 0;
             int elen = (extra != null) ? extra.length : 0;
+            boolean foundExtraTime = false;     // if extra timestamp present
+            int eoff = 0;
             int elen64 = 0;
             int elenEXTT = 0;
+            int elenNTFS = 0;
             if ((flag & FLAG_DATADESCR) != 0) {
                 writeShort(os, version());      // version needed to extract
                 writeShort(os, flag);           // general purpose bit flag
@@ -2128,14 +2139,27 @@
                     writeInt(os, size);         // uncompressed size
                 }
             }
-            if (atime != -1 && !isWindows) {    // on unix use "ext time"
-                if (ctime == -1)
-                    elenEXTT = 13;
-                else
-                    elenEXTT = 17;
+            while (eoff + 4 < elen) {
+                int tag = SH(extra, eoff);
+                int sz = SH(extra, eoff + 2);
+                if (tag == EXTID_EXTT || tag == EXTID_NTFS) {
+                    foundExtraTime = true;
+                }
+                eoff += (4 + sz);
+            }
+            if (!foundExtraTime) {
+                if (isWindows) {
+                    elenNTFS = 36;              // NTFS, total 36 bytes
+                } else {                        // on unix use "ext time"
+                    elenEXTT = 9;
+                    if (atime != -1)
+                        elenEXTT += 4;
+                    if (ctime != -1)
+                        elenEXTT += 4;
+                }
             }
             writeShort(os, name.length);
-            writeShort(os, elen + elen64 + elenEXTT);
+            writeShort(os, elen + elen64 + elenNTFS + elenEXTT);
             writeBytes(os, name);
             if (elen64 != 0) {
                 writeShort(os, EXTID_ZIP64);
@@ -2143,22 +2167,35 @@
                 writeLong(os, size);
                 writeLong(os, csize);
             }
+            if (elenNTFS != 0) {
+                writeShort(os, EXTID_NTFS);
+                writeShort(os, elenNTFS - 4);
+                writeInt(os, 0);            // reserved
+                writeShort(os, 0x0001);     // NTFS attr tag
+                writeShort(os, 24);
+                writeLong(os, javaToWinTime(mtime));
+                writeLong(os, javaToWinTime(atime));
+                writeLong(os, javaToWinTime(ctime));
+            }
             if (elenEXTT != 0) {
                 writeShort(os, EXTID_EXTT);
                 writeShort(os, elenEXTT - 4);// size for the folowing data block
-                if (ctime == -1)
-                    os.write(0x3);           // mtime and atime
-                else
-                    os.write(0x7);           // mtime, atime and ctime
+                int fbyte = 0x1;
+                if (atime != -1)           // mtime and atime
+                    fbyte |= 0x2;
+                if (ctime != -1)           // mtime, atime and ctime
+                    fbyte |= 0x4;
+                os.write(fbyte);           // flags byte
                 writeInt(os, javaToUnixTime(mtime));
-                writeInt(os, javaToUnixTime(atime));
+                if (atime != -1)
+                    writeInt(os, javaToUnixTime(atime));
                 if (ctime != -1)
                     writeInt(os, javaToUnixTime(ctime));
             }
             if (extra != null) {
                 writeBytes(os, extra);
             }
-            return LOCHDR + name.length + elen + elen64 + elenEXTT;
+            return LOCHDR + name.length + elen + elen64 + elenNTFS + elenEXTT;
         }
 
         // Data Descriptior
--- a/jdk/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipInfo.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipInfo.java	Mon Jun 10 10:38:33 2013 +0100
@@ -214,7 +214,7 @@
                       winToJavaTime(LL(extra, off + 24)));
                 break;
             case EXTID_EXTT:
-                print("         ->Inof-ZIP Extended Timestamp: flag=%x%n",extra[off]);
+                print("         ->Info-ZIP Extended Timestamp: flag=%x%n",extra[off]);
                 pos = off + 1 ;
                 while (pos + 4 <= off + sz) {
                     print("            *%tc%n",
@@ -223,6 +223,7 @@
                 }
                 break;
             default:
+                print("         ->[tag=%x, size=%d]%n", tag, sz);
             }
             off += sz;
         }
--- a/jdk/src/share/javavm/export/jmm.h	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/javavm/export/jmm.h	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -49,7 +49,8 @@
   JMM_VERSION_1_1 = 0x20010100, // JDK 6
   JMM_VERSION_1_2 = 0x20010200, // JDK 7
   JMM_VERSION_1_2_1 = 0x20010201, // JDK 7 GA
-  JMM_VERSION     = 0x20010202
+  JMM_VERSION_1_2_2 = 0x20010202,
+  JMM_VERSION     = 0x20010203
 };
 
 typedef struct {
@@ -62,7 +63,8 @@
   unsigned int isObjectMonitorUsageSupported : 1;
   unsigned int isSynchronizerUsageSupported : 1;
   unsigned int isThreadAllocatedMemorySupported : 1;
-  unsigned int : 23;
+  unsigned int isRemoteDiagnosticCommandsSupported : 1;
+  unsigned int : 22;
 } jmmOptionalSupport;
 
 typedef enum {
@@ -190,21 +192,27 @@
 } jmmGCStat;
 
 typedef struct {
-  const char* name;
-  const char* description;
-  const char* impact;
-  int         num_arguments;
-  jboolean    enabled;
+  const char* name;                /* Name of the diagnostic command */
+  const char* description;         /* Short description */
+  const char* impact;              /* Impact on the JVM */
+  const char* permission_class;    /* Class name of the required permission if any */
+  const char* permission_name;     /* Permission name of the required permission if any */
+  const char* permission_action;   /* Action name of the required permission if any*/
+  int         num_arguments;       /* Number of supported options or arguments */
+  jboolean    enabled;             /* True if the diagnostic command can be invoked, false otherwise*/
 } dcmdInfo;
 
 typedef struct {
-  const char* name;
-  const char* description;
-  const char* type;
-  const char* default_string;
-  jboolean    mandatory;
-  jboolean    option;
-  int         position;
+  const char* name;                /* Option/Argument name*/
+  const char* description;         /* Short description */
+  const char* type;                /* Type: STRING, BOOLEAN, etc. */
+  const char* default_string;      /* Default value in a parsable string */
+  jboolean    mandatory;           /* True if the option/argument is mandatory */
+  jboolean    option;              /* True if it is an option, false if it is an argument */
+                                   /* (see diagnosticFramework.hpp for option/argument definitions) */
+  jboolean    multiple;            /* True is the option can be specified several time */
+  int         position;            /* Expected position for this argument (this field is */
+                                   /* meaningless for options) */
 } dcmdArgInfo;
 
 typedef struct jmmInterface_1_ {
@@ -327,6 +335,9 @@
   jstring      (JNICALL *ExecuteDiagnosticCommand)
                                                  (JNIEnv *env,
                                                   jstring command);
+  void         (JNICALL *SetDiagnosticFrameworkNotificationEnabled)
+                                                 (JNIEnv *env,
+                                                  jboolean enabled);
 } JmmInterface;
 
 #ifdef __cplusplus
--- a/jdk/src/share/javavm/export/jvm.h	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/javavm/export/jvm.h	Mon Jun 10 10:38:33 2013 +0100
@@ -441,9 +441,6 @@
 JNIEXPORT jobject JNICALL
 JVM_GetProtectionDomain(JNIEnv *env, jclass cls);
 
-JNIEXPORT void JNICALL
-JVM_SetProtectionDomain(JNIEnv *env, jclass cls, jobject protection_domain);
-
 JNIEXPORT jboolean JNICALL
 JVM_IsArrayClass(JNIEnv *env, jclass cls);
 
--- a/jdk/src/share/lib/security/java.security-linux	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/lib/security/java.security-linux	Mon Jun 10 10:38:33 2013 +0100
@@ -177,6 +177,7 @@
 # corresponding RuntimePermission ("accessClassInPackage."+package) has
 # been granted.
 package.access=sun.,\
+               com.sun.corba.se.impl.,\
                com.sun.xml.internal.,\
                com.sun.imageio.,\
                com.sun.istack.internal.,\
@@ -220,6 +221,7 @@
 # checkPackageDefinition.
 #
 package.definition=sun.,\
+                   com.sun.corba.se.impl.,\
                    com.sun.xml.internal.,\
                    com.sun.imageio.,\
                    com.sun.istack.internal.,\
--- a/jdk/src/share/lib/security/java.security-macosx	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/lib/security/java.security-macosx	Mon Jun 10 10:38:33 2013 +0100
@@ -178,6 +178,7 @@
 # corresponding RuntimePermission ("accessClassInPackage."+package) has
 # been granted.
 package.access=sun.,\
+               com.sun.corba.se.impl.,\
                com.sun.xml.internal.,\
                com.sun.imageio.,\
                com.sun.istack.internal.,\
@@ -221,6 +222,7 @@
 # checkPackageDefinition.
 #
 package.definition=sun.,\
+                   com.sun.corba.se.impl.,\
                    com.sun.xml.internal.,\
                    com.sun.imageio.,\
                    com.sun.istack.internal.,\
--- a/jdk/src/share/lib/security/java.security-solaris	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/lib/security/java.security-solaris	Mon Jun 10 10:38:33 2013 +0100
@@ -179,6 +179,7 @@
 # corresponding RuntimePermission ("accessClassInPackage."+package) has
 # been granted.
 package.access=sun.,\
+               com.sun.corba.se.impl.,\
                com.sun.xml.internal.,\
                com.sun.imageio.,\
                com.sun.istack.internal.,\
@@ -221,6 +222,7 @@
 # checkPackageDefinition.
 #
 package.definition=sun.,\
+                   com.sun.corba.se.impl.,\
                    com.sun.xml.internal.,\
                    com.sun.imageio.,\
                    com.sun.istack.internal.,\
--- a/jdk/src/share/lib/security/java.security-windows	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/lib/security/java.security-windows	Mon Jun 10 10:38:33 2013 +0100
@@ -178,6 +178,7 @@
 # corresponding RuntimePermission ("accessClassInPackage."+package) has
 # been granted.
 package.access=sun.,\
+               com.sun.corba.se.impl.,\
                com.sun.xml.internal.,\
                com.sun.imageio.,\
                com.sun.istack.internal.,\
@@ -221,6 +222,7 @@
 # checkPackageDefinition.
 #
 package.definition=sun.,\
+                   com.sun.corba.se.impl.,\
                    com.sun.xml.internal.,\
                    com.sun.imageio.,\
                    com.sun.istack.internal.,\
--- a/jdk/src/share/native/java/io/FileInputStream.c	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/native/java/io/FileInputStream.c	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -100,6 +100,8 @@
     if (IO_Available(fd, &ret)) {
         if (ret > INT_MAX) {
             ret = (jlong) INT_MAX;
+        } else if (ret < 0) {
+            ret = 0;
         }
         return jlong_to_jint(ret);
     }
--- a/jdk/src/share/native/java/lang/Class.c	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/native/java/lang/Class.c	Mon Jun 10 10:38:33 2013 +0100
@@ -68,7 +68,6 @@
     {"getDeclaredMethods0","(Z)[" MHD,      (void *)&JVM_GetClassDeclaredMethods},
     {"getDeclaredConstructors0","(Z)[" CTR, (void *)&JVM_GetClassDeclaredConstructors},
     {"getProtectionDomain0", "()" PD,       (void *)&JVM_GetProtectionDomain},
-    {"setProtectionDomain0", "(" PD ")V",   (void *)&JVM_SetProtectionDomain},
     {"getDeclaredClasses0",  "()[" CLS,      (void *)&JVM_GetDeclaredClasses},
     {"getDeclaringClass",   "()" CLS,      (void *)&JVM_GetDeclaringClass},
     {"getGenericSignature", "()" STR,       (void *)&JVM_GetClassSignature},
--- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscgats.c	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscgats.c	Mon Jun 10 10:38:33 2013 +0100
@@ -634,6 +634,8 @@
     cmsFloat64Number dnum = 0.0;
     int sign = 1;
 
+    if (Buffer == NULL) return 0.0;
+
     if (*Buffer == '-' || *Buffer == '+') {
 
          sign = (*Buffer == '-') ? -1 : 1;
--- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c	Mon Jun 10 10:38:33 2013 +0100
@@ -1022,6 +1022,7 @@
     cmsFreeToneCurveTriple(LabTable);
 
     if (mpe == NULL) return mpe;
+
     mpe ->Implements = cmsSigLabV2toV4;
     return mpe;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/native/sun/management/DiagnosticCommandImpl.c	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,169 @@
+/*
+ * 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.
+ */
+
+#include <jni.h>
+#include "management.h"
+#include "sun_management_DiagnosticCommandImpl.h"
+
+JNIEXPORT void JNICALL Java_sun_management_DiagnosticCommandImpl_setNotificationEnabled
+(JNIEnv *env, jobject dummy, jboolean enabled) {
+    if(jmm_version > JMM_VERSION_1_2_2) {
+        jmm_interface->SetDiagnosticFrameworkNotificationEnabled(env, enabled);
+    } else {
+        JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+                        "JMX interface to diagnostic framework notifications is not supported by this VM");
+    }
+}
+
+JNIEXPORT jobjectArray JNICALL
+Java_sun_management_DiagnosticCommandImpl_getDiagnosticCommands
+  (JNIEnv *env, jobject dummy)
+{
+  return jmm_interface->GetDiagnosticCommands(env);
+}
+
+jobject getDiagnosticCommandArgumentInfoArray(JNIEnv *env, jstring command,
+                                              int num_arg) {
+  int i;
+  jobject obj;
+  jobjectArray result;
+  dcmdArgInfo* dcmd_arg_info_array;
+  jclass dcmdArgInfoCls;
+  jclass arraysCls;
+  jmethodID mid;
+  jobject resultList;
+
+  dcmd_arg_info_array = (dcmdArgInfo*) malloc(num_arg * sizeof(dcmdArgInfo));
+  if (dcmd_arg_info_array == NULL) {
+    return NULL;
+  }
+  jmm_interface->GetDiagnosticCommandArgumentsInfo(env, command,
+                                                   dcmd_arg_info_array);
+  dcmdArgInfoCls = (*env)->FindClass(env,
+                                     "sun/management/DiagnosticCommandArgumentInfo");
+  result = (*env)->NewObjectArray(env, num_arg, dcmdArgInfoCls, NULL);
+  if (result == NULL) {
+    free(dcmd_arg_info_array);
+    return NULL;
+  }
+  for (i=0; i<num_arg; i++) {
+    obj = JNU_NewObjectByName(env,
+                              "sun/management/DiagnosticCommandArgumentInfo",
+                              "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZZI)V",
+                              (*env)->NewStringUTF(env,dcmd_arg_info_array[i].name),
+                              (*env)->NewStringUTF(env,dcmd_arg_info_array[i].description),
+                              (*env)->NewStringUTF(env,dcmd_arg_info_array[i].type),
+                              dcmd_arg_info_array[i].default_string == NULL ? NULL:
+                              (*env)->NewStringUTF(env, dcmd_arg_info_array[i].default_string),
+                              dcmd_arg_info_array[i].mandatory,
+                              dcmd_arg_info_array[i].option,
+                              dcmd_arg_info_array[i].multiple,
+                              dcmd_arg_info_array[i].position);
+    if (obj == NULL) {
+      free(dcmd_arg_info_array);
+      return NULL;
+    }
+    (*env)->SetObjectArrayElement(env, result, i, obj);
+  }
+  free(dcmd_arg_info_array);
+  arraysCls = (*env)->FindClass(env, "java/util/Arrays");
+  mid = (*env)->GetStaticMethodID(env, arraysCls,
+                                  "asList", "([Ljava/lang/Object;)Ljava/util/List;");
+  resultList = (*env)->CallStaticObjectMethod(env, arraysCls, mid, result);
+  return resultList;
+}
+
+/* Throws IllegalArgumentException if at least one of the diagnostic command
+ * passed in argument is not supported by the JVM
+ */
+JNIEXPORT jobjectArray JNICALL
+Java_sun_management_DiagnosticCommandImpl_getDiagnosticCommandInfo
+(JNIEnv *env, jobject dummy, jobjectArray commands)
+{
+  int i;
+  jclass dcmdInfoCls;
+  jobject result;
+  jobjectArray args;
+  jobject obj;
+  jmmOptionalSupport mos;
+  jint ret = jmm_interface->GetOptionalSupport(env, &mos);
+  jsize num_commands;
+  dcmdInfo* dcmd_info_array;
+
+  if (commands == NULL) {
+      JNU_ThrowNullPointerException(env, "Invalid String Array");
+      return NULL;
+  }
+  num_commands = (*env)->GetArrayLength(env, commands);
+  dcmd_info_array = (dcmdInfo*) malloc(num_commands *
+                                       sizeof(dcmdInfo));
+  if (dcmd_info_array == NULL) {
+      JNU_ThrowOutOfMemoryError(env, NULL);
+  }
+  jmm_interface->GetDiagnosticCommandInfo(env, commands, dcmd_info_array);
+  dcmdInfoCls = (*env)->FindClass(env,
+                                  "sun/management/DiagnosticCommandInfo");
+  result = (*env)->NewObjectArray(env, num_commands, dcmdInfoCls, NULL);
+  if (result == NULL) {
+      free(dcmd_info_array);
+      JNU_ThrowOutOfMemoryError(env, 0);
+  }
+  for (i=0; i<num_commands; i++) {
+      args = getDiagnosticCommandArgumentInfoArray(env,
+                                                   (*env)->GetObjectArrayElement(env,commands,i),
+                                                   dcmd_info_array[i].num_arguments);
+      if (args == NULL) {
+          free(dcmd_info_array);
+          JNU_ThrowOutOfMemoryError(env, 0);
+      }
+      obj = JNU_NewObjectByName(env,
+                                "sun/management/DiagnosticCommandInfo",
+                                "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZLjava/util/List;)V",
+                                (*env)->NewStringUTF(env,dcmd_info_array[i].name),
+                                (*env)->NewStringUTF(env,dcmd_info_array[i].description),
+                                (*env)->NewStringUTF(env,dcmd_info_array[i].impact),
+                                dcmd_info_array[i].permission_class==NULL?NULL:(*env)->NewStringUTF(env,dcmd_info_array[i].permission_class),
+                                dcmd_info_array[i].permission_name==NULL?NULL:(*env)->NewStringUTF(env,dcmd_info_array[i].permission_name),
+                                dcmd_info_array[i].permission_action==NULL?NULL:(*env)->NewStringUTF(env,dcmd_info_array[i].permission_action),
+                                dcmd_info_array[i].enabled,
+                                args);
+      if (obj == NULL) {
+          free(dcmd_info_array);
+          JNU_ThrowOutOfMemoryError(env, 0);
+      }
+      (*env)->SetObjectArrayElement(env, result, i, obj);
+  }
+  free(dcmd_info_array);
+  return result;
+}
+
+/* Throws IllegalArgumentException if the diagnostic command
+ * passed in argument is not supported by the JVM
+ */
+JNIEXPORT jstring JNICALL
+Java_sun_management_DiagnosticCommandImpl_executeDiagnosticCommand
+(JNIEnv *env, jobject dummy, jstring command) {
+  return jmm_interface->ExecuteDiagnosticCommand(env, command);
+}
--- a/jdk/src/share/native/sun/management/VMManagementImpl.c	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/share/native/sun/management/VMManagementImpl.c	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -24,6 +24,7 @@
  */
 
 #include <jni.h>
+#include <stdlib.h>
 #include "jvm.h"
 #include "management.h"
 #include "sun_management_VMManagementImpl.h"
@@ -96,6 +97,9 @@
     value = mos.isThreadAllocatedMemorySupported;
     setStaticBooleanField(env, cls, "threadAllocatedMemorySupport", value);
 
+    value = mos.isRemoteDiagnosticCommandsSupported;
+    setStaticBooleanField(env, cls, "remoteDiagnosticCommandsSupport", value);
+
     if ((jmm_version > JMM_VERSION_1_2) ||
         (jmm_version == JMM_VERSION_1_2 && ((jmm_version&0xFF) >= 1))) {
         setStaticBooleanField(env, cls, "gcNotificationSupport", JNI_TRUE);
--- a/jdk/src/solaris/bin/arm/jvm.cfg	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/solaris/bin/arm/jvm.cfg	Mon Jun 10 10:38:33 2013 +0100
@@ -30,6 +30,6 @@
 # "-XXaltjvm=<jvm_dir>" option, but that too is unsupported
 # and may not be available in a future release.
 #
--client KNOWN
+-client IF_SERVER_CLASS -server
 -server KNOWN
 -minimal KNOWN
--- a/jdk/src/solaris/bin/java_md_solinux.c	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/solaris/bin/java_md_solinux.c	Mon Jun 10 10:38:33 2013 +0100
@@ -649,9 +649,9 @@
                         && (dmpath == NULL) /* data model specific variables not set  */
 #endif /* __solaris__ */
                         ) {
-
+                    JLI_MemFree(newargv);
+                    JLI_MemFree(new_runpath);
                     return;
-
                 }
             }
 
@@ -935,7 +935,7 @@
         char buf[PATH_MAX+1];
         int len = readlink(self, buf, PATH_MAX);
         if (len >= 0) {
-            buf[len] = '\0';            /* readlink doesn't nul terminate */
+            buf[len] = '\0';            /* readlink(2) doesn't NUL terminate */
             exec_path = JLI_StringDup(buf);
         }
     }
--- a/jdk/src/solaris/classes/sun/awt/X11/MotifDnDConstants.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/solaris/classes/sun/awt/X11/MotifDnDConstants.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -190,7 +190,7 @@
                 try {
                     Native.putLong(data, motifWindow);
 
-                    XToolkit.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
+                    XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
                     XlibWrapper.XChangeProperty(XToolkit.getDisplay(),
                                                 defaultRootWindow,
                                                 XA_MOTIF_DRAG_WINDOW.getAtom(),
@@ -198,10 +198,10 @@
                                                 XConstants.PropModeReplace,
                                                 data, 1);
 
-                    XToolkit.RESTORE_XERROR_HANDLER();
+                    XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
 
-                    if (XToolkit.saved_error != null &&
-                        XToolkit.saved_error.get_error_code() != XConstants.Success) {
+                    if ((XErrorHandlerUtil.saved_error != null) &&
+                        (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {
                         throw new XException("Cannot write motif drag window handle.");
                     }
 
@@ -394,7 +394,7 @@
                 }
             }
 
-            XToolkit.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
+            XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
             XlibWrapper.XChangeProperty(XToolkit.getDisplay(),
                                         motifWindow,
                                         XA_MOTIF_DRAG_TARGETS.getAtom(),
@@ -402,15 +402,15 @@
                                         XConstants.PropModeReplace,
                                         data, tableSize);
 
-            XToolkit.RESTORE_XERROR_HANDLER();
+            XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
 
-            if (XToolkit.saved_error != null &&
-                XToolkit.saved_error.get_error_code() != XConstants.Success) {
+            if ((XErrorHandlerUtil.saved_error != null) &&
+                (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {
 
                 // Create a new motif window and retry.
                 motifWindow = createMotifWindow();
 
-                XToolkit.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
+                XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
                 XlibWrapper.XChangeProperty(XToolkit.getDisplay(),
                                             motifWindow,
                                             XA_MOTIF_DRAG_TARGETS.getAtom(),
@@ -418,10 +418,10 @@
                                             XConstants.PropModeReplace,
                                             data, tableSize);
 
-                XToolkit.RESTORE_XERROR_HANDLER();
+                XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
 
-                if (XToolkit.saved_error != null &&
-                    XToolkit.saved_error.get_error_code() != XConstants.Success) {
+                if ((XErrorHandlerUtil.saved_error != null) &&
+                    (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {
                     throw new XException("Cannot write motif drag targets property.");
                 }
             }
@@ -534,16 +534,16 @@
             // CARD32 icc_handle
             unsafe.putInt(structData + 4, (int)XA_MOTIF_ATOM_0.getAtom());
 
-            XToolkit.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
+            XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
             XlibWrapper.XChangeProperty(XToolkit.getDisplay(), window,
                                         XA_MOTIF_ATOM_0.getAtom(),
                                         XA_MOTIF_DRAG_INITIATOR_INFO.getAtom(),
                                         8, XConstants.PropModeReplace,
                                         structData, MOTIF_INITIATOR_INFO_SIZE);
-            XToolkit.RESTORE_XERROR_HANDLER();
+            XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
 
-            if (XToolkit.saved_error != null &&
-                XToolkit.saved_error.get_error_code() != XConstants.Success) {
+            if ((XErrorHandlerUtil.saved_error != null) &&
+                (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {
                 throw new XException("Cannot write drag initiator info");
             }
         } finally {
@@ -567,16 +567,16 @@
             unsafe.putShort(data + 10, (short)0); /* pad */
             unsafe.putInt(data + 12, dataSize);
 
-            XToolkit.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
+            XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
             XlibWrapper.XChangeProperty(XToolkit.getDisplay(), window,
                                         XA_MOTIF_DRAG_RECEIVER_INFO.getAtom(),
                                         XA_MOTIF_DRAG_RECEIVER_INFO.getAtom(),
                                         8, XConstants.PropModeReplace,
                                         data, dataSize);
-            XToolkit.RESTORE_XERROR_HANDLER();
+            XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
 
-            if (XToolkit.saved_error != null &&
-                XToolkit.saved_error.get_error_code() != XConstants.Success) {
+            if ((XErrorHandlerUtil.saved_error != null) &&
+                (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {
                 throw new XException("Cannot write Motif receiver info property");
             }
         } finally {
--- a/jdk/src/solaris/classes/sun/awt/X11/MotifDnDDropTargetProtocol.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/solaris/classes/sun/awt/X11/MotifDnDDropTargetProtocol.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -162,16 +162,16 @@
                 unsafe.putInt(data + 12, dataSize);
             }
 
-            XToolkit.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
+            XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
             XlibWrapper.XChangeProperty(XToolkit.getDisplay(), embedder,
                                         MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO.getAtom(),
                                         MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO.getAtom(),
                                         8, XConstants.PropModeReplace,
                                         data, dataSize);
-            XToolkit.RESTORE_XERROR_HANDLER();
+            XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
 
-            if (XToolkit.saved_error != null &&
-                XToolkit.saved_error.get_error_code() != XConstants.Success) {
+            if ((XErrorHandlerUtil.saved_error != null) &&
+                (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {
                 throw new XException("Cannot write Motif receiver info property");
             }
         } finally {
@@ -236,16 +236,16 @@
 
                     unsafe.putInt(data + 4, tproxy);
 
-                    XToolkit.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
+                    XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
                     XlibWrapper.XChangeProperty(XToolkit.getDisplay(), embedder,
                                                 MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO.getAtom(),
                                                 MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO.getAtom(),
                                                 8, XConstants.PropModeReplace,
                                                 data, dataSize);
-                    XToolkit.RESTORE_XERROR_HANDLER();
+                    XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
 
-                    if (XToolkit.saved_error != null &&
-                        XToolkit.saved_error.get_error_code() != XConstants.Success) {
+                    if ((XErrorHandlerUtil.saved_error != null) &&
+                        (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {
                         throw new XException("Cannot write Motif receiver info property");
                     }
                 }
@@ -412,15 +412,15 @@
          */
         XWindowAttributes wattr = new XWindowAttributes();
         try {
-            XToolkit.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
+            XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
             int status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
                                                           source_win, wattr.pData);
 
-            XToolkit.RESTORE_XERROR_HANDLER();
+            XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
 
-            if (status == 0 ||
-                (XToolkit.saved_error != null &&
-                 XToolkit.saved_error.get_error_code() != XConstants.Success)) {
+            if ((status == 0) ||
+                ((XErrorHandlerUtil.saved_error != null) &&
+                (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success))) {
                 throw new XException("XGetWindowAttributes failed");
             }
 
@@ -429,15 +429,15 @@
             wattr.dispose();
         }
 
-        XToolkit.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
+        XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
         XlibWrapper.XSelectInput(XToolkit.getDisplay(), source_win,
                                  source_win_mask |
                                  XConstants.StructureNotifyMask);
 
-        XToolkit.RESTORE_XERROR_HANDLER();
+        XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
 
-        if (XToolkit.saved_error != null &&
-            XToolkit.saved_error.get_error_code() != XConstants.Success) {
+        if ((XErrorHandlerUtil.saved_error != null) &&
+            (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {
             throw new XException("XSelectInput failed");
         }
 
@@ -1024,10 +1024,10 @@
         if (sourceWindow != 0) {
             XToolkit.awtLock();
             try {
-                XToolkit.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
+                XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
                 XlibWrapper.XSelectInput(XToolkit.getDisplay(), sourceWindow,
                                          sourceWindowMask);
-                XToolkit.RESTORE_XERROR_HANDLER();
+                XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
             } finally {
                 XToolkit.awtUnlock();
             }
--- a/jdk/src/solaris/classes/sun/awt/X11/WindowPropertyGetter.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/solaris/classes/sun/awt/X11/WindowPropertyGetter.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -99,7 +99,7 @@
             }
 
             if (errorHandler != null) {
-                XToolkit.WITH_XERROR_HANDLER(errorHandler);
+                XErrorHandlerUtil.WITH_XERROR_HANDLER(errorHandler);
             }
             Native.putLong(data, 0);
             int status = XlibWrapper.XGetWindowProperty(XToolkit.getDisplay(), window, property.getAtom(),
@@ -112,7 +112,7 @@
             }
 
             if (errorHandler != null) {
-                XToolkit.RESTORE_XERROR_HANDLER();
+                XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
             }
             return status;
         } finally {
--- a/jdk/src/solaris/classes/sun/awt/X11/XConstants.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/solaris/classes/sun/awt/X11/XConstants.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -674,4 +674,9 @@
     public static final long XkbModifierMapMask = (1L<<2);
     public static final long XkbVirtualModsMask = (1L<<6); //server map
 
+    /*****************************************************************
+     * X SHARED MEMORY EXTENSION FUNCTIONS
+     *****************************************************************/
+
+    public static final int X_ShmAttach = 1;
 }
--- a/jdk/src/solaris/classes/sun/awt/X11/XDnDDragSourceProtocol.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/solaris/classes/sun/awt/X11/XDnDDragSourceProtocol.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -96,14 +96,14 @@
                 action_count++;
             }
 
-            XToolkit.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
+            XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
             XDnDConstants.XA_XdndActionList.setAtomData(window,
                                                         XAtom.XA_ATOM,
                                                         data, action_count);
-            XToolkit.RESTORE_XERROR_HANDLER();
+            XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
 
-            if (XToolkit.saved_error != null &&
-                XToolkit.saved_error.get_error_code() != XConstants.Success) {
+            if ((XErrorHandlerUtil.saved_error) != null &&
+                (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {
                 cleanup();
                 throw new XException("Cannot write XdndActionList property");
             }
@@ -117,14 +117,14 @@
         try {
             Native.put(data, formats);
 
-            XToolkit.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
+            XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
             XDnDConstants.XA_XdndTypeList.setAtomData(window,
                                                       XAtom.XA_ATOM,
                                                       data, formats.length);
-            XToolkit.RESTORE_XERROR_HANDLER();
+            XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
 
-            if (XToolkit.saved_error != null &&
-                XToolkit.saved_error.get_error_code() != XConstants.Success) {
+            if ((XErrorHandlerUtil.saved_error != null) &&
+                (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {
                 cleanup();
                 throw new XException("Cannot write XdndActionList property");
             }
--- a/jdk/src/solaris/classes/sun/awt/X11/XDnDDropTargetProtocol.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/solaris/classes/sun/awt/X11/XDnDDropTargetProtocol.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -88,12 +88,12 @@
         try {
             Native.putLong(data, 0, XDnDConstants.XDND_PROTOCOL_VERSION);
 
-            XToolkit.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
+            XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
             XDnDConstants.XA_XdndAware.setAtomData(window, XAtom.XA_ATOM, data, 1);
-            XToolkit.RESTORE_XERROR_HANDLER();
+            XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
 
-            if (XToolkit.saved_error != null &&
-                XToolkit.saved_error.get_error_code() != XConstants.Success) {
+            if ((XErrorHandlerUtil.saved_error != null) &&
+                (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {
                 throw new XException("Cannot write XdndAware property");
             }
         } finally {
@@ -205,54 +205,50 @@
 
             /* The proxy window must have the XdndAware set, as XDnD protocol
                prescribes to check the proxy window for XdndAware. */
-            XToolkit.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
+            XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
             XDnDConstants.XA_XdndAware.setAtomData(newProxy, XAtom.XA_ATOM,
                                                    data, 1);
-            XToolkit.RESTORE_XERROR_HANDLER();
+            XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
 
-            if (XToolkit.saved_error != null &&
-                XToolkit.saved_error.get_error_code() !=
-                XConstants.Success) {
+            if ((XErrorHandlerUtil.saved_error != null) &&
+                (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {
                 throw new XException("Cannot write XdndAware property");
             }
 
             Native.putLong(data, 0, newProxy);
 
             /* The proxy window must have the XdndProxy set to point to itself.*/
-            XToolkit.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
+            XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
             XDnDConstants.XA_XdndProxy.setAtomData(newProxy, XAtom.XA_WINDOW,
                                                    data, 1);
-            XToolkit.RESTORE_XERROR_HANDLER();
+            XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
 
-            if (XToolkit.saved_error != null &&
-                XToolkit.saved_error.get_error_code() !=
-                XConstants.Success) {
+            if ((XErrorHandlerUtil.saved_error != null) &&
+                (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {
                 throw new XException("Cannot write XdndProxy property");
             }
 
             Native.putLong(data, 0, XDnDConstants.XDND_PROTOCOL_VERSION);
 
-            XToolkit.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
+            XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
             XDnDConstants.XA_XdndAware.setAtomData(embedder, XAtom.XA_ATOM,
                                                    data, 1);
-            XToolkit.RESTORE_XERROR_HANDLER();
+            XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
 
-            if (XToolkit.saved_error != null &&
-                XToolkit.saved_error.get_error_code() !=
-                XConstants.Success) {
+            if ((XErrorHandlerUtil.saved_error != null) &&
+                (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {
                 throw new XException("Cannot write XdndAware property");
             }
 
             Native.putLong(data, 0, newProxy);
 
-            XToolkit.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
+            XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
             XDnDConstants.XA_XdndProxy.setAtomData(embedder, XAtom.XA_WINDOW,
                                                    data, 1);
-            XToolkit.RESTORE_XERROR_HANDLER();
+            XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
 
-            if (XToolkit.saved_error != null &&
-                XToolkit.saved_error.get_error_code() !=
-                XConstants.Success) {
+            if ((XErrorHandlerUtil.saved_error != null) &&
+                (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {
                 throw new XException("Cannot write XdndProxy property");
             }
         } finally {
@@ -278,27 +274,25 @@
             try {
                 Native.putLong(data, 0, entry.getVersion());
 
-                XToolkit.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
+                XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
                 XDnDConstants.XA_XdndAware.setAtomData(embedder, XAtom.XA_ATOM,
                                                        data, 1);
-                XToolkit.RESTORE_XERROR_HANDLER();
+                XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
 
-                if (XToolkit.saved_error != null &&
-                    XToolkit.saved_error.get_error_code() !=
-                    XConstants.Success) {
+                if ((XErrorHandlerUtil.saved_error != null) &&
+                    (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {
                     throw new XException("Cannot write XdndAware property");
                 }
 
                 Native.putLong(data, 0, (int)entry.getProxy());
 
-                XToolkit.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
+                XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
                 XDnDConstants.XA_XdndProxy.setAtomData(embedder, XAtom.XA_WINDOW,
                                                        data, 1);
-                XToolkit.RESTORE_XERROR_HANDLER();
+                XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
 
-                if (XToolkit.saved_error != null &&
-                    XToolkit.saved_error.get_error_code() !=
-                    XConstants.Success) {
+                if ((XErrorHandlerUtil.saved_error != null) &&
+                    (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {
                     throw new XException("Cannot write XdndProxy property");
                 }
             } finally {
@@ -541,15 +535,15 @@
          */
         XWindowAttributes wattr = new XWindowAttributes();
         try {
-            XToolkit.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
+            XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
             int status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
                                                           source_win, wattr.pData);
 
-            XToolkit.RESTORE_XERROR_HANDLER();
+            XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
 
-            if (status == 0 ||
-                (XToolkit.saved_error != null &&
-                 XToolkit.saved_error.get_error_code() != XConstants.Success)) {
+            if ((status == 0) ||
+                ((XErrorHandlerUtil.saved_error != null) &&
+                (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success))) {
                 throw new XException("XGetWindowAttributes failed");
             }
 
@@ -558,15 +552,15 @@
             wattr.dispose();
         }
 
-        XToolkit.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
+        XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
         XlibWrapper.XSelectInput(XToolkit.getDisplay(), source_win,
                                  source_win_mask |
                                  XConstants.StructureNotifyMask);
 
-        XToolkit.RESTORE_XERROR_HANDLER();
+        XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
 
-        if (XToolkit.saved_error != null &&
-            XToolkit.saved_error.get_error_code() != XConstants.Success) {
+        if ((XErrorHandlerUtil.saved_error != null) &&
+            (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {
             throw new XException("XSelectInput failed");
         }
 
@@ -963,10 +957,10 @@
         if (sourceWindow != 0) {
             XToolkit.awtLock();
             try {
-                XToolkit.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
+                XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
                 XlibWrapper.XSelectInput(XToolkit.getDisplay(), sourceWindow,
                                          sourceWindowMask);
-                XToolkit.RESTORE_XERROR_HANDLER();
+                XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
             } finally {
                 XToolkit.awtUnlock();
             }
@@ -1111,15 +1105,15 @@
 
                             XToolkit.awtLock();
                             try {
-                                XToolkit.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
+                                XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
                                 XDnDConstants.XA_XdndTypeList.setAtomData(xclient.get_window(),
                                                                           XAtom.XA_ATOM,
                                                                           wpg.getData(),
                                                                           wpg.getNumberOfItems());
-                                XToolkit.RESTORE_XERROR_HANDLER();
+                                XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
 
-                                if (XToolkit.saved_error != null &&
-                                    XToolkit.saved_error.get_error_code() != XConstants.Success) {
+                                if ((XErrorHandlerUtil.saved_error != null) &&
+                                    (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {
                                     if (logger.isLoggable(PlatformLogger.WARNING)) {
                                         logger.warning("Cannot set XdndTypeList on the proxy window");
                                     }
--- a/jdk/src/solaris/classes/sun/awt/X11/XDragSourceProtocol.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/solaris/classes/sun/awt/X11/XDragSourceProtocol.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -181,15 +181,15 @@
                                    long time) {
         XWindowAttributes wattr = new XWindowAttributes();
         try {
-            XToolkit.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
+            XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
             int status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
                                                           targetWindow, wattr.pData);
 
-            XToolkit.RESTORE_XERROR_HANDLER();
+            XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
 
-            if (status == 0 ||
-                (XToolkit.saved_error != null &&
-                 XToolkit.saved_error.get_error_code() != XConstants.Success)) {
+            if ((status == 0) ||
+                ((XErrorHandlerUtil.saved_error != null) &&
+                (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success))) {
                 throw new XException("XGetWindowAttributes failed");
             }
 
@@ -198,15 +198,15 @@
             wattr.dispose();
         }
 
-        XToolkit.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
+        XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
         XlibWrapper.XSelectInput(XToolkit.getDisplay(), targetWindow,
                                  targetWindowMask |
                                  XConstants.StructureNotifyMask);
 
-        XToolkit.RESTORE_XERROR_HANDLER();
+        XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
 
-        if (XToolkit.saved_error != null &&
-            XToolkit.saved_error.get_error_code() != XConstants.Success) {
+        if ((XErrorHandlerUtil.saved_error != null) &&
+            (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {
             throw new XException("XSelectInput failed");
         }
 
@@ -214,10 +214,10 @@
     }
 
     protected final void finalizeDrop() {
-        XToolkit.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
+        XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
         XlibWrapper.XSelectInput(XToolkit.getDisplay(), targetWindow,
                                  targetWindowMask);
-        XToolkit.RESTORE_XERROR_HANDLER();
+        XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
     }
 
     public abstract boolean processProxyModeEvent(XClientMessageEvent xclient,
--- a/jdk/src/solaris/classes/sun/awt/X11/XDropTargetRegistry.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/solaris/classes/sun/awt/X11/XDropTargetRegistry.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -168,14 +168,14 @@
                 if (dest_x >= 0 && dest_y >= 0) {
                     XWindowAttributes wattr = new XWindowAttributes();
                     try {
-                        XToolkit.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
+                        XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
                         int status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
                                                                       window, wattr.pData);
-                        XToolkit.RESTORE_XERROR_HANDLER();
+                        XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
 
-                        if (status == 0 ||
-                            (XToolkit.saved_error != null &&
-                             XToolkit.saved_error.get_error_code() != XConstants.Success)) {
+                        if ((status == 0) ||
+                            ((XErrorHandlerUtil.saved_error != null) &&
+                            (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success))) {
                             continue;
                         }
 
@@ -222,14 +222,14 @@
             long event_mask = 0;
             XWindowAttributes wattr = new XWindowAttributes();
             try {
-                XToolkit.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
+                XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
                 int status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
                                                               embedder, wattr.pData);
-                XToolkit.RESTORE_XERROR_HANDLER();
+                XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
 
-                if (status == 0 ||
-                    (XToolkit.saved_error != null &&
-                     XToolkit.saved_error.get_error_code() != XConstants.Success)) {
+                if ((status == 0) ||
+                    ((XErrorHandlerUtil.saved_error != null) &&
+                    (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success))) {
                     throw new XException("XGetWindowAttributes failed");
                 }
 
@@ -240,13 +240,13 @@
             }
 
             if ((event_mask & XConstants.PropertyChangeMask) == 0) {
-                XToolkit.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
+                XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
                 XlibWrapper.XSelectInput(XToolkit.getDisplay(), embedder,
                                          event_mask | XConstants.PropertyChangeMask);
-                XToolkit.RESTORE_XERROR_HANDLER();
+                XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
 
-                if (XToolkit.saved_error != null &&
-                    XToolkit.saved_error.get_error_code() != XConstants.Success) {
+                if ((XErrorHandlerUtil.saved_error != null) &&
+                    (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {
                     throw new XException("XSelectInput failed");
                 }
             }
@@ -394,13 +394,13 @@
 
             /* Restore the original event mask for the embedder. */
             if ((event_mask & XConstants.PropertyChangeMask) == 0) {
-                XToolkit.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
+                XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
                 XlibWrapper.XSelectInput(XToolkit.getDisplay(), embedder,
                                          event_mask);
-                XToolkit.RESTORE_XERROR_HANDLER();
+                XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
 
-                if (XToolkit.saved_error != null &&
-                    XToolkit.saved_error.get_error_code() != XConstants.Success) {
+                if ((XErrorHandlerUtil.saved_error != null) &&
+                    (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {
                     throw new XException("XSelectInput failed");
                 }
             }
--- a/jdk/src/solaris/classes/sun/awt/X11/XEmbedCanvasPeer.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/solaris/classes/sun/awt/X11/XEmbedCanvasPeer.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -301,15 +301,15 @@
         try {
             XWindowAttributes wattr = new XWindowAttributes();
             try {
-                XToolkit.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
+                XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
                 int status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
                                                               xembed.handle, wattr.pData);
 
-                XToolkit.RESTORE_XERROR_HANDLER();
+                XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
 
-                if (status == 0 ||
-                    (XToolkit.saved_error != null &&
-                     XToolkit.saved_error.get_error_code() != XConstants.Success)) {
+                if ((status == 0) ||
+                    ((XErrorHandlerUtil.saved_error != null) &&
+                    (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success))) {
                     return null;
                 }
 
--- a/jdk/src/solaris/classes/sun/awt/X11/XErrorHandler.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/solaris/classes/sun/awt/X11/XErrorHandler.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -38,7 +38,30 @@
     public static class XBaseErrorHandler extends XErrorHandler {
         @Override
         public int handleError(long display, XErrorEvent err) {
-            return XToolkit.SAVED_ERROR_HANDLER(display, err);
+            return XErrorHandlerUtil.SAVED_XERROR_HANDLER(display, err);
+        }
+    }
+
+    /**
+     * This is a base synthetic error handler containing a boolean flag which allows
+     * to show that an error is handled or not.
+     */
+    public static class XErrorHandlerWithFlag extends XBaseErrorHandler {
+        private volatile boolean errorOccurred = false;
+
+        public boolean getErrorOccurredFlag() {
+            return errorOccurred;
+        }
+
+        /**
+         * Sets an internal boolean flag to a particular value. Should be always called with
+         * <code>false</code> value of the parameter <code>errorOccurred</code> before this
+         * error handler is set as current.
+         * @param errorOccurred <code>true</code> to indicate that an error was handled,
+         *     <code>false</code> to reset the internal boolean flag
+         */
+        public void setErrorOccurredFlag(boolean errorOccurred) {
+            this.errorOccurred = errorOccurred;
         }
     }
 
@@ -76,4 +99,51 @@
             return theInstance;
         }
     }
+
+    /**
+     * This is a synthetic error handler for errors generated by the native function
+     * <code>XShmAttach</code>. If an error is handled, an internal boolean flag of the
+     * handler is set to <code>true</code>.
+     */
+    public static final class XShmAttachHandler extends XErrorHandlerWithFlag {
+        private XShmAttachHandler() {}
+
+        @Override
+        public int handleError(long display, XErrorEvent err) {
+            if (err.get_minor_code() == XConstants.X_ShmAttach) {
+                setErrorOccurredFlag(true);
+                return 0;
+            }
+            return super.handleError(display, err);
+        }
+
+        // Shared instance
+        private static XShmAttachHandler theInstance = new XShmAttachHandler();
+        public static XShmAttachHandler getInstance() {
+            return theInstance;
+        }
+    }
+
+    /**
+     * This is a synthetic error handler for <code>BadAlloc</code> errors generated by the
+     * native <code>glX*</code> functions. Its internal boolean flag is set to <code>true</code>,
+     * if an error is handled.
+     */
+    public static final class GLXBadAllocHandler extends XErrorHandlerWithFlag {
+        private GLXBadAllocHandler() {}
+
+        @Override
+        public int handleError(long display, XErrorEvent err) {
+            if (err.get_error_code() == XConstants.BadAlloc) {
+                setErrorOccurredFlag(true);
+                return 0;
+            }
+            return super.handleError(display, err);
+        }
+
+        private static GLXBadAllocHandler theInstance = new GLXBadAllocHandler();
+        public static GLXBadAllocHandler getInstance() {
+            return theInstance;
+        }
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/awt/X11/XErrorHandlerUtil.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,162 @@
+/*
+ * 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.awt.X11;
+
+import java.security.AccessController;
+import sun.awt.SunToolkit;
+import sun.security.action.GetBooleanAction;
+import sun.util.logging.PlatformLogger;
+
+/**
+ * This class contains code of the global toolkit error handler, exposes static
+ * methods which allow to set and unset synthetic error handlers.
+ */
+public final class XErrorHandlerUtil {
+    private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XErrorHandlerUtil");
+
+    /**
+     * The connection to X11 window server.
+     */
+    private static long display;
+
+    /**
+     * Error handler at the moment of <code>XErrorHandlerUtil</code> initialization.
+     */
+    private static long saved_error_handler;
+
+    /**
+     * XErrorEvent being handled.
+     */
+    static volatile XErrorEvent saved_error;
+
+    /**
+     * Current error handler or null if no error handler is set.
+     */
+    private static XErrorHandler current_error_handler;
+
+    /**
+     * Value of sun.awt.noisyerrorhandler system property.
+     */
+    private static boolean noisyAwtHandler = AccessController.doPrivileged(
+        new GetBooleanAction("sun.awt.noisyerrorhandler"));
+
+    /**
+     * The flag indicating that <code>init</code> was called already.
+     */
+    private static boolean initPassed;
+
+    /**
+     * Guarantees that no instance of this class can be created.
+     */
+    private XErrorHandlerUtil() {}
+
+    /**
+     * Sets the toolkit global error handler, stores the connection to X11 server, which
+     * will be used during an error handling process. This method is called once from
+     * <code>awt_init_Display</code> function defined in <code>awt_GraphicsEnv.c</code>
+     * file immediately after the connection to X11 window server is opened.
+     * @param display the connection to X11 server which should be stored
+     */
+    private static void init(long display) {
+        SunToolkit.awtLock();
+        try {
+            if (!initPassed) {
+                XErrorHandlerUtil.display = display;
+                saved_error_handler = XlibWrapper.SetToolkitErrorHandler();
+                initPassed = true;
+            }
+        } finally {
+            SunToolkit.awtUnlock();
+        }
+    }
+
+    /**
+     * Sets a synthetic error handler. Must be called with the acquired AWT lock.
+     * @param handler the synthetic error handler to set
+     */
+    public static void WITH_XERROR_HANDLER(XErrorHandler handler) {
+        saved_error = null;
+        current_error_handler = handler;
+    }
+
+    /**
+     * Unsets a current synthetic error handler. Must be called with the acquired AWT lock.
+     */
+    public static void RESTORE_XERROR_HANDLER() {
+        // Wait until all requests are processed by the X server
+        // and only then uninstall the error handler.
+        XSync();
+        current_error_handler = null;
+    }
+
+    /**
+     * Should be called under LOCK.
+     */
+    public static int SAVED_XERROR_HANDLER(long display, XErrorEvent error) {
+        if (saved_error_handler != 0) {
+            // Default XErrorHandler may just terminate the process. Don't call it.
+            // return XlibWrapper.CallErrorHandler(saved_error_handler, display, error.pData);
+        }
+        if (log.isLoggable(PlatformLogger.FINE)) {
+            log.fine("Unhandled XErrorEvent: " +
+                "id=" + error.get_resourceid() + ", " +
+                "serial=" + error.get_serial() + ", " +
+                "ec=" + error.get_error_code() + ", " +
+                "rc=" + error.get_request_code() + ", " +
+                "mc=" + error.get_minor_code());
+        }
+        return 0;
+    }
+
+    /**
+     * Called from the native code when an error occurs.
+     */
+    private static int globalErrorHandler(long display, long event_ptr) {
+        if (noisyAwtHandler) {
+            XlibWrapper.PrintXErrorEvent(display, event_ptr);
+        }
+        XErrorEvent event = new XErrorEvent(event_ptr);
+        saved_error = event;
+        try {
+            if (current_error_handler != null) {
+                return current_error_handler.handleError(display, event);
+            } else {
+                return SAVED_XERROR_HANDLER(display, event);
+            }
+        } catch (Throwable z) {
+            log.fine("Error in GlobalErrorHandler", z);
+        }
+        return 0;
+    }
+
+    private static void XSync() {
+        SunToolkit.awtLock();
+        try {
+            XlibWrapper.XSync(display, 0);
+        } finally {
+            SunToolkit.awtUnlock();
+        }
+    }
+}
--- a/jdk/src/solaris/classes/sun/awt/X11/XQueryTree.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/solaris/classes/sun/awt/X11/XQueryTree.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -61,7 +61,7 @@
                         }
                         __executed = true;
                         if (errorHandler != null) {
-                            XToolkit.WITH_XERROR_HANDLER(errorHandler);
+                            XErrorHandlerUtil.WITH_XERROR_HANDLER(errorHandler);
                         }
                         Native.putLong(children_ptr, 0);
                         int status =
@@ -72,7 +72,7 @@
                                 children_ptr,
                                 nchildren_ptr                   );
                         if (errorHandler != null) {
-                            XToolkit.RESTORE_XERROR_HANDLER();
+                            XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
                         }
                         return status;
                 } finally {
--- a/jdk/src/solaris/classes/sun/awt/X11/XToolkit.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/solaris/classes/sun/awt/X11/XToolkit.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 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
@@ -128,7 +128,6 @@
             initIDs();
             setBackingStoreType();
         }
-        noisyAwtHandler = AccessController.doPrivileged(new GetBooleanAction("sun.awt.noisyerrorhandler"));
     }
 
     /*
@@ -137,78 +136,6 @@
      */
     static native long getTrayIconDisplayTimeout();
 
-    //---- ERROR HANDLER CODE ----//
-
-    /*
-     * Error handler at the moment of XToolkit initialization
-     */
-    private static long saved_error_handler;
-
-    /*
-     * XErrorEvent being handled
-     */
-    static volatile XErrorEvent saved_error;
-
-    /*
-     * Current error handler or null if no error handler is set
-     */
-    private static XErrorHandler current_error_handler;
-
-    /*
-     * Value of sun.awt.noisyerrorhandler system property
-     */
-    private static boolean noisyAwtHandler;
-
-    public static void WITH_XERROR_HANDLER(XErrorHandler handler) {
-        saved_error = null;
-        current_error_handler = handler;
-    }
-
-    public static void RESTORE_XERROR_HANDLER() {
-        // wait until all requests are processed by the X server
-        // and only then uninstall the error handler
-        XSync();
-        current_error_handler = null;
-    }
-
-    // Should be called under LOCK
-    public static int SAVED_ERROR_HANDLER(long display, XErrorEvent error) {
-        if (saved_error_handler != 0) {
-            // Default XErrorHandler may just terminate the process. Don't call it.
-            // return XlibWrapper.CallErrorHandler(saved_error_handler, display, error.pData);
-        }
-        if (log.isLoggable(PlatformLogger.FINE)) {
-            log.fine("Unhandled XErrorEvent: " +
-                     "id=" + error.get_resourceid() + ", " +
-                     "serial=" + error.get_serial() + ", " +
-                     "ec=" + error.get_error_code() + ", " +
-                     "rc=" + error.get_request_code() + ", " +
-                     "mc=" + error.get_minor_code());
-        }
-        return 0;
-    }
-
-    // Called from the native code when an error occurs
-    private static int globalErrorHandler(long display, long event_ptr) {
-        if (noisyAwtHandler) {
-            XlibWrapper.PrintXErrorEvent(display, event_ptr);
-        }
-        XErrorEvent event = new XErrorEvent(event_ptr);
-        saved_error = event;
-        try {
-            if (current_error_handler != null) {
-                return current_error_handler.handleError(display, event);
-            } else {
-                return SAVED_ERROR_HANDLER(display, event);
-            }
-        } catch (Throwable z) {
-            log.fine("Error in GlobalErrorHandler", z);
-        }
-        return 0;
-    }
-
-    //---- END OF ERROR HANDLER CODE ----//
-
     private native static void initIDs();
     native static void waitForEvents(long nextTaskTime);
     static Thread toolkitThread;
@@ -306,8 +233,6 @@
             //set system property if not yet assigned
             System.setProperty("sun.awt.enableExtraMouseButtons", ""+areExtraMouseButtonsEnabled);
 
-            saved_error_handler = XlibWrapper.SetToolkitErrorHandler();
-
             // Detect display mode changes
             XlibWrapper.XSelectInput(XToolkit.getDisplay(), XToolkit.getDefaultRootWindow(), XConstants.StructureNotifyMask);
             XToolkit.addEventDispatcher(XToolkit.getDefaultRootWindow(), new XEventDispatcher() {
--- a/jdk/src/solaris/classes/sun/awt/X11/XTranslateCoordinates.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/solaris/classes/sun/awt/X11/XTranslateCoordinates.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -68,7 +68,7 @@
                         }
                         __executed = true;
                         if (errorHandler != null) {
-                            XToolkit.WITH_XERROR_HANDLER(errorHandler);
+                            XErrorHandlerUtil.WITH_XERROR_HANDLER(errorHandler);
                         }
                         int status =
                         XlibWrapper.XTranslateCoordinates(XToolkit.getDisplay(),
@@ -80,7 +80,7 @@
                                 dest_y_ptr,
                                 child_ptr                       );
                         if (errorHandler != null) {
-                            XToolkit.RESTORE_XERROR_HANDLER();
+                            XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
                         }
                         return status;
                 } finally {
--- a/jdk/src/solaris/classes/sun/awt/X11/XWM.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/solaris/classes/sun/awt/X11/XWM.java	Mon Jun 10 10:38:33 2013 +0100
@@ -285,12 +285,12 @@
             winmgr_running = false;
             substruct.set_event_mask(XConstants.SubstructureRedirectMask);
 
-            XToolkit.WITH_XERROR_HANDLER(detectWMHandler);
+            XErrorHandlerUtil.WITH_XERROR_HANDLER(detectWMHandler);
             XlibWrapper.XChangeWindowAttributes(XToolkit.getDisplay(),
                                                 XToolkit.getDefaultRootWindow(),
                                                 XConstants.CWEventMask,
                                                 substruct.pData);
-            XToolkit.RESTORE_XERROR_HANDLER();
+            XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
 
             /*
              * If no WM is running then our selection for SubstructureRedirect
@@ -633,15 +633,16 @@
 
         XToolkit.awtLock();
         try {
-            XToolkit.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
+            XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
             XlibWrapper.XChangePropertyS(XToolkit.getDisplay(), XToolkit.getDefaultRootWindow(),
                                          XA_ICEWM_WINOPTHINT.getAtom(),
                                          XA_ICEWM_WINOPTHINT.getAtom(),
                                          8, XConstants.PropModeReplace,
                                          new String(opt));
-            XToolkit.RESTORE_XERROR_HANDLER();
+            XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
 
-            if (XToolkit.saved_error != null && XToolkit.saved_error.get_error_code() != XConstants.Success) {
+            if ((XErrorHandlerUtil.saved_error != null) &&
+                (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {
                 log.finer("Erorr getting XA_ICEWM_WINOPTHINT property");
                 return false;
             }
--- a/jdk/src/solaris/classes/sun/awt/X11/XlibUtil.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/solaris/classes/sun/awt/X11/XlibUtil.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -151,8 +151,8 @@
             {
                 int status = xtc.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());
                 if ((status != 0) &&
-                    ((XToolkit.saved_error == null) ||
-                     (XToolkit.saved_error.get_error_code() == XConstants.Success)))
+                    ((XErrorHandlerUtil.saved_error == null) ||
+                    (XErrorHandlerUtil.saved_error.get_error_code() == XConstants.Success)))
                 {
                     translated = new Point(xtc.get_dest_x(), xtc.get_dest_y());
                 }
@@ -345,13 +345,13 @@
         XWindowAttributes wattr = new XWindowAttributes();
         try
         {
-            XToolkit.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
+            XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
             int status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
                                                           window, wattr.pData);
-            XToolkit.RESTORE_XERROR_HANDLER();
+            XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
             if ((status != 0) &&
-                ((XToolkit.saved_error == null) ||
-                 (XToolkit.saved_error.get_error_code() == XConstants.Success)))
+                ((XErrorHandlerUtil.saved_error == null) ||
+                (XErrorHandlerUtil.saved_error.get_error_code() == XConstants.Success)))
             {
                 return wattr.get_map_state();
             }
--- a/jdk/src/solaris/classes/sun/awt/X11/generator/WrapperGenerator.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/solaris/classes/sun/awt/X11/generator/WrapperGenerator.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -996,7 +996,7 @@
             pw.println("\t\t\t}");
             pw.println("\t\t\t__executed = true;");
             pw.println("\t\t\tif (errorHandler != null) {");
-            pw.println("\t\t\t    XToolkit.WITH_XERROR_HANDLER(errorHandler);");
+            pw.println("\t\t\t    XErrorHandlerUtil.WITH_XERROR_HANDLER(errorHandler);");
             pw.println("\t\t\t}");
             iter = ft.getArguments().iterator();
             while (iter.hasNext()) {
@@ -1025,7 +1025,7 @@
             }
             pw.println("\t\t\t);");
             pw.println("\t\t\tif (errorHandler != null) {");
-            pw.println("\t\t\t    XToolkit.RESTORE_XERROR_HANDLER();");
+            pw.println("\t\t\t    XErrorHandlerUtil.RESTORE_XERROR_HANDLER();");
             pw.println("\t\t\t}");
             if (!ft.isVoid()) {
                 pw.println("\t\t\treturn status;");
--- a/jdk/src/solaris/classes/sun/print/IPPPrintService.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/solaris/classes/sun/print/IPPPrintService.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1023,6 +1023,13 @@
 
             // this is already supported in UnixPrintJob
             catList.add(Destination.class);
+
+            // It is unfortunate that CUPS doesn't provide a way to query
+            // if printer supports collation but since most printers
+            // now supports collation and that most OS has a way
+            // of setting it, it is a safe assumption to just always
+            // include SheetCollate as supported attribute.
+            catList.add(SheetCollate.class);
         }
 
         // With the assumption that  Chromaticity is equivalent to
--- a/jdk/src/solaris/native/java/net/NetworkInterface.c	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/solaris/native/java/net/NetworkInterface.c	Mon Jun 10 10:38:33 2013 +0100
@@ -658,9 +658,9 @@
                     if (ia2Obj) {
                        setInetAddress_addr(env, ia2Obj, htonl(((struct sockaddr_in*)addrP->brdcast)->sin_addr.s_addr));
                        (*env)->SetObjectField(env, ibObj, ni_ib4broadcastID, ia2Obj);
-                       (*env)->SetShortField(env, ibObj, ni_ib4maskID, addrP->mask);
                     }
                  }
+                 (*env)->SetShortField(env, ibObj, ni_ib4maskID, addrP->mask);
                  (*env)->SetObjectArrayElement(env, bindArr, bind_index++, ibObj);
             }
         }
@@ -887,15 +887,12 @@
     addrP->mask = prefix;
     addrP->next = 0;
     if (family == AF_INET) {
-      /*
-       * Deal with broadcast addr & subnet mask
-       */
+       // Deal with broadcast addr & subnet mask
        struct sockaddr * brdcast_to = (struct sockaddr *) ((char *) addrP + sizeof(netaddr) + addr_size);
        addrP->brdcast = getBroadcast(env, sock, name,  brdcast_to );
 
-       if (addrP->brdcast && (mask = getSubnet(env, sock, name)) != -1) {
+       if ((mask = getSubnet(env, sock, name)) != -1)
            addrP->mask = mask;
-       }
      }
 
     /**
--- a/jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.c	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.c	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -758,6 +758,8 @@
     }
 
     XSetIOErrorHandler(xioerror_handler);
+    JNU_CallStaticMethodByName(env, NULL, "sun/awt/X11/XErrorHandlerUtil", "init", "(J)V",
+        ptr_to_jlong(awt_display));
 
     /* set awt_numScreens, and whether or not we're using Xinerama */
     xineramaInit();
@@ -904,30 +906,14 @@
 
 static jint canUseShmExt = UNSET_MITSHM;
 static jint canUseShmExtPixmaps = UNSET_MITSHM;
-static jboolean xshmAttachFailed = JNI_FALSE;
 
 extern int mitShmPermissionMask;
 
-int J2DXErrHandler(Display *display, XErrorEvent *xerr) {
-    int ret = 0;
-    if (xerr->minor_code == X_ShmAttach) {
-        xshmAttachFailed = JNI_TRUE;
-    } else {
-        ret = (*xerror_saved_handler)(display, xerr);
-    }
-    return ret;
-}
-jboolean isXShmAttachFailed() {
-    return xshmAttachFailed;
-}
-void resetXShmAttachFailed() {
-    xshmAttachFailed = JNI_FALSE;
-}
-
 void TryInitMITShm(JNIEnv *env, jint *shmExt, jint *shmPixmaps) {
     XShmSegmentInfo shminfo;
     int XShmMajor, XShmMinor;
     int a, b, c;
+    jboolean xShmAttachResult;
 
     AWT_LOCK();
     if (canUseShmExt != UNSET_MITSHM) {
@@ -966,21 +952,14 @@
         }
         shminfo.readOnly = True;
 
-        resetXShmAttachFailed();
-        /**
-         * The J2DXErrHandler handler will set xshmAttachFailed
-         * to JNI_TRUE if any Shm error has occured.
-         */
-        EXEC_WITH_XERROR_HANDLER(J2DXErrHandler,
-                                 XShmAttach(awt_display, &shminfo));
-
+        xShmAttachResult = TryXShmAttach(env, awt_display, &shminfo);
         /**
          * Get rid of the id now to reduce chances of leaking
          * system resources.
          */
         shmctl(shminfo.shmid, IPC_RMID, 0);
 
-        if (isXShmAttachFailed() == JNI_FALSE) {
+        if (xShmAttachResult == JNI_TRUE) {
             canUseShmExt = CAN_USE_MITSHM;
             /* check if we can use shared pixmaps */
             XShmQueryVersion(awt_display, &XShmMajor, &XShmMinor,
@@ -995,6 +974,23 @@
     }
     AWT_UNLOCK();
 }
+
+/*
+ * Must be called with the acquired AWT lock.
+ */
+jboolean TryXShmAttach(JNIEnv *env, Display *display, XShmSegmentInfo *shminfo) {
+    jboolean errorOccurredFlag = JNI_FALSE;
+    jobject errorHandlerRef;
+
+    /*
+     * XShmAttachHandler will set its internal flag to JNI_TRUE, if any Shm error occurs.
+     */
+    EXEC_WITH_XERROR_HANDLER(env, "sun/awt/X11/XErrorHandler$XShmAttachHandler",
+        "()Lsun/awt/X11/XErrorHandler$XShmAttachHandler;", JNI_TRUE,
+        errorHandlerRef, errorOccurredFlag,
+        XShmAttach(display, shminfo));
+    return errorOccurredFlag == JNI_FALSE ? JNI_TRUE : JNI_FALSE;
+}
 #endif /* MITSHM */
 
 /*
--- a/jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.h	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.h	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -53,8 +53,7 @@
 extern int XShmQueryExtension();
 
 void TryInitMITShm(JNIEnv *env, jint *shmExt, jint *shmPixmaps);
-void resetXShmAttachFailed();
-jboolean isXShmAttachFailed();
+jboolean TryXShmAttach(JNIEnv *env, Display *display, XShmSegmentInfo *shminfo);
 
 #endif /* MITSHM */
 
--- a/jdk/src/solaris/native/sun/awt/awt_InputMethod.c	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/solaris/native/sun/awt/awt_InputMethod.c	Mon Jun 10 10:38:33 2013 +0100
@@ -185,7 +185,6 @@
 );
 #endif
 
-#ifdef XAWT_HACK
 /*
  * This function is stolen from /src/solaris/hpi/src/system_md.c
  * It is used in setting the time in Java-level InputEvents
@@ -197,7 +196,6 @@
     gettimeofday(&t, NULL);
     return ((jlong)t.tv_sec) * 1000 + (jlong)(t.tv_usec/1000);
 }
-#endif /* XAWT_HACK */
 
 /*
  * Converts the wchar_t string to a multi-byte string calling wcstombs(). A
@@ -546,11 +544,7 @@
                                  "dispatchCommittedText",
                                  "(Ljava/lang/String;J)V",
                                  javastr,
-#ifndef XAWT_HACK
-                                 awt_util_nowMillisUTC_offset(event->time));
-#else
                                  event->time);
-#endif
         }
         break;
 
--- a/jdk/src/solaris/native/sun/awt/awt_util.c	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/solaris/native/sun/awt/awt_util.c	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -41,18 +41,6 @@
 
 #include "java_awt_event_MouseWheelEvent.h"
 
-/*
- * Since X reports protocol errors asynchronously, we often need to
- * install an error handler that acts like a callback.  While that
- * specialized handler is installed we save original handler here.
- */
-XErrorHandler xerror_saved_handler;
-
-/*
- * A place for error handler to report the error code.
- */
-unsigned char xerror_code;
-
 extern jint getModifiers(uint32_t state, jint button, jint keyCode);
 extern jint getButton(uint32_t button);
 
--- a/jdk/src/solaris/native/sun/awt/awt_util.h	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/solaris/native/sun/awt/awt_util.h	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,42 +29,47 @@
 #ifndef HEADLESS
 #include "gdefs.h"
 
-#define WITH_XERROR_HANDLER(f) do {             \
-    XSync(awt_display, False);                  \
-    xerror_code = Success;                      \
-    xerror_saved_handler = XSetErrorHandler(f); \
-} while (0)
-
-/* Convenience macro for handlers to use */
-#define XERROR_SAVE(err) do {                   \
-    xerror_code = (err)->error_code;            \
-} while (0)
-
-#define RESTORE_XERROR_HANDLER do {             \
-    XSync(awt_display, False);                  \
-    XSetErrorHandler(xerror_saved_handler);     \
-} while (0)
-
-#define EXEC_WITH_XERROR_HANDLER(f, code) do {  \
-    WITH_XERROR_HANDLER(f);                     \
-    do {                                        \
-        code;                                   \
-    } while (0);                                \
-    RESTORE_XERROR_HANDLER;                     \
+/*
+ * Expected types of arguments of the macro.
+ * (JNIEnv*, const char*, const char*, jboolean, jobject)
+ */
+#define WITH_XERROR_HANDLER(env, handlerClassName, getInstanceSignature,                          \
+                            handlerHasFlag, handlerRef) do {                                      \
+    handlerRef = JNU_CallStaticMethodByName(env, NULL, handlerClassName, "getInstance",           \
+        getInstanceSignature).l;                                                                  \
+    if (handlerHasFlag == JNI_TRUE) {                                                             \
+        JNU_CallMethodByName(env, NULL, handlerRef, "setErrorOccurredFlag", "(Z)V", JNI_FALSE);   \
+    }                                                                                             \
+    JNU_CallStaticMethodByName(env, NULL, "sun/awt/X11/XErrorHandlerUtil", "WITH_XERROR_HANDLER", \
+        "(Lsun/awt/X11/XErrorHandler;)V", handlerRef);                                            \
 } while (0)
 
 /*
- * Since X reports protocol errors asynchronously, we often need to
- * install an error handler that acts like a callback.  While that
- * specialized handler is installed we save original handler here.
+ * Expected types of arguments of the macro.
+ * (JNIEnv*)
  */
-extern XErrorHandler xerror_saved_handler;
+#define RESTORE_XERROR_HANDLER(env) do {                                                          \
+    JNU_CallStaticMethodByName(env, NULL, "sun/awt/X11/XErrorHandlerUtil",                        \
+        "RESTORE_XERROR_HANDLER", "()V");                                                         \
+} while (0)
 
 /*
- * A place for error handler to report the error code.
+ * Expected types of arguments of the macro.
+ * (JNIEnv*, const char*, const char*, jboolean, jobject, jboolean, No type - C expression)
  */
-extern unsigned char xerror_code;
-
+#define EXEC_WITH_XERROR_HANDLER(env, handlerClassName, getInstanceSignature, handlerHasFlag,     \
+                                 handlerRef, errorOccurredFlag, code) do {                        \
+    handlerRef = NULL;                                                                            \
+    WITH_XERROR_HANDLER(env, handlerClassName, getInstanceSignature, handlerHasFlag, handlerRef); \
+    do {                                                                                          \
+        code;                                                                                     \
+    } while (0);                                                                                  \
+    RESTORE_XERROR_HANDLER(env);                                                                  \
+    if (handlerHasFlag == JNI_TRUE) {                                                             \
+        errorOccurredFlag = JNU_CallMethodByName(env, NULL, handlerRef, "getErrorOccurredFlag",   \
+            "()Z").z;                                                                             \
+    }                                                                                             \
+} while (0)
 #endif /* !HEADLESS */
 
 #ifndef INTERSECTS
--- a/jdk/src/solaris/native/sun/java2d/opengl/GLXSurfaceData.c	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/solaris/native/sun/java2d/opengl/GLXSurfaceData.c	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -48,8 +48,6 @@
 extern void
     OGLSD_SetNativeDimensions(JNIEnv *env, OGLSDOps *oglsdo, jint w, jint h);
 
-jboolean surfaceCreationFailed = JNI_FALSE;
-
 #endif /* !HEADLESS */
 
 JNIEXPORT void JNICALL
@@ -349,18 +347,6 @@
     return JNI_TRUE;
 }
 
-static int
-GLXSD_BadAllocXErrHandler(Display *display, XErrorEvent *xerr)
-{
-    int ret = 0;
-    if (xerr->error_code == BadAlloc) {
-        surfaceCreationFailed = JNI_TRUE;
-    } else {
-        ret = (*xerror_saved_handler)(display, xerr);
-    }
-    return ret;
-}
-
 JNIEXPORT jboolean JNICALL
 Java_sun_java2d_opengl_GLXSurfaceData_initPbuffer
     (JNIEnv *env, jobject glxsd,
@@ -376,6 +362,8 @@
     int attrlist[] = {GLX_PBUFFER_WIDTH, 0,
                       GLX_PBUFFER_HEIGHT, 0,
                       GLX_PRESERVED_CONTENTS, GL_FALSE, 0};
+    jboolean errorOccurredFlag;
+    jobject errorHandlerRef;
 
     J2dTraceLn3(J2D_TRACE_INFO,
                 "GLXSurfaceData_initPbuffer: w=%d h=%d opq=%d",
@@ -403,12 +391,13 @@
     attrlist[1] = width;
     attrlist[3] = height;
 
-    surfaceCreationFailed = JNI_FALSE;
-    EXEC_WITH_XERROR_HANDLER(
-        GLXSD_BadAllocXErrHandler,
-        pbuffer = j2d_glXCreatePbuffer(awt_display,
-                                       glxinfo->fbconfig, attrlist));
-    if ((pbuffer == 0) || surfaceCreationFailed) {
+    errorOccurredFlag = JNI_FALSE;
+    EXEC_WITH_XERROR_HANDLER(env, "sun/awt/X11/XErrorHandler$GLXBadAllocHandler",
+        "()Lsun/awt/X11/XErrorHandler$GLXBadAllocHandler;", JNI_TRUE,
+        errorHandlerRef, errorOccurredFlag,
+        pbuffer = j2d_glXCreatePbuffer(awt_display, glxinfo->fbconfig, attrlist));
+
+    if ((pbuffer == 0) || errorOccurredFlag) {
         J2dRlsTraceLn(J2D_TRACE_ERROR,
             "GLXSurfaceData_initPbuffer: could not create glx pbuffer");
         return JNI_FALSE;
--- a/jdk/src/solaris/native/sun/java2d/x11/X11SurfaceData.c	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/solaris/native/sun/java2d/x11/X11SurfaceData.c	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -65,7 +65,6 @@
 static DisposeFunc X11SD_Dispose;
 static GetPixmapBgFunc X11SD_GetPixmapWithBg;
 static ReleasePixmapBgFunc X11SD_ReleasePixmapWithBg;
-extern int J2DXErrHandler(Display *display, XErrorEvent *xerr);
 extern AwtGraphicsConfigDataPtr
     getGraphicsConfigFromComponentPeer(JNIEnv *env, jobject this);
 extern struct X11GraphicsConfigIDs x11GraphicsConfigIDs;
@@ -529,6 +528,8 @@
 {
     XImage *img = NULL;
     XShmSegmentInfo *shminfo;
+    JNIEnv* env;
+    jboolean xShmAttachResult;
 
     shminfo = malloc(sizeof(XShmSegmentInfo));
     if (shminfo == NULL) {
@@ -568,9 +569,8 @@
 
     shminfo->readOnly = False;
 
-    resetXShmAttachFailed();
-    EXEC_WITH_XERROR_HANDLER(J2DXErrHandler,
-                             XShmAttach(awt_display, shminfo));
+    env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_2);
+    xShmAttachResult = TryXShmAttach(env, awt_display, shminfo);
 
     /*
      * Once the XSync round trip has finished then we
@@ -579,7 +579,7 @@
      */
     shmctl(shminfo->shmid, IPC_RMID, 0);
 
-    if (isXShmAttachFailed() == JNI_TRUE) {
+    if (xShmAttachResult == JNI_FALSE) {
         J2dRlsTraceLn1(J2D_TRACE_ERROR,
                        "X11SD_SetupSharedSegment XShmAttach has failed: %s",
                        strerror(errno));
--- a/jdk/src/solaris/native/sun/xawt/XlibWrapper.c	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/solaris/native/sun/xawt/XlibWrapper.c	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 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
@@ -1265,8 +1265,8 @@
     if (jvm != NULL) {
         env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
         if (env) {
-            return JNU_CallStaticMethodByName(env, NULL, "sun/awt/X11/XToolkit", "globalErrorHandler", "(JJ)I",
-                                              ptr_to_jlong(dpy), ptr_to_jlong(event)).i;
+            return JNU_CallStaticMethodByName(env, NULL, "sun/awt/X11/XErrorHandlerUtil",
+                "globalErrorHandler", "(JJ)I", ptr_to_jlong(dpy), ptr_to_jlong(event)).i;
         }
     }
     return 0;
--- a/jdk/src/windows/bin/cmdtoargs.c	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/windows/bin/cmdtoargs.c	Mon Jun 10 10:38:33 2013 +0100
@@ -128,7 +128,9 @@
                 *wildcard = JNI_TRUE;
             }
             if (prev == '\\') {
-                *dest++ = prev;
+                for (i = 0 ; i < slashes ; i++) {
+                    *dest++ = prev;
+                }
             }
             *dest++ = ch;
             break;
@@ -184,7 +186,7 @@
         argv = (StdArg*) JLI_MemRealloc(argv, (nargs+1) * sizeof(StdArg));
         argv[nargs].arg = JLI_StringDup(arg);
         argv[nargs].has_wildcard = wildcard;
-
+        *arg = NULL;
         nargs++;
     } while (src != NULL);
 
@@ -602,6 +604,14 @@
     v->add("d", FALSE);
     vectors[i++] = v;
 
+    v= new Vector(argv[0], "\\\\?");
+    v->add("\\\\?", TRUE);
+    vectors[i++] = v;
+
+    v= new Vector(argv[0], "\\\\*");
+    v->add("\\\\*", TRUE);
+    vectors[i++] = v;
+
     dotest(vectors);
     printf("All tests pass [%d]\n", i);
     doexit(0);
--- a/jdk/src/windows/classes/sun/awt/windows/WPathGraphics.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/windows/classes/sun/awt/windows/WPathGraphics.java	Mon Jun 10 10:38:33 2013 +0100
@@ -549,6 +549,8 @@
                 userx += xAdvance;
                 userpos.x += xAdvance;
                 deviceTransform.transform(userpos, devpos);
+                devx = devpos.x;
+                devy = devpos.y;
             }
         } else {
             super.drawString(str, x, y, font, frc, targetW);
--- a/jdk/src/windows/classes/sun/nio/fs/WindowsConstants.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsConstants.java	Mon Jun 10 10:38:33 2013 +0100
@@ -100,6 +100,7 @@
     public static final int ERROR_INVALID_LEVEL         = 124;
     public static final int ERROR_DIR_NOT_EMPTY         = 145;
     public static final int ERROR_ALREADY_EXISTS        = 183;
+    public static final int ERROR_MORE_DATA             = 234;
     public static final int ERROR_DIRECTORY             = 267;
     public static final int ERROR_NOTIFY_ENUM_DIR       = 1022;
     public static final int ERROR_NONE_MAPPED           = 1332;
--- a/jdk/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java	Mon Jun 10 10:38:33 2013 +0100
@@ -973,19 +973,19 @@
      * HANDLE CreateIoCompletionPort (
      *   HANDLE FileHandle,
      *   HANDLE ExistingCompletionPort,
-     *   DWORD CompletionKey,
+     *   ULONG_PTR CompletionKey,
      *   DWORD NumberOfConcurrentThreads
      * )
      */
     static native long CreateIoCompletionPort(long fileHandle, long existingPort,
-        int completionKey) throws WindowsException;
+        long completionKey) throws WindowsException;
 
 
     /**
      * GetQueuedCompletionStatus(
      *   HANDLE CompletionPort,
      *   LPDWORD lpNumberOfBytesTransferred,
-     *   LPDWORD lpCompletionKey,
+     *   PULONG_PTR lpCompletionKey,
      *   LPOVERLAPPED *lpOverlapped,
      *   DWORD dwMilliseconds
      */
@@ -999,12 +999,12 @@
     static class CompletionStatus {
         private int error;
         private int bytesTransferred;
-        private int completionKey;
+        private long completionKey;
         private CompletionStatus() { }
 
         int error() { return error; }
         int bytesTransferred() { return bytesTransferred; }
-        int completionKey() { return completionKey; }
+        long completionKey() { return completionKey; }
     }
     private static native void GetQueuedCompletionStatus0(long completionPort,
         CompletionStatus status) throws WindowsException;
@@ -1013,12 +1013,12 @@
      * PostQueuedCompletionStatus(
      *   HANDLE CompletionPort,
      *   DWORD dwNumberOfBytesTransferred,
-     *   DWORD dwCompletionKey,
+     *   ULONG_PTR dwCompletionKey,
      *   LPOVERLAPPED lpOverlapped
      * )
      */
     static native void PostQueuedCompletionStatus(long completionPort,
-        int completionKey) throws WindowsException;
+        long completionKey) throws WindowsException;
 
     /**
      * ReadDirectoryChangesW(
--- a/jdk/src/windows/classes/sun/nio/fs/WindowsWatchService.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsWatchService.java	Mon Jun 10 10:38:33 2013 +0100
@@ -41,6 +41,7 @@
 class WindowsWatchService
     extends AbstractWatchService
 {
+    private final static int WAKEUP_COMPLETION_KEY = 0;
     private final Unsafe unsafe = Unsafe.getUnsafe();
 
     // background thread to service I/O completion port
@@ -83,7 +84,7 @@
      */
     private class WindowsWatchKey extends AbstractWatchKey {
         // file key (used to detect existing registrations)
-        private FileKey fileKey;
+        private final FileKey fileKey;
 
         // handle to directory
         private volatile long handle = INVALID_HANDLE_VALUE;
@@ -223,8 +224,7 @@
             FileKey other = (FileKey)obj;
             if (this.volSerialNumber != other.volSerialNumber) return false;
             if (this.fileIndexHigh != other.fileIndexHigh) return false;
-            if (this.fileIndexLow != other.fileIndexLow) return false;
-            return true;
+            return this.fileIndexLow == other.fileIndexLow;
         }
     }
 
@@ -268,6 +268,7 @@
         private static final short OFFSETOF_FILENAME        = 12;
 
         // size of per-directory buffer for events (FIXME - make this configurable)
+        // Need to be less than 4*16384 = 65536. DWORD align.
         private static final int CHANGES_BUFFER_SIZE    = 16 * 1024;
 
         private final WindowsFileSystem fs;
@@ -275,27 +276,28 @@
         private final long port;
 
         // maps completion key to WatchKey
-        private final Map<Integer,WindowsWatchKey> int2key;
+        private final Map<Integer,WindowsWatchKey> ck2key;
 
         // maps file key to WatchKey
         private final Map<FileKey,WindowsWatchKey> fk2key;
 
         // unique completion key for each directory
+        // native completion key capacity is 64 bits on Win64.
         private int lastCompletionKey;
 
         Poller(WindowsFileSystem fs, WindowsWatchService watcher, long port) {
             this.fs = fs;
             this.watcher = watcher;
             this.port = port;
-            this.int2key = new HashMap<Integer,WindowsWatchKey>();
-            this.fk2key = new HashMap<FileKey,WindowsWatchKey>();
+            this.ck2key = new HashMap<>();
+            this.fk2key = new HashMap<>();
             this.lastCompletionKey = 0;
         }
 
         @Override
         void wakeup() throws IOException {
             try {
-                PostQueuedCompletionStatus(port, 0);
+                PostQueuedCompletionStatus(port, WAKEUP_COMPLETION_KEY);
             } catch (WindowsException x) {
                 throw new IOException(x.getMessage());
             }
@@ -322,7 +324,6 @@
             for (WatchEvent.Modifier modifier: modifiers) {
                 if (modifier == ExtendedWatchEventModifier.FILE_TREE) {
                     watchSubtree = true;
-                    continue;
                 } else {
                     if (modifier == null)
                         return new NullPointerException();
@@ -333,7 +334,7 @@
             }
 
             // open directory
-            long handle = -1L;
+            long handle;
             try {
                 handle = CreateFile(dir.getPathForWin32Calls(),
                                     FILE_LIST_DIRECTORY,
@@ -347,7 +348,7 @@
             boolean registered = false;
             try {
                 // read attributes and check file is a directory
-                WindowsFileAttributes attrs = null;
+                WindowsFileAttributes attrs;
                 try {
                     attrs = WindowsFileAttributes.readAttributes(handle);
                 } catch (WindowsException x) {
@@ -370,9 +371,10 @@
                     return existing;
                 }
 
-                // unique completion key (skip 0)
+                // Can overflow the int type capacity.
+                // Skip WAKEUP_COMPLETION_KEY value.
                 int completionKey = ++lastCompletionKey;
-                if (completionKey == 0)
+                if (completionKey == WAKEUP_COMPLETION_KEY)
                     completionKey = ++lastCompletionKey;
 
                 // associate handle with completion port
@@ -418,13 +420,13 @@
                     // 1. remove mapping from old completion key to existing watch key
                     // 2. release existing key's resources (handle/buffer)
                     // 3. re-initialize key with new handle/buffer
-                    int2key.remove(existing.completionKey());
+                    ck2key.remove(existing.completionKey());
                     existing.releaseResources();
                     watchKey = existing.init(handle, events, watchSubtree, buffer,
                         countAddress, overlappedAddress, completionKey);
                 }
                 // map completion map to watch key
-                int2key.put(completionKey, watchKey);
+                ck2key.put(completionKey, watchKey);
 
                 registered = true;
                 return watchKey;
@@ -440,7 +442,7 @@
             WindowsWatchKey key = (WindowsWatchKey)obj;
             if (key.isValid()) {
                 fk2key.remove(key.fileKey());
-                int2key.remove(key.completionKey());
+                ck2key.remove(key.completionKey());
                 key.invalidate();
             }
         }
@@ -449,11 +451,11 @@
         @Override
         void implCloseAll() {
             // cancel all keys
-            for (Map.Entry<Integer,WindowsWatchKey> entry: int2key.entrySet()) {
+            for (Map.Entry<Integer, WindowsWatchKey> entry: ck2key.entrySet()) {
                 entry.getValue().invalidate();
             }
             fk2key.clear();
-            int2key.clear();
+            ck2key.clear();
 
             // close I/O completion port
             CloseHandle(port);
@@ -517,7 +519,7 @@
         @Override
         public void run() {
             for (;;) {
-                CompletionStatus info = null;
+                CompletionStatus info;
                 try {
                     info = GetQueuedCompletionStatus(port);
                 } catch (WindowsException x) {
@@ -527,7 +529,7 @@
                 }
 
                 // wakeup
-                if (info.completionKey() == 0) {
+                if (info.completionKey() == WAKEUP_COMPLETION_KEY) {
                     boolean shutdown = processRequests();
                     if (shutdown) {
                         return;
@@ -536,7 +538,7 @@
                 }
 
                 // map completionKey to get WatchKey
-                WindowsWatchKey key = int2key.get(info.completionKey());
+                WindowsWatchKey key = ck2key.get((int)info.completionKey());
                 if (key == null) {
                     // We get here when a registration is changed. In that case
                     // the directory is closed which causes an event with the
@@ -544,38 +546,44 @@
                     continue;
                 }
 
-                // ReadDirectoryChangesW failed
-                if (info.error() != 0) {
+                boolean criticalError = false;
+                int errorCode = info.error();
+                int messageSize = info.bytesTransferred();
+                if (errorCode == ERROR_NOTIFY_ENUM_DIR) {
                     // buffer overflow
-                    if (info.error() == ERROR_NOTIFY_ENUM_DIR) {
-                        key.signalEvent(StandardWatchEventKinds.OVERFLOW, null);
-                    } else {
-                        // other error so cancel key
-                        implCancelKey(key);
-                        key.signal();
-                    }
-                    continue;
-                }
+                    key.signalEvent(StandardWatchEventKinds.OVERFLOW, null);
+                } else if (errorCode != 0 && errorCode != ERROR_MORE_DATA) {
+                    // ReadDirectoryChangesW failed
+                    criticalError = true;
+                } else {
+                    // ERROR_MORE_DATA is a warning about incomplite
+                    // data transfer over TCP/UDP stack. For the case
+                    // [messageSize] is zero in the most of cases.
 
-                // process the events
-                if (info.bytesTransferred() > 0) {
-                    processEvents(key, info.bytesTransferred());
-                } else {
-                    // insufficient buffer size
-                    key.signalEvent(StandardWatchEventKinds.OVERFLOW, null);
-                }
+                    if (messageSize > 0) {
+                        // process non-empty events.
+                        processEvents(key, messageSize);
+                    } else if (errorCode == 0) {
+                        // insufficient buffer size
+                        // not described, but can happen.
+                        key.signalEvent(StandardWatchEventKinds.OVERFLOW, null);
+                    }
 
-                // start read for next batch of changes
-                try {
-                    ReadDirectoryChangesW(key.handle(),
-                                          key.buffer().address(),
-                                          CHANGES_BUFFER_SIZE,
-                                          key.watchSubtree(),
-                                          ALL_FILE_NOTIFY_EVENTS,
-                                          key.countAddress(),
-                                          key.overlappedAddress());
-                } catch (WindowsException x) {
-                    // no choice but to cancel key
+                    // start read for next batch of changes
+                    try {
+                        ReadDirectoryChangesW(key.handle(),
+                                              key.buffer().address(),
+                                              CHANGES_BUFFER_SIZE,
+                                              key.watchSubtree(),
+                                              ALL_FILE_NOTIFY_EVENTS,
+                                              key.countAddress(),
+                                              key.overlappedAddress());
+                    } catch (WindowsException x) {
+                        // no choice but to cancel key
+                        criticalError = true;
+                    }
+                }
+                if (criticalError) {
                     implCancelKey(key);
                     key.signal();
                 }
--- a/jdk/src/windows/classes/sun/security/krb5/internal/tools/Ktab.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/windows/classes/sun/security/krb5/internal/tools/Ktab.java	Mon Jun 10 10:38:33 2013 +0100
@@ -80,42 +80,24 @@
         } else {
             ktab.processArgs(args);
         }
-        try {
+        ktab.table = KeyTab.getInstance(ktab.name);
+        if (ktab.table.isMissing() && ktab.action != 'a') {
             if (ktab.name == null) {
-                //  ktab.admin = new KeyTabAdmin();    // use the default keytab.
-                ktab.table = KeyTab.getInstance();
-                if (ktab.table == null) {
-                    if (ktab.action == 'a') {
-                        ktab.table = KeyTab.create();
-                    } else {
-                        System.out.println("No default key table exists.");
-                        System.exit(-1);
-                    }
-                }
+                System.out.println("No default key table exists.");
             } else {
-                if ((ktab.action != 'a') &&
-                    !(new File(ktab.name)).exists()) {
-                    System.out.println("Key table " +
-                                ktab.name + " does not exist.");
-                    System.exit(-1);
-                } else {
-                    ktab.table = KeyTab.getInstance(ktab.name);
-                }
-                if (ktab.table == null) {
-                    if (ktab.action == 'a') {
-                        ktab.table = KeyTab.create(ktab.name);
-                    } else {
-                        System.out.println("The format of key table " +
-                                ktab.name + " is incorrect.");
-                        System.exit(-1);
-                    }
-                }
+                System.out.println("Key table " +
+                        ktab.name + " does not exist.");
             }
-        } catch (RealmException e) {
-            System.err.println("Error loading key table.");
             System.exit(-1);
-        } catch (IOException e) {
-            System.err.println("Error loading key table.");
+        }
+        if (!ktab.table.isValid()) {
+            if (ktab.name == null) {
+                System.out.println("The format of the default key table " +
+                        " is incorrect.");
+            } else {
+                System.out.println("The format of key table " +
+                        ktab.name + " is incorrect.");
+            }
             System.exit(-1);
         }
         switch (ktab.action) {
--- a/jdk/src/windows/classes/sun/util/locale/provider/HostLocaleProviderAdapterImpl.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/windows/classes/sun/util/locale/provider/HostLocaleProviderAdapterImpl.java	Mon Jun 10 10:38:33 2013 +0100
@@ -48,7 +48,6 @@
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.atomic.AtomicReferenceArray;
 import java.util.spi.CalendarDataProvider;
-import java.util.spi.CalendarNameProvider;
 import java.util.spi.CurrencyNameProvider;
 import java.util.spi.LocaleNameProvider;
 import sun.util.spi.CalendarProvider;
@@ -364,32 +363,6 @@
         };
     }
 
-    public static CalendarNameProvider getCalendarNameProvider() {
-        return new CalendarNameProvider() {
-            @Override
-            public Locale[] getAvailableLocales() {
-                return getSupportedCalendarLocales();
-            }
-
-            @Override
-            public boolean isSupportedLocale(Locale locale) {
-                return isSupportedCalendarLocale(locale);
-            }
-
-            @Override
-            public String getDisplayName(String calType, int field, int value,
-                                         int style, Locale locale) {
-                return null;
-            }
-
-            @Override
-            public Map<String, Integer> getDisplayNames(String calType,
-                                         int field, int style, Locale locale) {
-                return null;
-            }
-        };
-    }
-
     public static CalendarProvider getCalendarProvider() {
         return new CalendarProvider() {
             @Override
--- a/jdk/src/windows/native/java/io/WinNTFileSystem_md.c	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/windows/native/java/io/WinNTFileSystem_md.c	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 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
@@ -199,7 +199,7 @@
 
 /**
  * If the given attributes are the attributes of a reparse point, then
- * read and return the attributes of the final target.
+ * read and return the attributes of the special cases.
  */
 DWORD getFinalAttributesIfReparsePoint(WCHAR *path, DWORD a)
 {
@@ -213,6 +213,28 @@
     return a;
 }
 
+/**
+ * Take special cases into account when retrieving the attributes
+ * of path
+ */
+DWORD getFinalAttributes(WCHAR *path)
+{
+    DWORD attr = INVALID_FILE_ATTRIBUTES;
+
+    WIN32_FILE_ATTRIBUTE_DATA wfad;
+    WIN32_FIND_DATAW wfd;
+    HANDLE h;
+
+    if (GetFileAttributesExW(path, GetFileExInfoStandard, &wfad)) {
+        attr = getFinalAttributesIfReparsePoint(path, wfad.dwFileAttributes);
+    } else if (GetLastError() == ERROR_SHARING_VIOLATION &&
+               (h = FindFirstFileW(path, &wfd)) != INVALID_HANDLE_VALUE) {
+        attr = getFinalAttributesIfReparsePoint(path, wfd.dwFileAttributes);
+        FindClose(h);
+    }
+    return attr;
+}
+
 JNIEXPORT jstring JNICALL
 Java_java_io_WinNTFileSystem_canonicalize0(JNIEnv *env, jobject this,
                                            jstring pathname)
@@ -337,38 +359,21 @@
 Java_java_io_WinNTFileSystem_getBooleanAttributes(JNIEnv *env, jobject this,
                                                   jobject file)
 {
-
     jint rv = 0;
     jint pathlen;
 
-    /* both pagefile.sys and hiberfil.sys have length 12 */
-#define SPECIALFILE_NAMELEN 12
-
     WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
-    WIN32_FILE_ATTRIBUTE_DATA wfad;
     if (pathbuf == NULL)
         return rv;
     if (!isReservedDeviceNameW(pathbuf)) {
-        if (GetFileAttributesExW(pathbuf, GetFileExInfoStandard, &wfad)) {
-            DWORD a = getFinalAttributesIfReparsePoint(pathbuf, wfad.dwFileAttributes);
-            if (a != INVALID_FILE_ATTRIBUTES) {
-                rv = (java_io_FileSystem_BA_EXISTS
-                    | ((a & FILE_ATTRIBUTE_DIRECTORY)
-                        ? java_io_FileSystem_BA_DIRECTORY
-                        : java_io_FileSystem_BA_REGULAR)
-                    | ((a & FILE_ATTRIBUTE_HIDDEN)
-                        ? java_io_FileSystem_BA_HIDDEN : 0));
-            }
-        } else { /* pagefile.sys is a special case */
-            if (GetLastError() == ERROR_SHARING_VIOLATION) {
-                rv = java_io_FileSystem_BA_EXISTS;
-                if ((pathlen = (jint)wcslen(pathbuf)) >= SPECIALFILE_NAMELEN &&
-                    (_wcsicmp(pathbuf + pathlen - SPECIALFILE_NAMELEN,
-                              L"pagefile.sys") == 0) ||
-                    (_wcsicmp(pathbuf + pathlen - SPECIALFILE_NAMELEN,
-                              L"hiberfil.sys") == 0))
-                  rv |= java_io_FileSystem_BA_REGULAR;
-            }
+        DWORD a = getFinalAttributes(pathbuf);
+        if (a != INVALID_FILE_ATTRIBUTES) {
+            rv = (java_io_FileSystem_BA_EXISTS
+                | ((a & FILE_ATTRIBUTE_DIRECTORY)
+                    ? java_io_FileSystem_BA_DIRECTORY
+                    : java_io_FileSystem_BA_REGULAR)
+                | ((a & FILE_ATTRIBUTE_HIDDEN)
+                    ? java_io_FileSystem_BA_HIDDEN : 0));
         }
     }
     free(pathbuf);
--- a/jdk/src/windows/native/java/net/DualStackPlainDatagramSocketImpl.c	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/windows/native/java/net/DualStackPlainDatagramSocketImpl.c	Mon Jun 10 10:38:33 2013 +0100
@@ -255,14 +255,14 @@
     packetBuffer = (*env)->GetObjectField(env, dpObj, dp_bufID);
     packetBufferOffset = (*env)->GetIntField(env, dpObj, dp_offsetID);
     packetBufferLen = (*env)->GetIntField(env, dpObj, dp_bufLengthID);
+    /* Note: the buffer needn't be greater than 65,536 (0xFFFF)
+    * the max size of an IP packet. Anything bigger is truncated anyway.
+    */
+    if (packetBufferLen > MAX_PACKET_LEN) {
+        packetBufferLen = MAX_PACKET_LEN;
+    }
 
     if (packetBufferLen > MAX_BUFFER_LEN) {
-        /* Note: the buffer needn't be greater than 65,536 (0xFFFF)
-         * the max size of an IP packet. Anything bigger is truncated anyway.
-         */
-        if (packetBufferLen > MAX_PACKET_LEN) {
-            packetBufferLen = MAX_PACKET_LEN;
-        }
         fullPacket = (char *)malloc(packetBufferLen);
         if (!fullPacket) {
             JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed");
--- a/jdk/src/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c	Mon Jun 10 10:38:33 2013 +0100
@@ -145,7 +145,7 @@
 /*
  * This function returns JNI_TRUE if the datagram size exceeds the underlying
  * provider's ability to send to the target address. The following OS
- * oddies have been observed :-
+ * oddities have been observed :-
  *
  * 1. On Windows 95/98 if we try to send a datagram > 12k to an application
  *    on the same machine then the send will fail silently.
@@ -218,7 +218,7 @@
 
             /*
              * Step 3: On Windows 95/98 then enumerate the IP addresses on
-             * this machine. This is necesary because we need to check if the
+             * this machine. This is neccesary because we need to check if the
              * datagram is being sent to an application on the same machine.
              */
             if (is95or98) {
@@ -566,8 +566,8 @@
 
     if (xp_or_later) {
         /* SIO_UDP_CONNRESET fixes a bug introduced in Windows 2000, which
-         * returns connection reset errors un connected UDP sockets (as well
-         * as connected sockets. The solution is to only enable this feature
+         * returns connection reset errors on connected UDP sockets (as well
+         * as connected sockets). The solution is to only enable this feature
          * when the socket is connected
          */
         DWORD x1, x2; /* ignored result codes */
@@ -691,6 +691,12 @@
     fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 
     packetBufferLen = (*env)->GetIntField(env, packet, dp_lengthID);
+    /* Note: the buffer needn't be greater than 65,536 (0xFFFF)...
+     * the maximum size of an IP packet. Anything bigger is truncated anyway.
+     */
+    if (packetBufferLen > MAX_PACKET_LEN) {
+        packetBufferLen = MAX_PACKET_LEN;
+    }
 
     if (connected) {
         addrp = 0; /* arg to JVM_Sendto () null in this case */
@@ -729,7 +735,7 @@
         }
 
         /* When JNI-ifying the JDK's IO routines, we turned
-         * read's and write's of byte arrays of size greater
+         * reads and writes of byte arrays of size greater
          * than 2048 bytes into several operations of size 2048.
          * This saves a malloc()/memcpy()/free() for big
          * buffers.  This is OK for file IO and TCP, but that
--- a/jdk/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c	Mon Jun 10 10:38:33 2013 +0100
@@ -162,7 +162,7 @@
     }
     completionStatus_error = (*env)->GetFieldID(env, clazz, "error", "I");
     completionStatus_bytesTransferred = (*env)->GetFieldID(env, clazz, "bytesTransferred", "I");
-    completionStatus_completionKey = (*env)->GetFieldID(env, clazz, "completionKey", "I");
+    completionStatus_completionKey = (*env)->GetFieldID(env, clazz, "completionKey", "J");
 
     clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$BackupResult");
     if (clazz == NULL) {
@@ -1169,12 +1169,11 @@
 
 JNIEXPORT jlong JNICALL
 Java_sun_nio_fs_WindowsNativeDispatcher_CreateIoCompletionPort(JNIEnv* env, jclass this,
-    jlong fileHandle, jlong existingPort, jint completionKey)
+    jlong fileHandle, jlong existingPort, jlong completionKey)
 {
-    ULONG_PTR ck = completionKey;
     HANDLE port = CreateIoCompletionPort((HANDLE)jlong_to_ptr(fileHandle),
                                          (HANDLE)jlong_to_ptr(existingPort),
-                                         ck,
+                                         (ULONG_PTR)completionKey,
                                          0);
     if (port == NULL) {
         throwWindowsException(env, GetLastError());
@@ -1203,21 +1202,20 @@
         (*env)->SetIntField(env, obj, completionStatus_error, ioResult);
         (*env)->SetIntField(env, obj, completionStatus_bytesTransferred,
             (jint)bytesTransferred);
-        (*env)->SetIntField(env, obj, completionStatus_completionKey,
-            (jint)completionKey);
-
+        (*env)->SetLongField(env, obj, completionStatus_completionKey,
+            (jlong)completionKey);
     }
 }
 
 JNIEXPORT void JNICALL
 Java_sun_nio_fs_WindowsNativeDispatcher_PostQueuedCompletionStatus(JNIEnv* env, jclass this,
-    jlong completionPort, jint completionKey)
+    jlong completionPort, jlong completionKey)
 {
     BOOL res;
 
     res = PostQueuedCompletionStatus((HANDLE)jlong_to_ptr(completionPort),
                                      (DWORD)0,  /* dwNumberOfBytesTransferred */
-                                     (DWORD)completionKey,
+                                     (ULONG_PTR)completionKey,
                                      NULL);  /* lpOverlapped */
     if (res == 0) {
         throwWindowsException(env, GetLastError());
@@ -1232,7 +1230,17 @@
     BOOL res;
     BOOL subtree = (watchSubTree == JNI_TRUE) ? TRUE : FALSE;
 
-    ((LPOVERLAPPED)jlong_to_ptr(pOverlapped))->hEvent = NULL;
+    /* Any unused members of [OVERLAPPED] structure should always be initialized to zero
+       before the structure is used in a function call.
+       Otherwise, the function may fail and return ERROR_INVALID_PARAMETER.
+       http://msdn.microsoft.com/en-us/library/windows/desktop/ms684342%28v=vs.85%29.aspx
+
+       The [Offset] and [OffsetHigh] members of this structure are not used.
+       http://msdn.microsoft.com/en-us/library/windows/desktop/aa365465%28v=vs.85%29.aspx
+
+       [hEvent] should be zero, other fields are the return values. */
+    ZeroMemory((LPOVERLAPPED)jlong_to_ptr(pOverlapped), sizeof(OVERLAPPED));
+
     res = ReadDirectoryChangesW((HANDLE)jlong_to_ptr(hDirectory),
                                 (LPVOID)jlong_to_ptr(bufferAddress),
                                 (DWORD)bufferLength,
--- a/jdk/test/Makefile	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/Makefile	Mon Jun 10 10:38:33 2013 +0100
@@ -657,9 +657,12 @@
 # Multiple by 4 the timeout numbers
 JTREG_TIMEOUT_OPTION =  -timeoutFactor:4
 JTREG_BASIC_OPTIONS += $(JTREG_TIMEOUT_OPTION)
-# Boost the max memory for jtreg to avoid gc thrashing
+# Set the max memory for jtreg control vm
 JTREG_MEMORY_OPTION = -J-Xmx512m
 JTREG_BASIC_OPTIONS += $(JTREG_MEMORY_OPTION)
+# Set the max memory for jtreg target test vms
+JTREG_TESTVM_MEMORY_OPTION = -vmoption:-Xmx512m
+JTREG_TEST_OPTIONS += $(JTREG_TESTVM_MEMORY_OPTION)
 
 # Make sure jtreg exists
 $(JTREG): $(JT_HOME)
--- a/jdk/test/ProblemList.txt	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/ProblemList.txt	Mon Jun 10 10:38:33 2013 +0100
@@ -122,9 +122,6 @@
 
 # jdk_lang
 
-# 8009615
-java/lang/instrument/IsModifiableClassAgent.java                generic-all
-
 # 6944188
 java/lang/management/ThreadMXBean/ThreadStateTest.java          generic-all
 
@@ -137,15 +134,15 @@
 # 8008200
 java/lang/Class/asSubclass/BasicUnit.java                       generic-all
 
-# 8009552
-vm/verifier/TestStaticIF.java                                   generic-all
+# 8015780
+java/lang/reflect/Method/GenericStringTest.java			generic-all
 
 ############################################################################
 
 # jdk_management
 
 # 8010897
-sun/management/HotspotRuntimeMBean/GetSafepointSyncTime.java	macosx-all 
+sun/management/HotspotRuntimeMBean/GetSafepointSyncTime.java	macosx-all
 
 ############################################################################
 
@@ -154,9 +151,6 @@
 # 6959636
 javax/management/loading/LibraryLoader/LibraryLoaderTest.java	windows-all
 
-# 8005472
-com/sun/jmx/remote/NotificationMarshalVersions/TestSerializationMismatch.sh windows-all
-
 ############################################################################
 
 # jdk_math
@@ -205,12 +199,6 @@
 # 7143960
 java/net/DatagramSocket/SendDatagramToBadAddress.java            macosx-all
 
-# 8014720
-java/net/ResponseCache/B6181108.java                             generic-all
-
-# 8014723
-sun/misc/URLClassPath/ClassnameCharTest.java                     generic-all
-
 # 8014719
 sun/net/www/http/HttpClient/ProxyTest.java                       generic-all
 
@@ -242,9 +230,6 @@
 # 7132677
 java/nio/channels/Selector/OutOfBand.java                       macosx-all
 
-# 8003895
-java/nio/channels/AsynchronousChannelGroup/Unbounded.java       windows-amd64
-
 ############################################################################
 
 # jdk_rmi
@@ -283,6 +268,13 @@
 sun/security/pkcs11/ec/ReadPKCS12.java                          solaris-all
 sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java            solaris-all
 
+# 8005247
+sun/security/pkcs11/ec/TestECDSA.java				solaris-all
+
+# 8009438
+sun/security/pkcs11/Secmod/AddPrivateKey.java			linux-all
+sun/security/pkcs11/Secmod/TrustAnchors.java 			linux-all
+
 # 7041639, Solaris DSA keypair generation bug (Note: jdk_util also affected)
 java/security/KeyPairGenerator/SolarisShortDSA.java             solaris-all
 sun/security/tools/jarsigner/onlymanifest.sh                    solaris-all
@@ -305,9 +297,6 @@
 # 7194428
 sun/security/mscapi/ShortRSAKey1024.sh                          windows-all
 
-# 8000897, vm crash
-sun/security/provider/DSA/TestAlgParameterGenerator.java        generic-all
-
 # 7144048, performance issue
 sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/SSLEngineDeadlock.java generic-all
 
@@ -338,11 +327,10 @@
 sun/jvmstat/monitor/MonitoredVm/CR6672135.java                  generic-all
 
 # Tests take too long, on sparcs see 7143279
-tools/pack200/CommandLineTests.java                             solaris-all, macosx-all 
+tools/pack200/CommandLineTests.java                             solaris-all, macosx-all
 tools/pack200/Pack200Test.java                                  solaris-all, macosx-all
-
-# 7150569
-tools/launcher/UnicodeTest.java                                 macosx-all
+# 8015666 
+tools/pack200/TimeStamp.java                                    generic-all
 
 # 8007410
 tools/launcher/FXLauncherTest.java                              linux-all
--- a/jdk/test/com/sun/crypto/provider/Mac/HmacPBESHA1.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/com/sun/crypto/provider/Mac/HmacPBESHA1.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -23,8 +23,8 @@
 
 /**
  * @test
- * @bug 4893959
- * @summary basic test for HmacPBESHA1
+ * @bug 4893959 8013069
+ * @summary basic test for PBE MAC algorithms.
  * @author Valerie Peng
  */
 import java.io.PrintStream;
@@ -68,8 +68,9 @@
         }
         Mac mac = Mac.getInstance(algo, PROVIDER);
         byte[] plainText = new byte[30];
-
-        mac.init(key);
+        PBEParameterSpec spec =
+            new PBEParameterSpec("saltValue".getBytes(), 250);
+        mac.init(key, spec);
         mac.update(plainText);
         byte[] value1 = mac.doFinal();
         if (value1.length != length) {
--- a/jdk/test/com/sun/crypto/provider/Mac/MacClone.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/com/sun/crypto/provider/Mac/MacClone.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,12 +23,13 @@
 
 /*
  * @test
- * @bug 7087021
- * @summary MacClone
+ * @bug 7087021 8013069
+ * @summary Clone tests for all MAC algorithms.
  * @author Jan Luehe
  */
+import java.security.spec.AlgorithmParameterSpec;
 import javax.crypto.*;
-import javax.crypto.spec.SecretKeySpec;
+import javax.crypto.spec.*;
 
 public class MacClone {
 
@@ -39,18 +40,23 @@
         KeyGenerator kgen = KeyGenerator.getInstance("DES");
         SecretKey skey = kgen.generateKey();
         for (String algo : algos) {
-            doTest(algo, skey);
+            doTest(algo, skey, null);
         }
 
-        String[] algos2 = { "HmacPBESHA1" };
+        String[] algos2 = { "HmacPBESHA1", "PBEWithHmacSHA1",
+                            "PBEWithHmacSHA224", "PBEWithHmacSHA256",
+                            "PBEWithHmacSHA384", "PBEWithHmacSHA512" };
         skey = new SecretKeySpec("whatever".getBytes(), "PBE");
+        PBEParameterSpec params =
+            new PBEParameterSpec("1234567890".getBytes(), 500);
         for (String algo : algos2) {
-            doTest(algo, skey);
+            doTest(algo, skey, params);
         }
         System.out.println("Test Passed");
     }
 
-    private static void doTest(String algo, SecretKey skey) throws Exception {
+    private static void doTest(String algo, SecretKey skey,
+        AlgorithmParameterSpec params) throws Exception {
         //
         // Clone an uninitialized Mac object
         //
@@ -72,7 +78,7 @@
         // Clone an initialized Mac object
         //
         mac = Mac.getInstance(algo, "SunJCE");
-        mac.init(skey);
+        mac.init(skey, params);
         macClone = (Mac)mac.clone();
         System.out.println(macClone.getProvider().toString());
         System.out.println(macClone.getAlgorithm());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/crypto/provider/TLS/TestLeadingZeroes.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,420 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8014618
+ * @summary Need to strip leading zeros in TlsPremasterSecret of DHKeyAgreement
+ * @author Pasi Eronen
+ */
+
+import java.io.*;
+import java.security.*;
+import java.security.spec.*;
+import java.security.interfaces.*;
+import javax.crypto.*;
+import javax.crypto.spec.*;
+import javax.crypto.interfaces.*;
+import com.sun.crypto.provider.SunJCE;
+
+/**
+ * Test that leading zeroes are stripped in TlsPremasterSecret case,
+ * but are left as-is in other cases.
+ *
+ * We use pre-generated keypairs, since with randomly generated keypairs,
+ * a leading zero happens only (roughly) 1 out of 256 cases.
+ */
+
+public class TestLeadingZeroes {
+
+    private static final String SUNJCE = "SunJCE";
+
+    private TestLeadingZeroes() {}
+
+    public static void main(String argv[]) throws Exception {
+        // Add JCE to the list of providers
+        SunJCE jce = new SunJCE();
+        Security.addProvider(jce);
+
+        TestLeadingZeroes keyAgree = new TestLeadingZeroes();
+        keyAgree.run();
+        System.out.println("Test Passed");
+    }
+
+    private void run() throws Exception {
+
+        // decode pre-generated keypairs
+        KeyFactory kfac = KeyFactory.getInstance("DH");
+        PublicKey alicePubKey =
+            kfac.generatePublic(new X509EncodedKeySpec(alicePubKeyEnc));
+        PublicKey bobPubKey =
+            kfac.generatePublic(new X509EncodedKeySpec(bobPubKeyEnc));
+        PrivateKey alicePrivKey =
+            kfac.generatePrivate(new PKCS8EncodedKeySpec(alicePrivKeyEnc));
+        PrivateKey bobPrivKey =
+            kfac.generatePrivate(new PKCS8EncodedKeySpec(bobPrivKeyEnc));
+
+        // generate normal shared secret
+        KeyAgreement aliceKeyAgree = KeyAgreement.getInstance("DH", SUNJCE);
+        aliceKeyAgree.init(alicePrivKey);
+        aliceKeyAgree.doPhase(bobPubKey, true);
+        byte[] sharedSecret = aliceKeyAgree.generateSecret();
+        System.out.println("shared secret:\n" + toHexString(sharedSecret));
+
+        // verify that leading zero is present
+        if (sharedSecret.length != 128) {
+            throw new Exception("Unexpected shared secret length");
+        }
+        if (sharedSecret[0] != 0) {
+            throw new Exception("First byte is not zero as expected");
+        }
+
+        // now, test TLS premaster secret
+        aliceKeyAgree.init(alicePrivKey);
+        aliceKeyAgree.doPhase(bobPubKey, true);
+        byte[] tlsPremasterSecret =
+            aliceKeyAgree.generateSecret("TlsPremasterSecret").getEncoded();
+        System.out.println(
+            "tls premaster secret:\n" + toHexString(tlsPremasterSecret));
+
+        // check that leading zero has been stripped
+        if (tlsPremasterSecret.length != 127) {
+            throw new Exception("Unexpected TLS premaster secret length");
+        }
+        if (tlsPremasterSecret[0] == 0) {
+            throw new Exception("First byte is zero");
+        }
+        for (int i = 0; i < tlsPremasterSecret.length; i++) {
+            if (tlsPremasterSecret[i] != sharedSecret[i+1]) {
+                throw new Exception("Shared secrets differ");
+            }
+        }
+
+    }
+
+    /*
+     * Converts a byte to hex digit and writes to the supplied buffer
+     */
+    private void byte2hex(byte b, StringBuffer buf) {
+        char[] hexChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
+                            '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+        int high = ((b & 0xf0) >> 4);
+        int low = (b & 0x0f);
+        buf.append(hexChars[high]);
+        buf.append(hexChars[low]);
+    }
+
+    /*
+     * Converts a byte array to hex string
+     */
+    private String toHexString(byte[] block) {
+        StringBuffer buf = new StringBuffer();
+
+        int len = block.length;
+
+        for (int i = 0; i < len; i++) {
+             byte2hex(block[i], buf);
+             if (i < len-1) {
+                 buf.append(":");
+             }
+        }
+        return buf.toString();
+    }
+
+    private static final byte alicePubKeyEnc[] = {
+        (byte)0x30, (byte)0x82, (byte)0x01, (byte)0x24,
+        (byte)0x30, (byte)0x81, (byte)0x99, (byte)0x06,
+        (byte)0x09, (byte)0x2A, (byte)0x86, (byte)0x48,
+        (byte)0x86, (byte)0xF7, (byte)0x0D, (byte)0x01,
+        (byte)0x03, (byte)0x01, (byte)0x30, (byte)0x81,
+        (byte)0x8B, (byte)0x02, (byte)0x81, (byte)0x81,
+        (byte)0x00, (byte)0xF4, (byte)0x88, (byte)0xFD,
+        (byte)0x58, (byte)0x4E, (byte)0x49, (byte)0xDB,
+        (byte)0xCD, (byte)0x20, (byte)0xB4, (byte)0x9D,
+        (byte)0xE4, (byte)0x91, (byte)0x07, (byte)0x36,
+        (byte)0x6B, (byte)0x33, (byte)0x6C, (byte)0x38,
+        (byte)0x0D, (byte)0x45, (byte)0x1D, (byte)0x0F,
+        (byte)0x7C, (byte)0x88, (byte)0xB3, (byte)0x1C,
+        (byte)0x7C, (byte)0x5B, (byte)0x2D, (byte)0x8E,
+        (byte)0xF6, (byte)0xF3, (byte)0xC9, (byte)0x23,
+        (byte)0xC0, (byte)0x43, (byte)0xF0, (byte)0xA5,
+        (byte)0x5B, (byte)0x18, (byte)0x8D, (byte)0x8E,
+        (byte)0xBB, (byte)0x55, (byte)0x8C, (byte)0xB8,
+        (byte)0x5D, (byte)0x38, (byte)0xD3, (byte)0x34,
+        (byte)0xFD, (byte)0x7C, (byte)0x17, (byte)0x57,
+        (byte)0x43, (byte)0xA3, (byte)0x1D, (byte)0x18,
+        (byte)0x6C, (byte)0xDE, (byte)0x33, (byte)0x21,
+        (byte)0x2C, (byte)0xB5, (byte)0x2A, (byte)0xFF,
+        (byte)0x3C, (byte)0xE1, (byte)0xB1, (byte)0x29,
+        (byte)0x40, (byte)0x18, (byte)0x11, (byte)0x8D,
+        (byte)0x7C, (byte)0x84, (byte)0xA7, (byte)0x0A,
+        (byte)0x72, (byte)0xD6, (byte)0x86, (byte)0xC4,
+        (byte)0x03, (byte)0x19, (byte)0xC8, (byte)0x07,
+        (byte)0x29, (byte)0x7A, (byte)0xCA, (byte)0x95,
+        (byte)0x0C, (byte)0xD9, (byte)0x96, (byte)0x9F,
+        (byte)0xAB, (byte)0xD0, (byte)0x0A, (byte)0x50,
+        (byte)0x9B, (byte)0x02, (byte)0x46, (byte)0xD3,
+        (byte)0x08, (byte)0x3D, (byte)0x66, (byte)0xA4,
+        (byte)0x5D, (byte)0x41, (byte)0x9F, (byte)0x9C,
+        (byte)0x7C, (byte)0xBD, (byte)0x89, (byte)0x4B,
+        (byte)0x22, (byte)0x19, (byte)0x26, (byte)0xBA,
+        (byte)0xAB, (byte)0xA2, (byte)0x5E, (byte)0xC3,
+        (byte)0x55, (byte)0xE9, (byte)0x2F, (byte)0x78,
+        (byte)0xC7, (byte)0x02, (byte)0x01, (byte)0x02,
+        (byte)0x02, (byte)0x02, (byte)0x02, (byte)0x00,
+        (byte)0x03, (byte)0x81, (byte)0x85, (byte)0x00,
+        (byte)0x02, (byte)0x81, (byte)0x81, (byte)0x00,
+        (byte)0xEE, (byte)0xD6, (byte)0xB1, (byte)0xA3,
+        (byte)0xB4, (byte)0x78, (byte)0x2B, (byte)0x35,
+        (byte)0xEF, (byte)0xCD, (byte)0x17, (byte)0x86,
+        (byte)0x63, (byte)0x2B, (byte)0x97, (byte)0x0E,
+        (byte)0x7A, (byte)0xD1, (byte)0xFF, (byte)0x7A,
+        (byte)0xEB, (byte)0x57, (byte)0x61, (byte)0xA1,
+        (byte)0xF7, (byte)0x90, (byte)0x11, (byte)0xA7,
+        (byte)0x79, (byte)0x28, (byte)0x69, (byte)0xBA,
+        (byte)0xA7, (byte)0xB2, (byte)0x37, (byte)0x17,
+        (byte)0xAE, (byte)0x3C, (byte)0x92, (byte)0x89,
+        (byte)0x88, (byte)0xE5, (byte)0x7E, (byte)0x8E,
+        (byte)0xF0, (byte)0x24, (byte)0xD0, (byte)0xE1,
+        (byte)0xC4, (byte)0xB0, (byte)0x26, (byte)0x5A,
+        (byte)0x1E, (byte)0xBD, (byte)0xA0, (byte)0xCF,
+        (byte)0x3E, (byte)0x97, (byte)0x2A, (byte)0x13,
+        (byte)0x92, (byte)0x3B, (byte)0x39, (byte)0xD0,
+        (byte)0x1D, (byte)0xA3, (byte)0x6B, (byte)0x3E,
+        (byte)0xC2, (byte)0xBB, (byte)0x14, (byte)0xB6,
+        (byte)0xE2, (byte)0x4C, (byte)0x0E, (byte)0x5B,
+        (byte)0x4B, (byte)0xA4, (byte)0x9D, (byte)0xA6,
+        (byte)0x21, (byte)0xB0, (byte)0xF9, (byte)0xDE,
+        (byte)0x55, (byte)0xAE, (byte)0x5C, (byte)0x29,
+        (byte)0x0E, (byte)0xC1, (byte)0xFC, (byte)0xBA,
+        (byte)0x51, (byte)0xD3, (byte)0xB6, (byte)0x6D,
+        (byte)0x75, (byte)0x72, (byte)0xDF, (byte)0x43,
+        (byte)0xAB, (byte)0x94, (byte)0x21, (byte)0x6E,
+        (byte)0x0C, (byte)0xD1, (byte)0x93, (byte)0x54,
+        (byte)0x56, (byte)0x7D, (byte)0x4B, (byte)0x90,
+        (byte)0xF1, (byte)0x94, (byte)0x45, (byte)0xD4,
+        (byte)0x2A, (byte)0x71, (byte)0xA1, (byte)0xB8,
+        (byte)0xDD, (byte)0xAA, (byte)0x05, (byte)0xF0,
+        (byte)0x27, (byte)0x37, (byte)0xBD, (byte)0x44
+    };
+
+    private static final byte alicePrivKeyEnc[] = {
+        (byte)0x30, (byte)0x81, (byte)0xE3, (byte)0x02,
+        (byte)0x01, (byte)0x00, (byte)0x30, (byte)0x81,
+        (byte)0x99, (byte)0x06, (byte)0x09, (byte)0x2A,
+        (byte)0x86, (byte)0x48, (byte)0x86, (byte)0xF7,
+        (byte)0x0D, (byte)0x01, (byte)0x03, (byte)0x01,
+        (byte)0x30, (byte)0x81, (byte)0x8B, (byte)0x02,
+        (byte)0x81, (byte)0x81, (byte)0x00, (byte)0xF4,
+        (byte)0x88, (byte)0xFD, (byte)0x58, (byte)0x4E,
+        (byte)0x49, (byte)0xDB, (byte)0xCD, (byte)0x20,
+        (byte)0xB4, (byte)0x9D, (byte)0xE4, (byte)0x91,
+        (byte)0x07, (byte)0x36, (byte)0x6B, (byte)0x33,
+        (byte)0x6C, (byte)0x38, (byte)0x0D, (byte)0x45,
+        (byte)0x1D, (byte)0x0F, (byte)0x7C, (byte)0x88,
+        (byte)0xB3, (byte)0x1C, (byte)0x7C, (byte)0x5B,
+        (byte)0x2D, (byte)0x8E, (byte)0xF6, (byte)0xF3,
+        (byte)0xC9, (byte)0x23, (byte)0xC0, (byte)0x43,
+        (byte)0xF0, (byte)0xA5, (byte)0x5B, (byte)0x18,
+        (byte)0x8D, (byte)0x8E, (byte)0xBB, (byte)0x55,
+        (byte)0x8C, (byte)0xB8, (byte)0x5D, (byte)0x38,
+        (byte)0xD3, (byte)0x34, (byte)0xFD, (byte)0x7C,
+        (byte)0x17, (byte)0x57, (byte)0x43, (byte)0xA3,
+        (byte)0x1D, (byte)0x18, (byte)0x6C, (byte)0xDE,
+        (byte)0x33, (byte)0x21, (byte)0x2C, (byte)0xB5,
+        (byte)0x2A, (byte)0xFF, (byte)0x3C, (byte)0xE1,
+        (byte)0xB1, (byte)0x29, (byte)0x40, (byte)0x18,
+        (byte)0x11, (byte)0x8D, (byte)0x7C, (byte)0x84,
+        (byte)0xA7, (byte)0x0A, (byte)0x72, (byte)0xD6,
+        (byte)0x86, (byte)0xC4, (byte)0x03, (byte)0x19,
+        (byte)0xC8, (byte)0x07, (byte)0x29, (byte)0x7A,
+        (byte)0xCA, (byte)0x95, (byte)0x0C, (byte)0xD9,
+        (byte)0x96, (byte)0x9F, (byte)0xAB, (byte)0xD0,
+        (byte)0x0A, (byte)0x50, (byte)0x9B, (byte)0x02,
+        (byte)0x46, (byte)0xD3, (byte)0x08, (byte)0x3D,
+        (byte)0x66, (byte)0xA4, (byte)0x5D, (byte)0x41,
+        (byte)0x9F, (byte)0x9C, (byte)0x7C, (byte)0xBD,
+        (byte)0x89, (byte)0x4B, (byte)0x22, (byte)0x19,
+        (byte)0x26, (byte)0xBA, (byte)0xAB, (byte)0xA2,
+        (byte)0x5E, (byte)0xC3, (byte)0x55, (byte)0xE9,
+        (byte)0x2F, (byte)0x78, (byte)0xC7, (byte)0x02,
+        (byte)0x01, (byte)0x02, (byte)0x02, (byte)0x02,
+        (byte)0x02, (byte)0x00, (byte)0x04, (byte)0x42,
+        (byte)0x02, (byte)0x40, (byte)0x36, (byte)0x4D,
+        (byte)0xD0, (byte)0x58, (byte)0x64, (byte)0x91,
+        (byte)0x78, (byte)0xA2, (byte)0x4B, (byte)0x79,
+        (byte)0x46, (byte)0xFE, (byte)0xC9, (byte)0xD9,
+        (byte)0xCA, (byte)0x5C, (byte)0xF9, (byte)0xFD,
+        (byte)0x6C, (byte)0x5D, (byte)0x76, (byte)0x3A,
+        (byte)0x41, (byte)0x6D, (byte)0x44, (byte)0x62,
+        (byte)0x75, (byte)0x93, (byte)0x81, (byte)0x93,
+        (byte)0x00, (byte)0x4C, (byte)0xB1, (byte)0xD8,
+        (byte)0x7D, (byte)0x9D, (byte)0xF3, (byte)0x16,
+        (byte)0x2C, (byte)0x6C, (byte)0x9F, (byte)0x7A,
+        (byte)0x84, (byte)0xA3, (byte)0x7A, (byte)0xC1,
+        (byte)0x4F, (byte)0x60, (byte)0xE3, (byte)0xB5,
+        (byte)0x86, (byte)0x28, (byte)0x08, (byte)0x4D,
+        (byte)0x94, (byte)0xB6, (byte)0x04, (byte)0x0D,
+        (byte)0xAC, (byte)0xBD, (byte)0x1F, (byte)0x42,
+        (byte)0x8F, (byte)0x1B
+    };
+
+    private static final byte bobPubKeyEnc[] = {
+        (byte)0x30, (byte)0x82, (byte)0x01, (byte)0x23,
+        (byte)0x30, (byte)0x81, (byte)0x99, (byte)0x06,
+        (byte)0x09, (byte)0x2A, (byte)0x86, (byte)0x48,
+        (byte)0x86, (byte)0xF7, (byte)0x0D, (byte)0x01,
+        (byte)0x03, (byte)0x01, (byte)0x30, (byte)0x81,
+        (byte)0x8B, (byte)0x02, (byte)0x81, (byte)0x81,
+        (byte)0x00, (byte)0xF4, (byte)0x88, (byte)0xFD,
+        (byte)0x58, (byte)0x4E, (byte)0x49, (byte)0xDB,
+        (byte)0xCD, (byte)0x20, (byte)0xB4, (byte)0x9D,
+        (byte)0xE4, (byte)0x91, (byte)0x07, (byte)0x36,
+        (byte)0x6B, (byte)0x33, (byte)0x6C, (byte)0x38,
+        (byte)0x0D, (byte)0x45, (byte)0x1D, (byte)0x0F,
+        (byte)0x7C, (byte)0x88, (byte)0xB3, (byte)0x1C,
+        (byte)0x7C, (byte)0x5B, (byte)0x2D, (byte)0x8E,
+        (byte)0xF6, (byte)0xF3, (byte)0xC9, (byte)0x23,
+        (byte)0xC0, (byte)0x43, (byte)0xF0, (byte)0xA5,
+        (byte)0x5B, (byte)0x18, (byte)0x8D, (byte)0x8E,
+        (byte)0xBB, (byte)0x55, (byte)0x8C, (byte)0xB8,
+        (byte)0x5D, (byte)0x38, (byte)0xD3, (byte)0x34,
+        (byte)0xFD, (byte)0x7C, (byte)0x17, (byte)0x57,
+        (byte)0x43, (byte)0xA3, (byte)0x1D, (byte)0x18,
+        (byte)0x6C, (byte)0xDE, (byte)0x33, (byte)0x21,
+        (byte)0x2C, (byte)0xB5, (byte)0x2A, (byte)0xFF,
+        (byte)0x3C, (byte)0xE1, (byte)0xB1, (byte)0x29,
+        (byte)0x40, (byte)0x18, (byte)0x11, (byte)0x8D,
+        (byte)0x7C, (byte)0x84, (byte)0xA7, (byte)0x0A,
+        (byte)0x72, (byte)0xD6, (byte)0x86, (byte)0xC4,
+        (byte)0x03, (byte)0x19, (byte)0xC8, (byte)0x07,
+        (byte)0x29, (byte)0x7A, (byte)0xCA, (byte)0x95,
+        (byte)0x0C, (byte)0xD9, (byte)0x96, (byte)0x9F,
+        (byte)0xAB, (byte)0xD0, (byte)0x0A, (byte)0x50,
+        (byte)0x9B, (byte)0x02, (byte)0x46, (byte)0xD3,
+        (byte)0x08, (byte)0x3D, (byte)0x66, (byte)0xA4,
+        (byte)0x5D, (byte)0x41, (byte)0x9F, (byte)0x9C,
+        (byte)0x7C, (byte)0xBD, (byte)0x89, (byte)0x4B,
+        (byte)0x22, (byte)0x19, (byte)0x26, (byte)0xBA,
+        (byte)0xAB, (byte)0xA2, (byte)0x5E, (byte)0xC3,
+        (byte)0x55, (byte)0xE9, (byte)0x2F, (byte)0x78,
+        (byte)0xC7, (byte)0x02, (byte)0x01, (byte)0x02,
+        (byte)0x02, (byte)0x02, (byte)0x02, (byte)0x00,
+        (byte)0x03, (byte)0x81, (byte)0x84, (byte)0x00,
+        (byte)0x02, (byte)0x81, (byte)0x80, (byte)0x2C,
+        (byte)0x40, (byte)0xFA, (byte)0xF6, (byte)0xA6,
+        (byte)0xF8, (byte)0xAC, (byte)0xC2, (byte)0x4F,
+        (byte)0xCD, (byte)0xC7, (byte)0x37, (byte)0x93,
+        (byte)0xE5, (byte)0xE4, (byte)0x5E, (byte)0x18,
+        (byte)0x14, (byte)0xE6, (byte)0x50, (byte)0xDA,
+        (byte)0x55, (byte)0x38, (byte)0x5D, (byte)0x24,
+        (byte)0xF5, (byte)0x42, (byte)0x68, (byte)0x5F,
+        (byte)0xF5, (byte)0x15, (byte)0xC8, (byte)0x9B,
+        (byte)0x5D, (byte)0x06, (byte)0x3D, (byte)0xE1,
+        (byte)0x52, (byte)0x2F, (byte)0x98, (byte)0xFF,
+        (byte)0x37, (byte)0xBB, (byte)0x75, (byte)0x48,
+        (byte)0x48, (byte)0xE9, (byte)0x65, (byte)0x84,
+        (byte)0x37, (byte)0xBB, (byte)0xB3, (byte)0xE9,
+        (byte)0x36, (byte)0x01, (byte)0xB4, (byte)0x6A,
+        (byte)0x1C, (byte)0xB2, (byte)0x11, (byte)0x82,
+        (byte)0xCE, (byte)0x3D, (byte)0x65, (byte)0xE5,
+        (byte)0x3C, (byte)0x89, (byte)0xE9, (byte)0x52,
+        (byte)0x19, (byte)0xBD, (byte)0x58, (byte)0xF6,
+        (byte)0xA2, (byte)0x03, (byte)0xA8, (byte)0xB2,
+        (byte)0xA5, (byte)0xDB, (byte)0xEB, (byte)0xF5,
+        (byte)0x94, (byte)0xF9, (byte)0x46, (byte)0xBE,
+        (byte)0x45, (byte)0x4C, (byte)0x65, (byte)0xD2,
+        (byte)0xD1, (byte)0xCF, (byte)0xFF, (byte)0xFF,
+        (byte)0xFA, (byte)0x38, (byte)0xF1, (byte)0x72,
+        (byte)0xAB, (byte)0xB9, (byte)0x14, (byte)0x4E,
+        (byte)0xF5, (byte)0xF0, (byte)0x7A, (byte)0x8E,
+        (byte)0x45, (byte)0xFD, (byte)0x5B, (byte)0xF9,
+        (byte)0xA2, (byte)0x97, (byte)0x1B, (byte)0xAE,
+        (byte)0x2C, (byte)0x7B, (byte)0x6B, (byte)0x7C,
+        (byte)0x98, (byte)0xFE, (byte)0x58, (byte)0xDD,
+        (byte)0xBE, (byte)0xF6, (byte)0x1C, (byte)0x8E,
+        (byte)0xD0, (byte)0xA1, (byte)0x72
+    };
+
+    private static final byte bobPrivKeyEnc[] = {
+        (byte)0x30, (byte)0x81, (byte)0xE4, (byte)0x02,
+        (byte)0x01, (byte)0x00, (byte)0x30, (byte)0x81,
+        (byte)0x99, (byte)0x06, (byte)0x09, (byte)0x2A,
+        (byte)0x86, (byte)0x48, (byte)0x86, (byte)0xF7,
+        (byte)0x0D, (byte)0x01, (byte)0x03, (byte)0x01,
+        (byte)0x30, (byte)0x81, (byte)0x8B, (byte)0x02,
+        (byte)0x81, (byte)0x81, (byte)0x00, (byte)0xF4,
+        (byte)0x88, (byte)0xFD, (byte)0x58, (byte)0x4E,
+        (byte)0x49, (byte)0xDB, (byte)0xCD, (byte)0x20,
+        (byte)0xB4, (byte)0x9D, (byte)0xE4, (byte)0x91,
+        (byte)0x07, (byte)0x36, (byte)0x6B, (byte)0x33,
+        (byte)0x6C, (byte)0x38, (byte)0x0D, (byte)0x45,
+        (byte)0x1D, (byte)0x0F, (byte)0x7C, (byte)0x88,
+        (byte)0xB3, (byte)0x1C, (byte)0x7C, (byte)0x5B,
+        (byte)0x2D, (byte)0x8E, (byte)0xF6, (byte)0xF3,
+        (byte)0xC9, (byte)0x23, (byte)0xC0, (byte)0x43,
+        (byte)0xF0, (byte)0xA5, (byte)0x5B, (byte)0x18,
+        (byte)0x8D, (byte)0x8E, (byte)0xBB, (byte)0x55,
+        (byte)0x8C, (byte)0xB8, (byte)0x5D, (byte)0x38,
+        (byte)0xD3, (byte)0x34, (byte)0xFD, (byte)0x7C,
+        (byte)0x17, (byte)0x57, (byte)0x43, (byte)0xA3,
+        (byte)0x1D, (byte)0x18, (byte)0x6C, (byte)0xDE,
+        (byte)0x33, (byte)0x21, (byte)0x2C, (byte)0xB5,
+        (byte)0x2A, (byte)0xFF, (byte)0x3C, (byte)0xE1,
+        (byte)0xB1, (byte)0x29, (byte)0x40, (byte)0x18,
+        (byte)0x11, (byte)0x8D, (byte)0x7C, (byte)0x84,
+        (byte)0xA7, (byte)0x0A, (byte)0x72, (byte)0xD6,
+        (byte)0x86, (byte)0xC4, (byte)0x03, (byte)0x19,
+        (byte)0xC8, (byte)0x07, (byte)0x29, (byte)0x7A,
+        (byte)0xCA, (byte)0x95, (byte)0x0C, (byte)0xD9,
+        (byte)0x96, (byte)0x9F, (byte)0xAB, (byte)0xD0,
+        (byte)0x0A, (byte)0x50, (byte)0x9B, (byte)0x02,
+        (byte)0x46, (byte)0xD3, (byte)0x08, (byte)0x3D,
+        (byte)0x66, (byte)0xA4, (byte)0x5D, (byte)0x41,
+        (byte)0x9F, (byte)0x9C, (byte)0x7C, (byte)0xBD,
+        (byte)0x89, (byte)0x4B, (byte)0x22, (byte)0x19,
+        (byte)0x26, (byte)0xBA, (byte)0xAB, (byte)0xA2,
+        (byte)0x5E, (byte)0xC3, (byte)0x55, (byte)0xE9,
+        (byte)0x2F, (byte)0x78, (byte)0xC7, (byte)0x02,
+        (byte)0x01, (byte)0x02, (byte)0x02, (byte)0x02,
+        (byte)0x02, (byte)0x00, (byte)0x04, (byte)0x43,
+        (byte)0x02, (byte)0x41, (byte)0x00, (byte)0xE0,
+        (byte)0x31, (byte)0xE7, (byte)0x77, (byte)0xB8,
+        (byte)0xD0, (byte)0x7E, (byte)0x0A, (byte)0x9B,
+        (byte)0x94, (byte)0xD5, (byte)0x3D, (byte)0x33,
+        (byte)0x62, (byte)0x32, (byte)0x51, (byte)0xCE,
+        (byte)0x74, (byte)0x5C, (byte)0xA5, (byte)0x72,
+        (byte)0xD9, (byte)0x36, (byte)0xF3, (byte)0x8A,
+        (byte)0x3F, (byte)0x8B, (byte)0xC6, (byte)0xFE,
+        (byte)0xEF, (byte)0x94, (byte)0x8B, (byte)0x50,
+        (byte)0x41, (byte)0x9B, (byte)0x14, (byte)0xC8,
+        (byte)0xE9, (byte)0x1F, (byte)0x24, (byte)0x1F,
+        (byte)0x65, (byte)0x8E, (byte)0xD3, (byte)0x85,
+        (byte)0xD0, (byte)0x68, (byte)0x6C, (byte)0xF1,
+        (byte)0x79, (byte)0x45, (byte)0xD0, (byte)0x06,
+        (byte)0xA4, (byte)0xB8, (byte)0xE0, (byte)0x64,
+        (byte)0xF5, (byte)0x38, (byte)0x72, (byte)0x97,
+        (byte)0x00, (byte)0x23, (byte)0x5F
+    };
+}
+
--- a/jdk/test/com/sun/jmx/remote/NotificationMarshalVersions/Client/Client.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/com/sun/jmx/remote/NotificationMarshalVersions/Client/Client.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,47 +1,78 @@
 
-import java.nio.charset.Charset;
-import java.nio.file.FileSystems;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.StandardWatchEventKinds;
-import java.nio.file.WatchEvent;
-import java.nio.file.WatchService;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
 import javax.management.MBeanServerConnection;
 import javax.management.Notification;
 import javax.management.NotificationListener;
 import javax.management.ObjectName;
+import javax.management.remote.JMXConnectionNotification;
 import javax.management.remote.JMXConnector;
 import javax.management.remote.JMXConnectorFactory;
 import javax.management.remote.JMXServiceURL;
 
 public class Client {
-    public static void main(String[] argv) throws Exception {
-        if (argv.length != 1) throw new IllegalArgumentException("Expecting exactly one jmx url argument");
+    public static void run(String url) throws Exception {
+        final int notifEmittedCnt = 10;
+        final CountDownLatch counter = new CountDownLatch(notifEmittedCnt);
+        final Set<Long> seqSet = Collections.synchronizedSet(new HashSet<Long>());
+        final AtomicBoolean duplNotification = new AtomicBoolean();
 
-        JMXServiceURL serverUrl = new JMXServiceURL(argv[0]);
+        JMXServiceURL serverUrl = new JMXServiceURL(url);
 
         ObjectName name = new ObjectName("test", "foo", "bar");
         JMXConnector jmxConnector = JMXConnectorFactory.connect(serverUrl);
         System.out.println("client connected");
         jmxConnector.addConnectionNotificationListener(new NotificationListener() {
+            @Override
             public void handleNotification(Notification notification, Object handback) {
-                System.err.println("no!" + notification);
+                System.out.println("connection notification: " + notification);
+                if (!seqSet.add(notification.getSequenceNumber())) {
+                    duplNotification.set(true);
+                }
+                if (notification.getType().equals(JMXConnectionNotification.NOTIFS_LOST)) {
+                    long lostNotifs = ((Long)((JMXConnectionNotification)notification).getUserData()).longValue();
+                    for(int i=0;i<lostNotifs;i++) {
+                        counter.countDown();
+                    }
+                }
             }
         }, null, null);
         MBeanServerConnection jmxServer = jmxConnector.getMBeanServerConnection();
 
         jmxServer.addNotificationListener(name, new NotificationListener() {
+            @Override
             public void handleNotification(Notification notification, Object handback) {
-                System.out.println("client got:" + notification);
+                System.out.println("client got: " + notification);
+                if (!seqSet.add(notification.getSequenceNumber())) {
+                    duplNotification.set(true);
+                }
+                counter.countDown();
             }
         }, null, null);
 
-        for(int i=0;i<10;i++) {
-            System.out.println("client invoking foo");
+        System.out.println("client invoking foo (" + notifEmittedCnt + " times)");
+        for(int i=0;i<notifEmittedCnt;i++) {
+            System.out.print(".");
             jmxServer.invoke(name, "foo", new Object[]{}, new String[]{});
-            Thread.sleep(50);
         }
-
-        System.err.println("happy!");
+        System.out.println();
+        try {
+            System.out.println("waiting for " + notifEmittedCnt + " notifications to arrive");
+            if (!counter.await(30, TimeUnit.SECONDS)) {
+                throw new InterruptedException();
+            }
+            if (duplNotification.get()) {
+                System.out.println("ERROR: received duplicated notifications");
+                throw new Error("received duplicated notifications");
+            }
+            System.out.println("\nshutting down client");
+        } catch (InterruptedException e) {
+            System.out.println("ERROR: notification processing thread interrupted");
+            throw new Error("notification thread interrupted unexpectedly");
+        }
     }
 }
--- a/jdk/test/com/sun/jmx/remote/NotificationMarshalVersions/Server/Server.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/com/sun/jmx/remote/NotificationMarshalVersions/Server/Server.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,11 +1,6 @@
+import java.io.File;
 import java.lang.management.ManagementFactory;
 import java.net.BindException;
-import java.nio.charset.Charset;
-import java.nio.file.FileSystem;
-import java.nio.file.FileSystems;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.StandardOpenOption;
 import java.rmi.registry.LocateRegistry;
 import java.rmi.server.ExportException;
 import java.util.Random;
@@ -16,7 +11,7 @@
 import javax.management.remote.JMXServiceURL;
 
 public class Server {
-    public static void main(String[] argv) throws Exception {
+    public static String start() throws Exception {
         int serverPort = 12345;
         ObjectName name = new ObjectName("test", "foo", "bar");
         MBeanServer jmxServer = ManagementFactory.getPlatformMBeanServer();
@@ -40,7 +35,7 @@
         JMXServiceURL serverUrl = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:" + serverPort + "/test");
         JMXConnectorServer jmxConnector = JMXConnectorServerFactory.newJMXConnectorServer(serverUrl, null, jmxServer);
         jmxConnector.start();
-        System.out.println(serverUrl);
-        System.err.println("server listening on " + serverUrl);
+
+        return serverUrl.toString();
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/jmx/remote/NotificationMarshalVersions/TestSerializationMismatch.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,123 @@
+
+import java.io.File;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Arrays;
+
+/**
+ * @test
+ * @summary Tests for the RMI unmarshalling errors not to cause silent failure.
+ * @author Jaroslav Bachorik
+ * @bug 6937053 8005472
+ *
+ * @run clean TestSerializationMismatch
+ * @run main/othervm TestSerializationMismatch
+ *
+ */
+public class TestSerializationMismatch {
+    static final String clientDir = "Client";
+    static final String serverDir = "Server";
+    static final String testSrc = System.getProperty("test.src");
+    static final String testSrcDir = testSrc != null ? testSrc : ".";
+    static final String testSrcClientDir = testSrcDir + File.separator + clientDir + File.separator;
+    static final String testSrcServerDir = testSrcDir + File.separator + serverDir + File.separator;
+    static final String testClasses = System.getProperty("test.classes");
+    static final String testClassesDir = testClasses != null ? testClasses : ".";
+    static final String testClassesClientDir = testClassesDir + File.separator + clientDir + File.separator;
+    static final String testClassesServerDir = testClassesDir + File.separator + serverDir + File.separator;
+
+    static final boolean debug = true;
+
+    public static void main(String[] args) throws Exception {
+        setup();
+
+        compileClient();
+        compileServer();
+
+        debug("starting server");
+        String url = startServer();
+        debug("server started and listening on " + url);
+        debug("starting client");
+        startClient(url);
+    }
+
+    static void setup() {
+        debug("setting up the output dirs");
+        cleanupDir(testClassesClientDir);
+        cleanupDir(testClassesServerDir);
+    }
+
+    static void cleanupDir(String path) {
+        debug("cleaning " + path);
+        File dir = new File(path);
+        if (dir.exists()) {
+            for(File src : dir.listFiles()) {
+                boolean rslt = src.delete();
+                debug((rslt == false ? "not " : "") + "deleted " + src);
+            }
+        } else {
+            dir.mkdirs();
+        }
+    }
+
+    static void compileClient() {
+        debug("compiling client");
+        compile("-d" , testClassesClientDir,
+            "-sourcepath", testSrcClientDir,
+            testSrcClientDir + "Client.java",
+            testSrcClientDir + "ConfigKey.java",
+            testSrcClientDir + "TestNotification.java");
+    }
+
+    static void compileServer() {
+        debug("compiling server");
+        compile("-d" , testClassesServerDir,
+            "-sourcepath", testSrcServerDir,
+            testSrcServerDir + "Server.java",
+            testSrcServerDir + "ConfigKey.java",
+            testSrcServerDir + "TestNotification.java",
+            testSrcServerDir + "Ste.java",
+            testSrcServerDir + "SteMBean.java");
+    }
+
+    static String startServer() throws Exception {
+        ClassLoader serverCL = customCL(testClassesServerDir);
+
+        Class serverClz = serverCL.loadClass("Server");
+        Method startMethod = serverClz.getMethod("start");
+        return (String)startMethod.invoke(null);
+    }
+
+    static void startClient(String url) throws Exception {
+        ClassLoader clientCL = customCL(testClassesClientDir);
+
+        Thread.currentThread().setContextClassLoader(clientCL);
+        Class clientClz = clientCL.loadClass("Client");
+        Method runMethod = clientClz.getMethod("run", String.class);
+        runMethod.invoke(null, url);
+    }
+
+    static ClassLoader customCL(String classDir) throws Exception {
+        return new URLClassLoader(
+            new URL[]{
+                new File(classDir).toURI().toURL()
+            },
+            TestSerializationMismatch.class.getClassLoader()
+        );
+    }
+
+    static void debug(Object message) {
+        if (debug) {
+            System.out.println(message);
+        }
+    }
+
+    /* run javac <args> */
+    static void compile(String... args) {
+        debug("Running: javac " + Arrays.toString(args));
+        if (com.sun.tools.javac.Main.compile(args) != 0) {
+            throw new RuntimeException("javac failed: args=" + Arrays.toString(args));
+        }
+    }
+}
--- a/jdk/test/com/sun/jmx/remote/NotificationMarshalVersions/TestSerializationMismatch.sh	Fri May 31 10:34:25 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-#
-# Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-# 
-# @test
-# @summary  Tests for the RMI unmarshalling errors not to cause silent failure.
-# @author   Jaroslav Bachorik
-# @bug      6937053
-#
-# @run shell TestSerializationMismatch.sh
-#
-
-#set -x
-
-#Set appropriate jdk
-#
-
-if [ ! -z "${TESTJAVA}" ] ; then
-     jdk="$TESTJAVA"
-else
-     echo "--Error: TESTJAVA must be defined as the pathname of a jdk to test."
-     exit 1
-fi
-
-SERVER_TESTCLASSES=$TESTCLASSES/Server
-CLIENT_TESTCLASSES=$TESTCLASSES/Client
-
-URL_PATH=$SERVER_TESTCLASSES/jmxurl
-
-rm $URL_PATH
-
-mkdir -p $SERVER_TESTCLASSES
-mkdir -p $CLIENT_TESTCLASSES
-
-$TESTJAVA/bin/javac -d $CLIENT_TESTCLASSES $TESTSRC/Client/ConfigKey.java $TESTSRC/Client/TestNotification.java $TESTSRC/Client/Client.java
-$TESTJAVA/bin/javac -d $SERVER_TESTCLASSES $TESTSRC/Server/ConfigKey.java $TESTSRC/Server/TestNotification.java $TESTSRC/Server/SteMBean.java $TESTSRC/Server/Ste.java $TESTSRC/Server/Server.java
-
-startServer()
-{
-   ($TESTJAVA/bin/java -classpath $SERVER_TESTCLASSES Server) 1>$URL_PATH &
-   SERVER_PID=$!
-}
-
-runClient() 
-{
-   while true
-   do
-      [ -f $URL_PATH ] && break
-      sleep 2
-   done
-   read JMXURL < $URL_PATH
-   
-   HAS_ERRORS=`($TESTJAVA/bin/java -classpath $CLIENT_TESTCLASSES Client $JMXURL) 2>&1 | grep -i "SEVERE: Failed to fetch notification, stopping thread. Error is: java.rmi.UnmarshalException"`
-}
-
-startServer
-
-runClient
-
-sleep 1 # wait for notifications to arrive
-
-kill "$SERVER_PID"
-
-if [ -z "$HAS_ERRORS" ]
-then
-  echo "Test PASSED"
-  exit 0
-fi
-
-echo "Test FAILED"
-echo $HAS_ERRORS 1>&2
-exit 1
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/management/DiagnosticCommandMBean/DcmdMBeanDoubleInvocationTest.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug     7150256
+ * @summary Basic Test for the DiagnosticCommandMBean
+ * @author  Frederic Parain
+ *
+ * @run main/othervm -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.port=8125 DcmdMBeanDoubleInvocationTest
+ */
+
+
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.management.Descriptor;
+import javax.management.InstanceNotFoundException;
+import javax.management.IntrospectionException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+import javax.management.*;
+import javax.management.remote.*;
+
+public class DcmdMBeanDoubleInvocationTest {
+
+    private static String HOTSPOT_DIAGNOSTIC_MXBEAN_NAME =
+        "com.sun.management:type=DiagnosticCommand";
+
+    public static void main(String[] args) {
+        MBeanServerConnection mbs = null;
+        try {
+            JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:8125/jmxrmi");
+            JMXConnector connector = JMXConnectorFactory.connect(url);
+            mbs = connector.getMBeanServerConnection();
+        } catch(Throwable t) {
+            t.printStackTrace();
+        }
+        ObjectName name;
+        try {
+            name = new ObjectName(HOTSPOT_DIAGNOSTIC_MXBEAN_NAME);
+            MBeanInfo info = mbs.getMBeanInfo(name);
+            String[] helpArgs = {"-all", "\n", "VM.version"};
+            Object[] dcmdArgs = {helpArgs};
+            String[] signature = {String[].class.getName()};
+            String result = (String) mbs.invoke(name, "help", dcmdArgs, signature);
+            System.out.println(result);
+         } catch (RuntimeMBeanException ex) {
+            if (ex.getCause() instanceof IllegalArgumentException) {
+                System.out.println("Test passed");
+                return;
+            } else {
+                ex.printStackTrace();
+                throw new RuntimeException("TEST FAILED");
+            }
+        } catch (InstanceNotFoundException | IntrospectionException
+                | ReflectionException | MalformedObjectNameException
+                | MBeanException|IOException ex) {
+            ex.printStackTrace();
+            throw new RuntimeException("TEST FAILED");
+        }
+        System.out.println("Double commands have not been detected");
+        throw new RuntimeException("TEST FAILED");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/management/DiagnosticCommandMBean/DcmdMBeanInvocationTest.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug     7150256
+ * @summary Basic Test for the DiagnosticCommandMBean
+ * @author  Frederic Parain
+ *
+ * @run main/othervm -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.port=8129 DcmdMBeanInvocationTest
+ */
+
+
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.management.Descriptor;
+import javax.management.InstanceNotFoundException;
+import javax.management.IntrospectionException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+import javax.management.*;
+import javax.management.remote.*;
+
+public class DcmdMBeanInvocationTest {
+
+    private static String HOTSPOT_DIAGNOSTIC_MXBEAN_NAME =
+        "com.sun.management:type=DiagnosticCommand";
+
+    public static void main(String[] args) {
+        MBeanServerConnection mbs = null;
+        try {
+            JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:8129/jmxrmi");
+            JMXConnector connector = JMXConnectorFactory.connect(url);
+            mbs = connector.getMBeanServerConnection();
+        } catch(Throwable t) {
+            t.printStackTrace();
+        }
+        ObjectName name;
+        try {
+            name = new ObjectName(HOTSPOT_DIAGNOSTIC_MXBEAN_NAME);
+            MBeanInfo info = mbs.getMBeanInfo(name);
+            String[] helpArgs = {"-all"};
+            Object[] dcmdArgs = {helpArgs};
+            String[] signature = {String[].class.getName()};
+            String result = (String) mbs.invoke(name, "help", dcmdArgs, signature);
+            System.out.println(result);
+        } catch (InstanceNotFoundException | IntrospectionException
+                | ReflectionException | MalformedObjectNameException
+                | MBeanException|IOException ex) {
+            ex.printStackTrace();
+            throw new RuntimeException("TEST FAILED");
+        }
+        System.out.println("Test passed");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/management/DiagnosticCommandMBean/DcmdMBeanPermissionsTest.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,242 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug     7150256
+ * @summary Permissions Tests for the DiagnosticCommandMBean
+ * @author  Frederic Parain
+ *
+ * @run main/othervm DcmdMBeanPermissionsTest
+ */
+
+import java.lang.management.ManagementFactory;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.ReflectPermission;
+import java.security.Permission;
+import java.util.HashSet;
+import java.util.Iterator;
+import javax.management.Descriptor;
+import javax.management.InstanceNotFoundException;
+import javax.management.IntrospectionException;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanPermission;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+import javax.management.RuntimeMBeanException;
+
+/**
+ *
+ * @author fparain
+ */
+public class DcmdMBeanPermissionsTest {
+
+    private static String HOTSPOT_DIAGNOSTIC_MXBEAN_NAME =
+        "com.sun.management:type=DiagnosticCommand";
+
+    static public class CustomSecurityManager extends SecurityManager {
+
+        private HashSet<Permission> grantedPermissions;
+
+        public CustomSecurityManager() {
+            grantedPermissions = new HashSet<Permission>();
+        }
+
+        public final void grantPermission(final Permission perm) {
+            grantedPermissions.add(perm);
+        }
+
+        public final void denyPermission(final Permission perm) {
+            Iterator<Permission> it = grantedPermissions.iterator();
+            while (it.hasNext()) {
+                Permission p = it.next();
+                if (p.equals(perm)) {
+                    it.remove();
+                }
+            }
+        }
+
+        public final void checkPermission(final Permission perm) {
+            for (Permission p : grantedPermissions) {
+                if (p.implies(perm)) {
+                    return;
+                }
+            }
+            throw new SecurityException(perm.toString());
+        }
+    };
+
+    static Permission createPermission(String classname, String name,
+            String action) {
+        Permission permission = null;
+        try {
+            Class c = Class.forName(classname);
+            if (action == null) {
+                try {
+                    Constructor constructor = c.getConstructor(String.class);
+                    permission = (Permission) constructor.newInstance(name);
+
+                } catch (InstantiationException | IllegalAccessException
+                        | IllegalArgumentException | InvocationTargetException
+                        | NoSuchMethodException | SecurityException ex) {
+                    ex.printStackTrace();
+                    throw new RuntimeException("TEST FAILED");
+                }
+            }
+            if (permission == null) {
+                try {
+                    Constructor constructor = c.getConstructor(String.class,
+                            String.class);
+                    permission = (Permission) constructor.newInstance(
+                            name,
+                            action);
+                } catch (InstantiationException | IllegalAccessException
+                        | IllegalArgumentException | InvocationTargetException
+                        | NoSuchMethodException | SecurityException ex) {
+                    ex.printStackTrace();
+                    throw new RuntimeException("TEST FAILED");
+                }
+            }
+        } catch (ClassNotFoundException ex) {
+            ex.printStackTrace();
+                    throw new RuntimeException("TEST FAILED");
+        }
+        if (permission == null) {
+            throw new RuntimeException("TEST FAILED");
+        }
+        return permission;
+    }
+
+    // return true if invokation triggered a SecurityException
+    static boolean invokeOperation(MBeanServer mbs, ObjectName on,
+            MBeanOperationInfo opInfo) {
+        try {
+            if (opInfo.getSignature().length == 0) {
+                mbs.invoke(on, opInfo.getName(),
+                        new Object[0], new String[0]);
+            } else {
+                mbs.invoke(on, opInfo.getName(),
+                        new Object[1], new String[]{ String[].class.getName()});
+            }
+        } catch (SecurityException ex) {
+            ex.printStackTrace();
+            return true;
+        } catch (RuntimeMBeanException ex) {
+            if (ex.getCause() instanceof SecurityException) {
+                //ex.printStackTrace();
+                return true;
+            }
+        } catch (MBeanException | InstanceNotFoundException
+                | ReflectionException ex) {
+            throw new RuntimeException("TEST FAILED");
+        }
+        return false;
+    }
+
+    static void testOperation(MBeanServer mbs, CustomSecurityManager sm,
+            ObjectName on, MBeanOperationInfo opInfo) {
+        System.out.println("Testing " + opInfo.getName());
+        Descriptor desc = opInfo.getDescriptor();
+        if (desc.getFieldValue("dcmd.permissionClass") == null) {
+        // No special permission required, execution should not trigger
+        // any security exception
+            if (invokeOperation(mbs, on, opInfo)) {
+                throw new RuntimeException("TEST FAILED");
+            }
+        } else {
+            // Building the required permission
+            Permission reqPerm = createPermission(
+                    (String)desc.getFieldValue("dcmd.permissionClass"),
+                    (String)desc.getFieldValue("dcmd.permissionName"),
+                    (String)desc.getFieldValue("dcmd.permissionAction"));
+            // Paranoid mode: check that the SecurityManager has not already
+            // been granted the permission
+            sm.denyPermission(reqPerm);
+            // A special permission is required for this operation,
+            // invoking it without the permission granted must trigger
+            // a security exception
+            if(!invokeOperation(mbs, on, opInfo)) {
+                throw new RuntimeException("TEST FAILED");
+            }
+            // grant the permission and re-try invoking the operation
+            sm.grantPermission(reqPerm);
+            if(invokeOperation(mbs, on, opInfo)) {
+                throw new RuntimeException("TEST FAILED");
+            }
+            // Clean up
+            sm.denyPermission(reqPerm);
+        }
+    }
+
+    public static void main(final String[] args) {
+        final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+        ObjectName on = null;
+        try {
+            on = new ObjectName(HOTSPOT_DIAGNOSTIC_MXBEAN_NAME);
+        } catch (MalformedObjectNameException ex) {
+            ex.printStackTrace();
+            throw new RuntimeException("TEST FAILED");
+        }
+        MBeanInfo info = null;
+        try {
+            info = mbs.getMBeanInfo(on);
+        } catch (InstanceNotFoundException | IntrospectionException
+                | ReflectionException ex) {
+            ex.printStackTrace();
+            throw new RuntimeException("TEST FAILED");
+        }
+        CustomSecurityManager sm = new CustomSecurityManager();
+        System.setSecurityManager(sm);
+        // Set of permission required to run the test cleanly
+        // Some permissions are required by the MBeanServer and other
+        // platform services (RuntimePermission("createClassLoader"),
+        // ReflectPermission("suppressAccessChecks"),
+        // java.util.logging.LoggingPermission("control"),
+        // RuntimePermission("exitVM.97")).
+        // Other permissions are required by commands being invoked
+        // in the test (for instance, RuntimePermission("modifyThreadGroup")
+        // and RuntimePermission("modifyThread") are checked when
+        // runFinalization() is invoked by the gcRunFinalization command.
+        sm.grantPermission(new RuntimePermission("createClassLoader"));
+        sm.grantPermission(new ReflectPermission("suppressAccessChecks"));
+        sm.grantPermission(new java.util.logging.LoggingPermission("control", ""));
+        sm.grantPermission(new java.lang.RuntimePermission("exitVM.97"));
+        sm.grantPermission(new java.lang.RuntimePermission("modifyThreadGroup"));
+        sm.grantPermission(new java.lang.RuntimePermission("modifyThread"));
+        for(MBeanOperationInfo opInfo : info.getOperations()) {
+            Permission opPermission = new MBeanPermission(info.getClassName(),
+                    opInfo.getName(),
+                    on,
+                    "invoke");
+            sm.grantPermission(opPermission);
+            testOperation(mbs, sm, on, opInfo);
+            sm.denyPermission(opPermission);
+        }
+        System.out.println("TEST PASSED");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/management/DiagnosticCommandMBean/DcmdMBeanTest.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug     7150256
+ * @summary Basic Test for the DiagnosticCommandMBean
+ * @author  Frederic Parain
+ *
+ * @run main/othervm -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.port=8127 DcmdMBeanTest
+ */
+
+
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.management.Descriptor;
+import javax.management.InstanceNotFoundException;
+import javax.management.IntrospectionException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+import javax.management.*;
+import javax.management.remote.*;
+
+public class DcmdMBeanTest {
+
+    private static String HOTSPOT_DIAGNOSTIC_MXBEAN_NAME =
+        "com.sun.management:type=DiagnosticCommand";
+
+    public static void main(String[] args) {
+        MBeanServerConnection mbs = null;
+        try {
+            JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:8127/jmxrmi");
+            JMXConnector connector = JMXConnectorFactory.connect(url);
+            mbs = connector.getMBeanServerConnection();
+        } catch(Throwable t) {
+            t.printStackTrace();
+        }
+        ObjectName name;
+        try {
+            name = new ObjectName(HOTSPOT_DIAGNOSTIC_MXBEAN_NAME);
+            MBeanInfo info = mbs.getMBeanInfo(name);
+            // the test should check that the MBean doesn't have any
+            // Attribute, notification or constructor. Current version only
+            // check operations
+            System.out.println("Class Name:"+info.getClassName());
+            System.out.println("Description:"+info.getDescription());
+            MBeanOperationInfo[] opInfo = info.getOperations();
+            System.out.println("Operations:");
+            for(int i=0; i<opInfo.length; i++) {
+                printOperation(opInfo[i]);
+                System.out.println("\n@@@@@@\n");
+            }
+        } catch (InstanceNotFoundException|IntrospectionException|ReflectionException
+                 |MalformedObjectNameException|IOException ex) {
+            Logger.getLogger(DcmdMBeanTest.class.getName()).log(Level.SEVERE, null, ex);
+        }
+    }
+
+    static void printOperation(MBeanOperationInfo info) {
+        System.out.println("Name: "+info.getName());
+        System.out.println("Description: "+info.getDescription());
+        System.out.println("Return Type: "+info.getReturnType());
+        System.out.println("Impact: "+info.getImpact());
+        Descriptor desc = info.getDescriptor();
+        System.out.println("Descriptor");
+        for(int i=0; i<desc.getFieldNames().length; i++) {
+            if(desc.getFieldNames()[i].compareTo("dcmd.arguments") == 0) {
+                System.out.println("\t"+desc.getFieldNames()[i]+":");
+                Descriptor desc2 =
+                        (Descriptor)desc.getFieldValue(desc.getFieldNames()[i]);
+                for(int j=0; j<desc2.getFieldNames().length; j++) {
+                    System.out.println("\t\t"+desc2.getFieldNames()[j]+"=");
+                    Descriptor desc3 =
+                            (Descriptor)desc2.getFieldValue(desc2.getFieldNames()[j]);
+                    for(int k=0; k<desc3.getFieldNames().length; k++) {
+                        System.out.println("\t\t\t"+desc3.getFieldNames()[k]+"="
+                                           +desc3.getFieldValue(desc3.getFieldNames()[k]));
+                    }
+                }
+            } else {
+                System.out.println("\t"+desc.getFieldNames()[i]+"="
+                        +desc.getFieldValue(desc.getFieldNames()[i]));
+            }
+        }
+    }
+}
+
--- a/jdk/test/demo/zipfs/ZipFSTester.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/demo/zipfs/ZipFSTester.java	Mon Jun 10 10:38:33 2013 +0100
@@ -29,6 +29,7 @@
 import java.nio.file.attribute.*;
 import java.net.*;
 import java.util.*;
+import java.util.concurrent.TimeUnit;
 import java.util.zip.*;
 
 import static java.nio.file.StandardOpenOption.*;
@@ -48,6 +49,7 @@
             test0(fs);
             test1(fs);
             test2(fs);   // more tests
+            testTime(Paths.get(args[0]));
         }
     }
 
@@ -337,6 +339,45 @@
         Files.delete(fs3Path);
     }
 
+    // test file stamp
+    static void testTime(Path src) throws Exception {
+        BasicFileAttributes attrs = Files
+                        .getFileAttributeView(src, BasicFileAttributeView.class)
+                        .readAttributes();
+        // create a new filesystem, copy this file into it
+        Map<String, Object> env = new HashMap<String, Object>();
+        env.put("create", "true");
+        Path fsPath = getTempPath();
+        FileSystem fs = newZipFileSystem(fsPath, env);
+
+        System.out.println("test copy with timestamps...");
+        // copyin
+        Path dst = getPathWithParents(fs, "me");
+        Files.copy(src, dst, COPY_ATTRIBUTES);
+        checkEqual(src, dst);
+        System.out.println("mtime: " + attrs.lastModifiedTime());
+        System.out.println("ctime: " + attrs.creationTime());
+        System.out.println("atime: " + attrs.lastAccessTime());
+        System.out.println(" ==============>");
+        BasicFileAttributes dstAttrs = Files
+                        .getFileAttributeView(dst, BasicFileAttributeView.class)
+                        .readAttributes();
+        System.out.println("mtime: " + dstAttrs.lastModifiedTime());
+        System.out.println("ctime: " + dstAttrs.creationTime());
+        System.out.println("atime: " + dstAttrs.lastAccessTime());
+
+        // 1-second granularity
+        if (attrs.lastModifiedTime().to(TimeUnit.SECONDS) !=
+            dstAttrs.lastModifiedTime().to(TimeUnit.SECONDS) ||
+            attrs.lastAccessTime().to(TimeUnit.SECONDS) !=
+            dstAttrs.lastAccessTime().to(TimeUnit.SECONDS) ||
+            attrs.creationTime().to(TimeUnit.SECONDS) !=
+            dstAttrs.creationTime().to(TimeUnit.SECONDS)) {
+            throw new RuntimeException("Timestamp Copy Failed!");
+        }
+        Files.delete(fsPath);
+    }
+
     private static FileSystem newZipFileSystem(Path path, Map<String, ?> env)
         throws Exception
     {
--- a/jdk/test/demo/zipfs/basic.sh	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/demo/zipfs/basic.sh	Mon Jun 10 10:38:33 2013 +0100
@@ -22,7 +22,7 @@
 #
 # @test
 # @bug 6990846 7009092 7009085 7015391 7014948 7005986 7017840 7007596
-# 7157656 8002390
+# 7157656 8002390 7012868 7012856 8015728
 # @summary Test ZipFileSystem demo
 # @build Basic PathOps ZipFSTester
 # @run shell basic.sh
--- a/jdk/test/java/awt/WMSpecificTests/Metacity/FullscreenDialogModality.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/awt/WMSpecificTests/Metacity/FullscreenDialogModality.java	Mon Jun 10 10:38:33 2013 +0100
@@ -25,6 +25,8 @@
  * @test
  * @bug 8012586
  * @summary verify that modal dialog will appeared above fullscreen window under Metacity WM.
+ * @library ../../regtesthelpers
+ * @build Util
  * @run main FullscreenDialogModality
  * @run main/othervm FullscreenDialogModality
  * @author vkravets
--- a/jdk/test/java/awt/Window/TranslucentJAppletTest/TranslucentJAppletTest.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/awt/Window/TranslucentJAppletTest/TranslucentJAppletTest.java	Mon Jun 10 10:38:33 2013 +0100
@@ -37,11 +37,12 @@
 
 public class TranslucentJAppletTest {
 
+    private static volatile GraphicsConfiguration graphicsConfig = null;
     private static JFrame frame;
     private static volatile boolean paintComponentCalled = false;
 
     private static void initAndShowGUI() {
-        frame = new JFrame();
+        frame = new JFrame(graphicsConfig);
         JApplet applet = new JApplet();
         applet.setBackground(new Color(0, 0, 0, 0));
         JPanel panel = new JPanel() {
@@ -66,6 +67,27 @@
     {
         sun.awt.SunToolkit tk = (sun.awt.SunToolkit)Toolkit.getDefaultToolkit();
 
+        final GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
+        for (GraphicsDevice gd : ge.getScreenDevices()) {
+            if (gd.isWindowTranslucencySupported(
+                        GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSLUCENT))
+            {
+                for (GraphicsConfiguration gc : gd.getConfigurations()) {
+                    if (gc.isTranslucencyCapable()) {
+                        graphicsConfig = gc;
+                        break;
+                    }
+                }
+            }
+            if (graphicsConfig != null) {
+                break;
+            }
+        }
+        if (graphicsConfig == null) {
+            System.out.println("The system does not support translucency. Consider the test passed.");
+            return;
+        }
+
         Robot r = new Robot();
         Color color1 = r.getPixelColor(100, 100); // (0, 0) in frame coordinates
 
--- a/jdk/test/java/awt/print/PrinterJob/Collate2DPrintingTest.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/awt/print/PrinterJob/Collate2DPrintingTest.java	Mon Jun 10 10:38:33 2013 +0100
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @bug 6362683
+ * @bug 6362683 8012381
  * @summary Collation should work.
  * @run main/manual Collate2DPrintingTest
  */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/print/PrinterJob/PrintLatinCJKTest.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+
+/**
+ * @test
+ * @bug 800535
+ * @summary JDK7 Printing: CJK and Latin Text in string overlap
+ * @run main/manual=yesno PrintLatinCJKTest
+ */
+
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.print.PageFormat;
+import java.awt.print.Pageable;
+import java.awt.print.Printable;
+import java.awt.print.PrinterException;
+import java.awt.print.PrinterJob;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JTextArea;
+
+import javax.swing.SwingUtilities;
+
+public class PrintLatinCJKTest implements Printable, ActionListener {
+
+    static PrintLatinCJKTest testInstance = new PrintLatinCJKTest();
+    private PageFormat pf;
+
+    static String info =
+       "You need a printer for this test. If you have none, let "+
+       "the test pass. If there is a printer, press Print, send "+
+       "the output to the printer, and examine it. It should have "+
+       "text looking like this : \u4e00\u4e01\u4e02\u4e03\u4e04English.";
+
+    public static void showFrame() {
+         JFrame f = new JFrame();
+         JTextArea jta = new JTextArea(info, 4, 30);
+         jta.setLineWrap(true);
+         jta.setWrapStyleWord(true);
+         f.add("Center", jta);
+         JButton b = new JButton("Print");
+         b.addActionListener(testInstance);
+         f.add("South", b);
+         f.pack();
+         f.setVisible(true);
+    }
+
+    public int print(Graphics g, PageFormat pf, int pageIndex)
+                         throws PrinterException {
+
+        if (pageIndex > 0) {
+            return Printable.NO_SUCH_PAGE;
+        }
+        g.translate((int) pf.getImageableX(), (int) pf.getImageableY());
+        g.setFont(new Font("Dialog", Font.PLAIN, 36));
+        g.drawString("\u4e00\u4e01\u4e02\u4e03\u4e04English", 20, 100);
+        return Printable.PAGE_EXISTS;
+    }
+
+    public void actionPerformed(ActionEvent e) {
+        try {
+            PrinterJob job = PrinterJob.getPrinterJob();
+            job.setPrintable(testInstance);
+            if (job.printDialog()) {
+                job.print();
+            }
+        } catch (PrinterException ex) {
+            ex.printStackTrace();
+        }
+    }
+
+    public static void main(String[] args) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                showFrame();
+            }
+        });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/beans/XMLEncoder/Test8013416.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8013416
+ * @summary Tests public synthetic methods
+ * @author Sergey Malenkov
+ */
+
+import java.beans.DefaultPersistenceDelegate;
+import java.beans.Encoder;
+import java.beans.Expression;
+import java.beans.Statement;
+import java.beans.XMLEncoder;
+import java.util.HashMap;
+import java.util.Map.Entry;
+import java.util.Set;
+
+public class Test8013416 extends AbstractTest {
+    public static void main(String[] args) {
+        new Test8013416().test(true);
+    }
+
+    protected Object getObject() {
+        Public<String, String> map = new Public<String, String>();
+        map.put(" pz1 ", " pz2 ");
+        map.put(" pz3 ", " pz4 ");
+        return map;
+    }
+
+    @Override
+    protected void initialize(XMLEncoder encoder) {
+        super.initialize(encoder);
+        encoder.setPersistenceDelegate(Public.class, new PublicPersistenceDelegate());
+    }
+
+    private static final class PublicPersistenceDelegate extends DefaultPersistenceDelegate {
+        @Override
+        protected Expression instantiate(Object oldInstance, Encoder out) {
+            return new Expression(oldInstance, oldInstance.getClass(), "new", null);
+        }
+
+        @Override
+        protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {
+            super.initialize(type, oldInstance, newInstance, out);
+
+            Public<String, String> map = (Public) oldInstance;
+            for (Entry<String, String> entry : map.getAll()) {
+                String[] args = {entry.getKey(), entry.getValue()};
+                out.writeStatement(new Statement(oldInstance, "put", args));
+            }
+        }
+    }
+
+    public static final class Public<K, V> extends Private<K, V> {
+    }
+
+    private static class Private<K, V> {
+        private HashMap<K, V> map = new HashMap<K, V>();
+
+        public void put(K key, V value) {
+            this.map.put(key, value);
+        }
+
+        public Set<Entry<K, V>> getAll() {
+            return this.map.entrySet();
+        }
+    }
+}
--- a/jdk/test/java/io/File/IsHidden.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/io/File/IsHidden.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -46,6 +46,11 @@
         Files.getFileAttributeView(f.toPath(), DosFileAttributeView.class).setHidden(value);
     }
 
+    private static void checkHidden(File f) {
+        if (!f.isHidden())
+            throw new RuntimeException(f + " should be hidden");
+    }
+
     private static void testWin32() throws Exception {
         File f = new File(dir, "test");
         f.deleteOnExit();
@@ -58,6 +63,11 @@
         }
         ck(".foo", false);
         ck("foo", false);
+
+        File pagefile = new File("C:\\pagefile.sys");
+        File hiberfil = new File("C:\\hiberfil.sys");
+        if (pagefile.exists()) checkHidden(pagefile);
+        if (hiberfil.exists()) checkHidden(hiberfil);
     }
 
     private static void testUnix() throws Exception {
--- a/jdk/test/java/io/FileInputStream/LargeFileAvailable.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/io/FileInputStream/LargeFileAvailable.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 6402006 7030573
+ * @bug 6402006 7030573 8011136
  * @summary Test if available returns correct value when reading
  *          a large file.
  */
@@ -61,9 +61,12 @@
             remaining -= skipBytes(fis, bigSkip, remaining);
             remaining -= skipBytes(fis, 10L, remaining);
             remaining -= skipBytes(fis, bigSkip, remaining);
-            if (fis.available() != (int) remaining) {
-                 throw new RuntimeException("available() returns "
-                     + fis.available() + " but expected " + remaining);
+            int expected = (remaining >= Integer.MAX_VALUE)
+                           ? Integer.MAX_VALUE
+                           : (remaining > 0 ? (int) remaining : 0);
+            if (fis.available() != expected) {
+                throw new RuntimeException("available() returns "
+                        + fis.available() + " but expected " + expected);
             }
         } finally {
             file.delete();
@@ -77,19 +80,18 @@
         long skip = is.skip(toSkip);
         if (skip != toSkip) {
             throw new RuntimeException("skip() returns " + skip
-                + " but expected " + toSkip);
+                                       + " but expected " + toSkip);
         }
         long remaining = avail - skip;
-        int expected = remaining >= Integer.MAX_VALUE
-                           ? Integer.MAX_VALUE
-                           : (int) remaining;
+        int expected = (remaining >= Integer.MAX_VALUE)
+                       ? Integer.MAX_VALUE
+                       : (remaining > 0 ? (int) remaining : 0);
 
-        System.out.println("Skipped " + skip + " bytes "
-            + " available() returns " + expected +
-            " remaining=" + remaining);
+        System.out.println("Skipped " + skip + " bytes, available() returns "
+                           + expected + ", remaining " + remaining);
         if (is.available() != expected) {
             throw new RuntimeException("available() returns "
-                + is.available() + " but expected " + expected);
+                    + is.available() + " but expected " + expected);
         }
         return skip;
     }
--- a/jdk/test/java/io/FileInputStream/NegativeAvailable.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/io/FileInputStream/NegativeAvailable.java	Mon Jun 10 10:38:33 2013 +0100
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8010837
+ * @bug 8010837 8011136
  * @summary Test if available returns correct value when skipping beyond
  *          the end of a file.
  * @author Dan Xu
@@ -42,6 +42,7 @@
     public static void main(String[] args) throws IOException {
         final int SIZE = 10;
         final int SKIP = 5;
+        final int NEGATIVE_SKIP = -5;
 
         // Create a temporary file with size of 10 bytes.
         Path tmp = Files.createTempFile(null, null);
@@ -56,12 +57,15 @@
         try (FileInputStream fis = new FileInputStream(tempFile)) {
             if (tempFile.length() != SIZE) {
                 throw new RuntimeException("unexpected file size = "
-                    + tempFile.length());
+                                           + tempFile.length());
             }
             long space = skipBytes(fis, SKIP, SIZE);
+            space = skipBytes(fis, NEGATIVE_SKIP, space);
             space = skipBytes(fis, SKIP, space);
             space = skipBytes(fis, SKIP, space);
             space = skipBytes(fis, SKIP, space);
+            space = skipBytes(fis, NEGATIVE_SKIP, space);
+            space = skipBytes(fis, NEGATIVE_SKIP, space);
         }
         Files.deleteIfExists(tmp);
     }
@@ -74,17 +78,18 @@
         long skip = fis.skip(toSkip);
         if (skip != toSkip) {
             throw new RuntimeException("skip() returns " + skip
-                + " but expected " + toSkip);
+                                       + " but expected " + toSkip);
         }
-        long remaining = space - toSkip;
+        long newSpace = space - toSkip;
+        long remaining = newSpace > 0 ? newSpace : 0;
         int avail = fis.available();
         if (avail != remaining) {
             throw new RuntimeException("available() returns " + avail
-                + " but expected " + remaining);
+                                       + " but expected " + remaining);
         }
 
         System.out.println("Skipped " + skip + " bytes "
-            + " available() returns " + avail);
-        return remaining;
+                           + " available() returns " + avail);
+        return newSpace;
     }
 }
--- a/jdk/test/java/io/pathNames/General.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/io/pathNames/General.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2000, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -40,7 +40,7 @@
 
 
     /* Generate a filename unique to this run */
-    private static String gensym() {
+    protected static String gensym() {
         return "x." + ++gensymCounter;
     }
 
@@ -127,9 +127,9 @@
         }
         for (int i = 0; i < dl.length; i++) {
             File f = new File(d, dl[i]);
-            if (f.isDirectory() && f.canRead()) {
+            if (f.isDirectory()) {
                 String[] dl2 = f.list();
-                if (dl2.length >= 250) {
+                if (dl2 == null || dl2.length >= 250) {
                     /* Heuristic to avoid scanning huge directories */
                     continue;
                 }
@@ -314,7 +314,7 @@
 
         /* Normal name */
         if (f.exists()) {
-            if (f.isDirectory() && f.canRead()) {
+            if (f.isDirectory() && f.list() != null) {
                 if ((n = findSomeFile(ans, create)) != null)
                     checkSlashes(d, create, ans + n, ask + n);
                 if ((n = findSomeDir(ans, create)) != null)
--- a/jdk/test/java/io/pathNames/GeneralWin32.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/io/pathNames/GeneralWin32.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,7 +22,7 @@
  */
 
 /* @test
-   @bug 4032066 4039597 4046914 4054511 4065189 4109131 4875229 6983520
+   @bug 4032066 4039597 4046914 4054511 4065189 4109131 4875229 6983520 8009258
    @summary General exhaustive test of win32 pathname handling
    @author Mark Reinhold
 
@@ -31,8 +31,6 @@
  */
 
 import java.io.*;
-import java.util.*;
-
 
 public class GeneralWin32 extends General {
 
@@ -49,25 +47,29 @@
     private static final String EXISTENT_UNC_SHARE = "pcdist";
     private static final String NONEXISTENT_UNC_HOST = "non-existent-unc-host";
     private static final String NONEXISTENT_UNC_SHARE = "bogus-share";
-
+    private static final int DEPTH = 2;
+    private static String baseDir = null;
+    private static String userDir = null;
+    private static String relative = null;
 
     /* Pathnames relative to working directory */
 
-    private static void checkCaseLookup(String ud) throws IOException {
+    private static void checkCaseLookup() throws IOException {
         /* Use long names here to avoid 8.3 format, which Samba servers often
            force to lowercase */
-        File d = new File("XyZzY0123", "FOO_bar_BAZ");
-        File f = new File(d, "GLORPified");
+        File d1 = new File(relative, "XyZzY0123");
+        File d2 = new File(d1, "FOO_bar_BAZ");
+        File f = new File(d2, "GLORPified");
         if (!f.exists()) {
-            if (!d.exists()) {
-                if (!d.mkdirs()) {
-                    throw new RuntimeException("Can't create directory " + d);
+            if (!d2.exists()) {
+                if (!d2.mkdirs()) {
+                    throw new RuntimeException("Can't create directory " + d2);
                 }
             }
             OutputStream o = new FileOutputStream(f);
             o.close();
         }
-        File f2 = new File(d.getParent(), "mumble"); /* For later ud tests */
+        File f2 = new File(d2.getParent(), "mumble"); /* For later ud tests */
         if (!f2.exists()) {
             OutputStream o = new FileOutputStream(f2);
             o.close();
@@ -75,11 +77,11 @@
 
         /* Computing the canonical path of a Win32 file should expose the true
            case of filenames, rather than just using the input case */
-        File y = new File(ud, f.getPath());
+        File y = new File(userDir, f.getPath());
         String ans = y.getPath();
-        check(ans, "XyZzY0123\\FOO_bar_BAZ\\GLORPified");
-        check(ans, "xyzzy0123\\foo_bar_baz\\glorpified");
-        check(ans, "XYZZY0123\\FOO_BAR_BAZ\\GLORPIFIED");
+        check(ans, relative + "XyZzY0123\\FOO_bar_BAZ\\GLORPified");
+        check(ans, relative + "xyzzy0123\\foo_bar_baz\\glorpified");
+        check(ans, relative + "XYZZY0123\\FOO_BAR_BAZ\\GLORPIFIED");
     }
 
     private static void checkWild(File f) throws Exception {
@@ -91,18 +93,17 @@
         throw new Exception("Wildcard path not rejected: " + f);
     }
 
-    private static void checkWildCards(String ud) throws Exception {
-        File d = new File(ud).getCanonicalFile();
+    private static void checkWildCards() throws Exception {
+        File d = new File(baseDir).getCanonicalFile();
         checkWild(new File(d, "*.*"));
         checkWild(new File(d, "*.???"));
         checkWild(new File(new File(d, "*.*"), "foo"));
     }
 
     private static void checkRelativePaths() throws Exception {
-        String ud = System.getProperty("user.dir").replace('/', '\\');
-        checkCaseLookup(ud);
-        checkWildCards(ud);
-        checkNames(3, true, ud + "\\", "");
+        checkCaseLookup();
+        checkWildCards();
+        checkNames(3, true, baseDir, relative);
     }
 
 
@@ -134,7 +135,7 @@
         String ans = exists ? df.getAbsolutePath() : d;
         if (!ans.endsWith("\\"))
             ans = ans + "\\";
-        checkNames(depth, false, ans, d);
+        checkNames(depth, false, ans + relative, d + relative);
     }
 
     private static void checkDrivePaths() throws Exception {
@@ -149,7 +150,7 @@
         String s = ("\\\\" + NONEXISTENT_UNC_HOST
                     + "\\" + NONEXISTENT_UNC_SHARE);
         ensureNon(s);
-        checkSlashes(2, false, s, s);
+        checkSlashes(DEPTH, false, s, s);
 
         s = "\\\\" + EXISTENT_UNC_HOST + "\\" + EXISTENT_UNC_SHARE;
         if (!(new File(s)).exists()) {
@@ -158,7 +159,7 @@
             return;
         }
 
-        checkSlashes(2, false, s, s);
+        checkSlashes(DEPTH, false, s, s);
     }
 
 
@@ -168,9 +169,34 @@
             return;
         }
         if (args.length > 0) debug = true;
+        userDir = System.getProperty("user.dir") + '\\';
+        baseDir = initTestData(6) + '\\';
+        relative = baseDir.substring(userDir.length());
         checkRelativePaths();
         checkDrivePaths();
         checkUncPaths();
     }
 
+    private static String initTestData(int maxDepth) throws IOException {
+        File parent = new File(userDir);
+        String baseDir = null;
+        maxDepth = maxDepth < DEPTH + 2 ? DEPTH + 2 : maxDepth;
+        for (int i = 0; i < maxDepth; i ++) {
+            File dir1 = new File(parent, gensym());
+            dir1.mkdir();
+            if (i != 0) {
+                File dir2 = new File(parent, gensym());
+                dir2.mkdir();
+                File f1 = new File(parent, gensym());
+                f1.createNewFile();
+                File f2 = new File(parent, gensym());
+                f2.createNewFile();
+            }
+            if (i == DEPTH + 1) {
+                baseDir = dir1.getAbsolutePath();
+            }
+            parent = dir1;
+        }
+        return baseDir;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/IntegralPrimitiveToString.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.LongFunction;
+import java.util.function.Function;
+
+import static org.testng.Assert.assertEquals;
+
+/**
+ * @test
+ * @run testng IntegralPrimitiveToString
+ * @summary test string conversions for primitive integral types.
+ * @author Mike Duigou
+ */
+public class IntegralPrimitiveToString {
+
+    @Test(dataProvider="numbers")
+    public <N extends Number> void testToString(String description,
+        Function<N, BigInteger> converter,
+        Function<N, BigInteger> unsignedConverter,
+        N[] values,
+        Stringifier<N>[] stringifiers) {
+        System.out.printf("%s : conversions: %d values: %d\n", description, stringifiers.length, values.length);
+        for( N value : values) {
+            BigInteger asBigInt = converter.apply(value);
+            BigInteger asUnsignedBigInt = unsignedConverter.apply(value);
+            for(Stringifier<N> stringifier : stringifiers) {
+                stringifier.assertMatchingToString(value, asBigInt, asUnsignedBigInt, description);
+            }
+        }
+    }
+
+    static class Stringifier<N extends Number> {
+        final boolean signed;
+        final int  radix;
+        final Function<N,String> toString;
+        Stringifier(boolean signed, int radix, Function<N,String> toString) {
+            this.signed = signed;
+            this.radix = radix;
+            this.toString = toString;
+        }
+
+        public void assertMatchingToString(N value, BigInteger asSigned, BigInteger asUnsigned, String description) {
+            String expected = signed
+                ? asSigned.toString(radix)
+                : asUnsigned.toString(radix);
+
+            String actual = toString.apply(value);
+
+            assertEquals(actual, expected, description + " conversion should be the same");
+        }
+    }
+
+    @DataProvider(name="numbers", parallel=true)
+    public Iterator<Object[]> testSetProvider() {
+
+    return Arrays.asList(
+        new Object[] { "Byte",
+            (Function<Byte,BigInteger>) b -> BigInteger.valueOf((long) b),
+            (Function<Byte,BigInteger>) b -> BigInteger.valueOf(Integer.toUnsignedLong((byte) b)),
+            numberProvider((LongFunction<Byte>) l -> Byte.valueOf((byte) l), Byte.SIZE),
+            new Stringifier[] {
+                new Stringifier<Byte>(true, 10, b -> b.toString()),
+                new Stringifier<Byte>(true, 10, b -> Byte.toString(b))
+            }
+        },
+        new Object[] { "Short",
+            (Function<Short,BigInteger>) s -> BigInteger.valueOf((long) s),
+            (Function<Short,BigInteger>) s -> BigInteger.valueOf(Integer.toUnsignedLong((short) s)),
+            numberProvider((LongFunction<Short>) l -> Short.valueOf((short) l), Short.SIZE),
+            new Stringifier[] {
+                new Stringifier<Short>(true, 10, s -> s.toString()),
+                new Stringifier<Short>(true, 10, s -> Short.toString( s))
+            }
+        },
+        new Object[] { "Integer",
+            (Function<Integer,BigInteger>) i -> BigInteger.valueOf((long) i),
+            (Function<Integer,BigInteger>) i -> BigInteger.valueOf(Integer.toUnsignedLong(i)),
+            numberProvider((LongFunction<Integer>) l -> Integer.valueOf((int) l), Integer.SIZE),
+            new Stringifier[] {
+                new Stringifier<Integer>(true, 10, i -> i.toString()),
+                new Stringifier<Integer>(true, 10, i -> Integer.toString(i)),
+                new Stringifier<Integer>(false, 2, Integer::toBinaryString),
+                new Stringifier<Integer>(false, 16, Integer::toHexString),
+                new Stringifier<Integer>(false, 8, Integer::toOctalString),
+                new Stringifier<Integer>(true, 2, i -> Integer.toString(i, 2)),
+                new Stringifier<Integer>(true, 8, i -> Integer.toString(i, 8)),
+                new Stringifier<Integer>(true, 10, i -> Integer.toString(i, 10)),
+                new Stringifier<Integer>(true, 16, i -> Integer.toString(i, 16)),
+                new Stringifier<Integer>(true, Character.MAX_RADIX, i -> Integer.toString(i, Character.MAX_RADIX)),
+                new Stringifier<Integer>(false, 10, i -> Integer.toUnsignedString(i)),
+                new Stringifier<Integer>(false, 2, i -> Integer.toUnsignedString(i, 2)),
+                new Stringifier<Integer>(false, 8, i -> Integer.toUnsignedString(i, 8)),
+                new Stringifier<Integer>(false, 10, i -> Integer.toUnsignedString(i, 10)),
+                new Stringifier<Integer>(false, 16, i -> Integer.toUnsignedString(i, 16)),
+                new Stringifier<Integer>(false, Character.MAX_RADIX, i -> Integer.toUnsignedString(i, Character.MAX_RADIX))
+            }
+        },
+        new Object[] { "Long",
+            (Function<Long, BigInteger>) BigInteger::valueOf,
+            (Function<Long, BigInteger>) l -> {
+                if (l >= 0) {
+                    return BigInteger.valueOf((long) l);
+                } else {
+                    int upper = (int)(l >>> 32);
+                    int lower = (int) (long) l;
+
+                    // return (upper << 32) + lower
+                    return (BigInteger.valueOf(Integer.toUnsignedLong(upper))).shiftLeft(32).
+                    add(BigInteger.valueOf(Integer.toUnsignedLong(lower)));
+                }
+            },
+            numberProvider((LongFunction<Long>) Long::valueOf, Long.SIZE),
+            new Stringifier[] {
+                new Stringifier<Long>(true, 10, l -> l.toString()),
+                new Stringifier<Long>(true, 10, l -> Long.toString(l)),
+                new Stringifier<Long>(false, 2, Long::toBinaryString),
+                new Stringifier<Long>(false, 16, Long::toHexString),
+                new Stringifier<Long>(false, 8, Long::toOctalString),
+                new Stringifier<Long>(true, 2, l -> Long.toString(l, 2)),
+                new Stringifier<Long>(true, 8, l -> Long.toString(l, 8)),
+                new Stringifier<Long>(true, 10, l -> Long.toString(l, 10)),
+                new Stringifier<Long>(true, 16, l -> Long.toString(l, 16)),
+                new Stringifier<Long>(true, Character.MAX_RADIX, l -> Long.toString(l, Character.MAX_RADIX)),
+                new Stringifier<Long>(false, 10, Long::toUnsignedString),
+                new Stringifier<Long>(false, 2, l -> Long.toUnsignedString(l, 2)),
+                new Stringifier<Long>(false, 8, l-> Long.toUnsignedString(l, 8)),
+                new Stringifier<Long>(false, 10, l -> Long.toUnsignedString(l, 10)),
+                new Stringifier<Long>(false, 16, l -> Long.toUnsignedString(l, 16)),
+                new Stringifier<Long>(false, Character.MAX_RADIX, l -> Long.toUnsignedString(l, Character.MAX_RADIX))
+            }
+        }
+        ).iterator();
+    }
+    private static final long[] SOME_PRIMES = {
+        3L, 5L, 7L, 11L, 13L, 17L, 19L, 23L, 29L, 31L, 37L, 41L, 43L, 47L, 53L,
+        59L, 61L, 71L, 73L, 79L, 83L, 89L, 97L, 101L, 103L, 107L, 109L, 113L,
+        5953L, 5981L, 5987L, 6007L, 6011L, 6029L, 6037L, 6043L, 6047L, 6053L,
+        16369L, 16381L, 16411L, 32749L, 32771L, 65521L, 65537L,
+        (long) Integer.MAX_VALUE };
+
+    public <N extends Number> N[] numberProvider(LongFunction<N> boxer, int bits, N... extras) {
+        List<N> numbers = new ArrayList<>();
+
+        for(int bitmag = 0; bitmag < bits; bitmag++) {
+            long value = 1L << bitmag;
+            numbers.add(boxer.apply(value));
+            numbers.add(boxer.apply(value - 1));
+            numbers.add(boxer.apply(value + 1));
+            numbers.add(boxer.apply(-value));
+            for(int divisor = 0; divisor < SOME_PRIMES.length && value < SOME_PRIMES[divisor]; divisor++) {
+                numbers.add(boxer.apply(value - SOME_PRIMES[divisor]));
+                numbers.add(boxer.apply(value + SOME_PRIMES[divisor]));
+                numbers.add(boxer.apply(value * SOME_PRIMES[divisor]));
+                numbers.add(boxer.apply(value / SOME_PRIMES[divisor]));
+                numbers.add(boxer.apply(value | SOME_PRIMES[divisor]));
+                numbers.add(boxer.apply(value & SOME_PRIMES[divisor]));
+                numbers.add(boxer.apply(value ^ SOME_PRIMES[divisor]));
+            }
+        }
+
+        numbers.addAll(Arrays.asList(extras));
+
+        return (N[]) numbers.toArray(new Number[numbers.size()]);
+    }
+}
--- a/jdk/test/java/lang/SecurityManager/CheckPackageAccess.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/lang/SecurityManager/CheckPackageAccess.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,8 +23,8 @@
 
 /*
  * @test
- * @bug 7146431
- * @summary Test that internal JAXP packages cannot be accessed
+ * @bug 7146431 8000450
+ * @summary Test that internal packages cannot be accessed
  */
 
 public class CheckPackageAccess {
@@ -32,6 +32,7 @@
     public static void main(String[] args) throws Exception {
 
         String[] pkgs = new String[] {
+            "com.sun.corba.se.impl.",
             "com.sun.org.apache.xerces.internal.utils.",
             "com.sun.org.apache.xalan.internal.utils." };
         SecurityManager sm = new SecurityManager();
@@ -40,7 +41,11 @@
             System.out.println("Checking package access for " + pkg);
             try {
                 sm.checkPackageAccess(pkg);
-                throw new Exception("Expected SecurityException not thrown");
+                throw new Exception("Expected PackageAccess SecurityException not thrown");
+            } catch (SecurityException se) { }
+            try {
+                sm.checkPackageDefinition(pkg);
+                throw new Exception("Expected PackageDefinition SecurityException not thrown");
             } catch (SecurityException se) { }
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/String/StringContentEqualsBug.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ */
+
+/**
+ * @test
+ * @bug 8014477
+ * @summary test String.contentEquals(StringBuffer)
+ */
+public class StringContentEqualsBug {
+
+    static abstract class Task extends Thread {
+        volatile StringBuffer sb;
+        volatile Exception exception;
+
+        Task(StringBuffer sb) {
+            this.sb = sb;
+        }
+
+        @Override
+        public void run() {
+            try {
+                StringBuffer sb;
+                while ((sb = this.sb) != null) {
+                    doWith(sb);
+                }
+            }
+            catch (Exception e) {
+                exception = e;
+            }
+        }
+
+        protected abstract void doWith(StringBuffer sb);
+    }
+
+    static class Tester extends Task {
+        Tester(StringBuffer sb) {
+            super(sb);
+        }
+
+        @Override
+        protected void doWith(StringBuffer sb) {
+            "AA".contentEquals(sb);
+        }
+    }
+
+    static class Disturber extends Task {
+        Disturber(StringBuffer sb) {
+            super(sb);
+        }
+
+        @Override
+        protected void doWith(StringBuffer sb) {
+            sb.setLength(0);
+            sb.trimToSize();
+            sb.append("AA");
+        }
+    }
+
+
+    public static void main(String[] args) throws Exception {
+        StringBuffer sb = new StringBuffer();
+        Task[] tasks = new Task[3];
+        (tasks[0] = new Tester(sb)).start();
+        for (int i = 1; i < tasks.length; i++) {
+            (tasks[i] = new Disturber(sb)).start();
+        }
+
+        try
+        {
+            // wait at most 5 seconds for any of the threads to throw exception
+            for (int i = 0; i < 20; i++) {
+                for (Task task : tasks) {
+                    if (task.exception != null) {
+                        throw task.exception;
+                    }
+                }
+                Thread.sleep(250L);
+            }
+        }
+        finally {
+            for (Task task : tasks) {
+                task.sb = null;
+                task.join();
+            }
+        }
+    }
+}
--- a/jdk/test/java/lang/StringBuffer/ToStringCache.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/lang/StringBuffer/ToStringCache.java	Mon Jun 10 10:38:33 2013 +0100
@@ -22,7 +22,7 @@
  */
 
 /* @test
- * @bug 8013395
+ * @bug 8013395 8014814
  * @summary Test StringBuffer.toString caching
  */
 
@@ -199,6 +199,28 @@
         b = sb.toString();
         checkUnequal(a, b);
 
+        // Extra checks that append(null) works correctly
+
+        sb.append((String)null);
+        b = sb.toString();
+        checkUnequal(a, b);
+        a = b;
+
+        sb.append((StringBuffer)null);
+        b = sb.toString();
+        checkUnequal(a, b);
+        a = b;
+
+        sb.append((StringBuilder)null);
+        b = sb.toString();
+        checkUnequal(a, b);
+        a = b;
+
+        sb.append((CharSequence)null);
+        b = sb.toString();
+        checkUnequal(a, b);
+        a = b;
+
         // non-mutating methods
 
         // Reset to known value
--- a/jdk/test/java/lang/instrument/MakeJAR4.sh	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/lang/instrument/MakeJAR4.sh	Mon Jun 10 10:38:33 2013 +0100
@@ -43,4 +43,4 @@
 done
 
 
-${JAR} "{TESTTOOLVMOPTS}" cvfm ${AGENT}.jar ${AGENT}.mf ${AGENT}*.class ${OTHER}*.java
+${JAR} "${TESTTOOLVMOPTS}" cvfm ${AGENT}.jar ${AGENT}.mf ${AGENT}*.class ${OTHER}*.java
--- a/jdk/test/java/lang/instrument/RetransformBigClass.sh	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/lang/instrument/RetransformBigClass.sh	Mon Jun 10 10:38:33 2013 +0100
@@ -23,7 +23,6 @@
 
 # @test
 # @bug 7122253
-# @ignore until the fix for 7122253 (from HotSpot) is in a promoted build
 # @summary Retransform a big class.
 # @author Daniel D. Daugherty
 #
--- a/jdk/test/java/lang/management/MXBean/MXBeanBehavior.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/lang/management/MXBean/MXBeanBehavior.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2013 Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -36,6 +36,10 @@
 import javax.management.*;
 
 public class MXBeanBehavior {
+    // Exclude list: list of platform MBeans that are not MXBeans
+    public static final HashSet<String> excludeList = new HashSet<>(
+            Arrays.asList("com.sun.management:type=DiagnosticCommand"));
+
     public static void main(String[] args) throws Exception {
         MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
 
@@ -92,6 +96,10 @@
        by generic MXBean tests.
      */
     private static void test(MBeanServer mbs, ObjectName name) throws Exception {
+        if(excludeList.contains(name.getCanonicalName())) {
+            // Skipping not MXBean objects.
+            return;
+        }
         System.out.println("Testing: " + name);
 
         MBeanInfo mbi = mbs.getMBeanInfo(name);
--- a/jdk/test/java/lang/management/ManagementFactory/MBeanServerMXBeanUnsupportedTest.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/lang/management/ManagementFactory/MBeanServerMXBeanUnsupportedTest.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2013 Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -36,6 +36,8 @@
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
+import java.util.Arrays;
+import java.util.HashSet;
 import javax.management.MBeanServer;
 import javax.management.MBeanServerBuilder;
 import javax.management.MBeanServerDelegate;
@@ -81,6 +83,9 @@
     public static class MBeanServerForwarderInvocationHandler
             implements InvocationHandler {
 
+        public static final HashSet<String> excludeList = new HashSet<String>(
+            Arrays.asList("com.sun.management:type=DiagnosticCommand"));
+
         public static MBeanServerForwarder newProxyInstance() {
 
             final InvocationHandler handler =
@@ -126,15 +131,17 @@
                 if (domain.equals("java.lang") ||
                     domain.equals("java.util.logging") ||
                     domain.equals("com.sun.management")) {
-                    String mxbean = (String)
-                        mbs.getMBeanInfo(name).getDescriptor().getFieldValue("mxbean");
-                    if (mxbean == null || !mxbean.equals("true")) {
-                        throw new RuntimeException(
+                    if(!excludeList.contains(name.getCanonicalName())) {
+                        String mxbean = (String)
+                            mbs.getMBeanInfo(name).getDescriptor().getFieldValue("mxbean");
+                        if (mxbean == null || !mxbean.equals("true")) {
+                            throw new RuntimeException(
                                 "Platform MBeans must be MXBeans!");
-                    }
-                    if (!(mbean instanceof StandardMBean)) {
-                        throw new RuntimeException(
+                        }
+                        if (!(mbean instanceof StandardMBean)) {
+                            throw new RuntimeException(
                                 "MXBeans must be wrapped in StandardMBean!");
+                        }
                     }
                 }
                 return result;
--- a/jdk/test/java/lang/management/MemoryMXBean/ResetPeakMemoryUsage.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/lang/management/MemoryMXBean/ResetPeakMemoryUsage.java	Mon Jun 10 10:38:33 2013 +0100
@@ -22,13 +22,18 @@
  */
 
 /*
+ * The -XX:MarkSweepAlwaysCompactCount=1 argument below makes sure serial gc
+ * compacts the heap at every full gc so that the usage is correctly updated.
+ */
+
+/*
  * @test
  * @bug     4892507
  * @summary Basic Test for MemoryPool.resetPeakUsage()
  * @author  Mandy Chung
  *
  * @build ResetPeakMemoryUsage MemoryUtil
- * @run main/othervm -XX:+UseSerialGC -Xmn8m ResetPeakMemoryUsage
+ * @run main/othervm -XX:+UseSerialGC -XX:MarkSweepAlwaysCompactCount=1 -Xmn8m ResetPeakMemoryUsage
  * @run main/othervm -XX:+UseConcMarkSweepGC -Xmn8m ResetPeakMemoryUsage
  * @run main/othervm -XX:+UseParallelGC -Xmn8m ResetPeakMemoryUsage
  * @run main/othervm -XX:+UseG1GC -Xmn8m -XX:G1HeapRegionSize=1m ResetPeakMemoryUsage
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/ref/OOMEInReferenceHandler.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+/**
+ * @test
+ * @bug 7038914
+ * @summary Verify that the reference handler does not die after an OOME allocating the InterruptedException object
+ * @run main/othervm -Xmx16M -XX:-UseTLAB OOMEInReferenceHandler
+ * @author peter.levart@gmail.com
+ */
+
+import java.lang.ref.*;
+
+public class OOMEInReferenceHandler {
+     static Object[] fillHeap() {
+         Object[] first = null, last = null;
+         int size = 1 << 20;
+         while (size > 0) {
+             try {
+                 Object[] array = new Object[size];
+                 if (first == null) {
+                     first = array;
+                 } else {
+                     last[0] = array;
+                 }
+                 last = array;
+             } catch (OutOfMemoryError oome) {
+                 size = size >>> 1;
+             }
+         }
+         return first;
+     }
+
+     public static void main(String[] args) throws Exception {
+         // preinitialize the InterruptedException class so that the reference handler
+         // does not die due to OOME when loading the class if it is the first use
+         InterruptedException ie = new InterruptedException("dummy");
+
+         ThreadGroup tg = Thread.currentThread().getThreadGroup();
+         for (
+             ThreadGroup tgn = tg;
+             tgn != null;
+             tg = tgn, tgn = tg.getParent()
+             )
+             ;
+
+         Thread[] threads = new Thread[tg.activeCount()];
+         Thread referenceHandlerThread = null;
+         int n = tg.enumerate(threads);
+         for (int i = 0; i < n; i++) {
+             if ("Reference Handler".equals(threads[i].getName())) {
+                 referenceHandlerThread = threads[i];
+             }
+         }
+
+         if (referenceHandlerThread == null) {
+             throw new IllegalStateException("Couldn't find Reference Handler thread.");
+         }
+
+         ReferenceQueue<Object> refQueue = new ReferenceQueue<>();
+         Object referent = new Object();
+         WeakReference<Object> weakRef = new WeakReference<>(referent, refQueue);
+
+         Object waste = fillHeap();
+
+         referenceHandlerThread.interrupt();
+
+         // allow referenceHandlerThread some time to throw OOME
+         Thread.sleep(500L);
+
+         // release waste & referent
+         waste = null;
+         referent = null;
+
+         // wait at most 10 seconds for success or failure
+         for (int i = 0; i < 20; i++) {
+             if (refQueue.poll() != null) {
+                 // Reference Handler thread still working -> success
+                 return;
+             }
+             System.gc();
+             Thread.sleep(500L); // wait a little to allow GC to do it's work before allocating objects
+             if (!referenceHandlerThread.isAlive()) {
+                 // Reference Handler thread died -> failure
+                 throw new Exception("Reference Handler thread died.");
+             }
+         }
+
+         // no sure answer after 10 seconds
+         throw new IllegalStateException("Reference Handler thread stuck.");
+     }
+}
--- a/jdk/test/java/net/CookieHandler/CookieManagerTest.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/net/CookieHandler/CookieManagerTest.java	Mon Jun 10 10:38:33 2013 +0100
@@ -24,20 +24,14 @@
 /*
  * @test
  * @summary Unit test for java.net.CookieManager
- * @bug 6244040 7150552
+ * @bug 6244040 7150552 7051862
  * @run main/othervm -ea CookieManagerTest
  * @author Edward Wang
  */
 
 import com.sun.net.httpserver.*;
 import java.io.IOException;
-import java.net.CookieHandler;
-import java.net.CookieManager;
-import java.net.CookiePolicy;
-import java.net.HttpURLConnection;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.URL;
+import java.net.*;
 
 public class CookieManagerTest {
 
@@ -51,15 +45,37 @@
         if (httpTrans.badRequest) {
             throw new RuntimeException("Test failed : bad cookie header");
         }
+        checkCookiePolicy();
     }
 
-    public static void startHttpServer() throws IOException {
+   public static void startHttpServer() throws IOException {
         httpTrans = new CookieTransactionHandler();
         server = HttpServer.create(new InetSocketAddress(0), 0);
         server.createContext("/", httpTrans);
         server.start();
     }
 
+    /*
+     * Checks if CookiePolicy.ACCEPT_ORIGINAL_SERVER#shouldAccept()
+     * returns false for null arguments
+     */
+    private static void checkCookiePolicy() throws Exception {
+        CookiePolicy cp = CookiePolicy.ACCEPT_ORIGINAL_SERVER;
+        boolean retVal;
+        retVal = cp.shouldAccept(null, null);
+        checkValue(retVal);
+        retVal = cp.shouldAccept(null, new HttpCookie("CookieName", "CookieVal"));
+        checkValue(retVal);
+        retVal = cp.shouldAccept((new URL("http", "localhost", 2345, "/")).toURI(),
+                                  null);
+        checkValue(retVal);
+    }
+
+    private static void checkValue(boolean val) {
+        if (val)
+            throw new RuntimeException("Return value is not false!");
+    }
+
     public static void makeHttpCall() throws IOException {
         try {
             System.out.println("http server listenining on: "
--- a/jdk/test/java/net/CookieHandler/TestHttpCookie.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/net/CookieHandler/TestHttpCookie.java	Mon Jun 10 10:38:33 2013 +0100
@@ -243,6 +243,10 @@
         test("set-cookie2: Customer = \"WILE_E_COYOTE\"; Version = \"1\"; Path = \"/acme\"")
         .n("Customer").v("WILE_E_COYOTE").ver(1).p("/acme");
 
+        // $NAME is reserved; result should be null
+        test("set-cookie2: $Customer = \"WILE_E_COYOTE\"; Version = \"1\"; Path = \"/acme\"")
+        .nil();
+
         // a 'full' cookie
         test("set-cookie2: Customer=\"WILE_E_COYOTE\"" +
                 ";Version=\"1\"" +
--- a/jdk/test/java/net/InterfaceAddress/NetworkPrefixLength.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/net/InterfaceAddress/NetworkPrefixLength.java	Mon Jun 10 10:38:33 2013 +0100
@@ -22,7 +22,7 @@
  */
 
 /* @test
- * @bug 6707289
+ * @bug 6707289 7107883
  * @summary InterfaceAddress.getNetworkPrefixLength() does not conform to Javadoc
  */
 
@@ -47,6 +47,14 @@
                     passed = false;
                     debug(nic.getName(), iaddr);
                 }
+                InetAddress ia = iaddr.getAddress();
+                if (ia.isLoopbackAddress() && ia instanceof Inet4Address) {
+                    // assumption: prefix length will always be 8
+                    if (iaddr.getNetworkPrefixLength() != 8) {
+                        out.println("Expected prefix of 8, got " + iaddr);
+                        passed = false;
+                    }
+                }
             }
         }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/Buffer/Chars.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,137 @@
+/*
+ * 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.
+ */
+
+/**
+ * @test
+ * @bug 8014854
+ * @summary Exercises CharBuffer#chars on each of the CharBuffer types
+ * @run testng Chars
+ */
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.CharBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+
+public class Chars {
+
+    static final Random RAND = new Random();
+
+    static final int SIZE = 128 + RAND.nextInt(1024);
+
+    /**
+     * Randomize the char buffer's position and limit.
+     */
+    static CharBuffer randomizeRange(CharBuffer cb) {
+        int mid = cb.capacity() >>> 1;
+        int start = RAND.nextInt(mid);
+        int end = mid + RAND.nextInt(mid);
+        cb.position(start);
+        cb.limit(end);
+        return cb;
+    }
+
+    /**
+     * Randomize the char buffer's contents, position and limit.
+     */
+    static CharBuffer randomize(CharBuffer cb) {
+        while (cb.hasRemaining()) {
+            cb.put((char)RAND.nextInt());
+        }
+        return randomizeRange(cb);
+    }
+
+    /**
+     * Sums the remaining chars in the char buffer.
+     */
+    static int intSum(CharBuffer cb) {
+        int sum = 0;
+        cb.mark();
+        while (cb.hasRemaining()) {
+            sum += cb.get();
+        }
+        cb.reset();
+        return sum;
+    }
+
+    /**
+     * Creates char buffers to test, adding them to the given list.
+     */
+    static void addCases(CharBuffer cb, List<CharBuffer> buffers) {
+        randomize(cb);
+        buffers.add(cb);
+
+        buffers.add(cb.slice());
+        buffers.add(cb.duplicate());
+        buffers.add(cb.asReadOnlyBuffer());
+
+        buffers.add(randomizeRange(cb.slice()));
+        buffers.add(randomizeRange(cb.duplicate()));
+        buffers.add(randomizeRange(cb.asReadOnlyBuffer()));
+    }
+
+    @DataProvider(name = "charbuffers")
+    public Object[][] createCharBuffers() {
+        List<CharBuffer> buffers = new ArrayList<>();
+
+        // heap
+        addCases(CharBuffer.allocate(SIZE), buffers);
+        addCases(CharBuffer.wrap(new char[SIZE]), buffers);
+        addCases(ByteBuffer.allocate(SIZE*2).order(ByteOrder.BIG_ENDIAN).asCharBuffer(),
+                 buffers);
+        addCases(ByteBuffer.allocate(SIZE*2).order(ByteOrder.LITTLE_ENDIAN).asCharBuffer(),
+                 buffers);
+
+        // direct
+        addCases(ByteBuffer.allocateDirect(SIZE*2).order(ByteOrder.BIG_ENDIAN).asCharBuffer(),
+                 buffers);
+        addCases(ByteBuffer.allocateDirect(SIZE*2).order(ByteOrder.LITTLE_ENDIAN).asCharBuffer(),
+                 buffers);
+
+        // read-only buffer backed by a CharSequence
+        buffers.add(CharBuffer.wrap(randomize(CharBuffer.allocate(SIZE))));
+
+        Object[][] params = new Object[buffers.size()][];
+        for (int i = 0; i < buffers.size(); i++) {
+            CharBuffer cb = buffers.get(i);
+            params[i] = new Object[] { cb.getClass().getName(), cb };
+        }
+
+        return params;
+    }
+
+    @Test(dataProvider = "charbuffers")
+    public void testChars(String type, CharBuffer cb) {
+        System.out.format("%s position=%d, limit=%d%n", type, cb.position(), cb.limit());
+        int expected = intSum(cb);
+        assertEquals(cb.chars().sum(), expected);
+        assertEquals(cb.chars().parallel().sum(), expected);
+    }
+}
--- a/jdk/test/java/nio/channels/AsynchronousChannelGroup/Unbounded.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/Unbounded.java	Mon Jun 10 10:38:33 2013 +0100
@@ -43,47 +43,24 @@
     static volatile boolean finished;
 
     public static void main(String[] args) throws Exception {
-        // all accepted connections are added to a queue
-        final ArrayBlockingQueue<AsynchronousSocketChannel> queue =
-            new ArrayBlockingQueue<AsynchronousSocketChannel>(CONCURRENCY_COUNT);
-
         // create listener to accept connections
-        final AsynchronousServerSocketChannel listener =
+        AsynchronousServerSocketChannel listener =
             AsynchronousServerSocketChannel.open()
                 .bind(new InetSocketAddress(0));
-        listener.accept((Void)null, new CompletionHandler<AsynchronousSocketChannel,Void>() {
-            public void completed(AsynchronousSocketChannel ch, Void att) {
-                queue.add(ch);
-                listener.accept((Void)null, this);
-            }
-            public void failed(Throwable exc, Void att) {
-                if (!finished) {
-                    failed = true;
-                    System.err.println("accept failed: " + exc);
-                }
-            }
-        });
-        System.out.println("Listener created.");
+
+        // establish connections
 
-        // establish lots of connections
+        AsynchronousSocketChannel[] clients = new AsynchronousSocketChannel[CONCURRENCY_COUNT];
+        AsynchronousSocketChannel[] peers = new AsynchronousSocketChannel[CONCURRENCY_COUNT];
+
         int port = ((InetSocketAddress)(listener.getLocalAddress())).getPort();
         SocketAddress sa = new InetSocketAddress(InetAddress.getLocalHost(), port);
-        AsynchronousSocketChannel[] channels =
-            new AsynchronousSocketChannel[CONCURRENCY_COUNT];
+
         for (int i=0; i<CONCURRENCY_COUNT; i++) {
-            int attempts = 0;
-            for (;;) {
-                try {
-                    channels[i] = AsynchronousSocketChannel.open();
-                    channels[i].connect(sa).get();
-                    break;
-                } catch (IOException x) {
-                    // probably resource issue so back off and retry
-                    if (++attempts >= 3)
-                        throw x;
-                    Thread.sleep(50);
-                }
-            }
+            clients[i] = AsynchronousSocketChannel.open();
+            Future<Void> result = clients[i].connect(sa);
+            peers[i] = listener.accept().get();
+            result.get();
         }
         System.out.println("All connection established.");
 
@@ -91,9 +68,9 @@
         final CyclicBarrier barrier = new CyclicBarrier(CONCURRENCY_COUNT+1);
 
         // initiate a read operation on each channel.
-        for (int i=0; i<CONCURRENCY_COUNT; i++) {
+        for (AsynchronousSocketChannel client: clients) {
             ByteBuffer buf = ByteBuffer.allocateDirect(100);
-            channels[i].read( buf, channels[i],
+            client.read(buf, client,
                 new CompletionHandler<Integer,AsynchronousSocketChannel>() {
                     public void completed(Integer bytesRead, AsynchronousSocketChannel ch) {
                         try {
@@ -113,13 +90,10 @@
         System.out.println("All read operations outstanding.");
 
         // write data to each of the accepted connections
-        int remaining = CONCURRENCY_COUNT;
-        while (remaining > 0) {
-            AsynchronousSocketChannel ch = queue.take();
-            ch.write(ByteBuffer.wrap("welcome".getBytes())).get();
-            ch.shutdownOutput();
-            ch.close();
-            remaining--;
+        for (AsynchronousSocketChannel peer: peers) {
+            peer.write(ByteBuffer.wrap("welcome".getBytes())).get();
+            peer.shutdownOutput();
+            peer.close();
         }
 
         // wait for all threads to reach the barrier
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/Files/FaultyFileSystem.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,499 @@
+/*
+ * 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.io.IOException;
+import java.net.URI;
+import java.nio.channels.SeekableByteChannel;
+import java.nio.file.AccessMode;
+import java.nio.file.CopyOption;
+import java.nio.file.DirectoryIteratorException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.FileStore;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystemAlreadyExistsException;
+import java.nio.file.FileSystemNotFoundException;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.OpenOption;
+import java.nio.file.Path;
+import java.nio.file.PathMatcher;
+import java.nio.file.WatchService;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.nio.file.attribute.FileAttribute;
+import java.nio.file.attribute.FileAttributeView;
+import java.nio.file.attribute.UserPrincipalLookupService;
+import java.nio.file.spi.FileSystemProvider;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.function.Supplier;
+
+/**
+ * A {@code FileSystem} that helps testing by trigger exception throwing based on filenames.
+ */
+class FaultyFileSystem extends FileSystem {
+    final Path root;
+    final boolean removeRootAfterClose;
+    final FileSystem delegate;
+    boolean isOpen;
+
+    FaultyFileSystem(Path root) throws IOException {
+        if (root == null) {
+            root = Files.createTempDirectory("faultyFS");
+            removeRootAfterClose = true;
+        } else {
+            if (! Files.isDirectory(root)) {
+                throw new IllegalArgumentException("must be a directory.");
+            }
+            removeRootAfterClose = false;
+        }
+        this.root = root;
+        delegate = root.getFileSystem();
+        isOpen = true;
+    }
+
+    private static Path unwrap(Path p) {
+        return PassThroughFileSystem.unwrap(p);
+    }
+
+    Path getRoot() {
+        return new PassThroughFileSystem.PassThroughPath(this, root);
+    }
+
+    @Override
+    public void close() throws IOException {
+        if (isOpen) {
+            if (removeRootAfterClose) {
+                TestUtil.removeAll(root);
+            }
+            isOpen = false;
+        }
+    }
+
+    @Override
+    public FileSystemProvider provider() {
+        return FaultyFSProvider.getInstance();
+    }
+
+    @Override
+    public boolean isOpen() {
+        return isOpen;
+    }
+
+    @Override
+    public boolean isReadOnly() {
+        return delegate.isReadOnly();
+    }
+
+    @Override
+    public String getSeparator() {
+        return delegate.getSeparator();
+    }
+
+    private <T> Iterable<T> SoleIterable(final T element) {
+        return new Iterable<T>() {
+            @Override
+            public Iterator<T> iterator() {
+                return new Iterator<T>() {
+                    private T soleElement = element;
+
+                    @Override
+                    public boolean hasNext() {
+                        return soleElement != null;
+                    }
+
+                    @Override
+                    public T next() {
+                        try {
+                            return soleElement;
+                        } finally {
+                            soleElement = null;
+                        }
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public Iterable<Path> getRootDirectories() {
+        return SoleIterable(getRoot());
+    }
+
+    @Override
+    public Iterable<FileStore> getFileStores() {
+        FileStore store;
+        try {
+            store = Files.getFileStore(root);
+        } catch (IOException ioe) {
+            store = null;
+        }
+        return SoleIterable(store);
+    }
+
+    @Override
+    public Set<String> supportedFileAttributeViews() {
+        // assume that unwrapped objects aren't exposed
+        return delegate.supportedFileAttributeViews();
+    }
+
+    @Override
+    public Path getPath(String first, String... more) {
+        return new PassThroughFileSystem.PassThroughPath(this, delegate.getPath(first, more));
+    }
+
+    @Override
+    public PathMatcher getPathMatcher(String syntaxAndPattern) {
+        final PathMatcher matcher = delegate.getPathMatcher(syntaxAndPattern);
+        return new PathMatcher() {
+            @Override
+            public boolean matches(Path path) {
+                return matcher.matches(unwrap(path));
+            }
+        };
+    }
+
+    @Override
+    public UserPrincipalLookupService getUserPrincipalLookupService() {
+        // assume that unwrapped objects aren't exposed
+        return delegate.getUserPrincipalLookupService();
+    }
+
+    @Override
+    public WatchService newWatchService() throws IOException {
+        // to keep it simple
+        throw new UnsupportedOperationException();
+    }
+
+    static class FaultyException extends IOException {
+        FaultyException() {
+            super("fault triggered.");
+        }
+    }
+
+    static class FaultyFSProvider extends FileSystemProvider {
+        private static final String SCHEME = "faulty";
+        private static volatile FaultyFileSystem delegate;
+        private static FaultyFSProvider INSTANCE = new FaultyFSProvider();
+        private boolean enabled;
+
+        private FaultyFSProvider() {}
+
+        public static FaultyFSProvider getInstance() {
+            return INSTANCE;
+        }
+
+        public void setFaultyMode(boolean enable) {
+            enabled = enable;
+        }
+
+        private void triggerEx(String filename, String... names) throws IOException {
+            if (! enabled) {
+                return;
+            }
+
+            if (filename.equals("SecurityException")) {
+                throw new SecurityException("FaultyFS", new FaultyException());
+            }
+
+            if (filename.equals("IOException")) {
+                throw new FaultyException();
+            }
+
+            for (String name: names) {
+                if (name.equals(filename)) {
+                    throw new FaultyException();
+                }
+            }
+        }
+
+        private void triggerEx(Path path, String... names) throws IOException {
+            triggerEx(path.getFileName().toString(), names);
+        }
+
+        @Override
+        public String getScheme() {
+            return SCHEME;
+        }
+
+        private void checkScheme(URI uri) {
+            if (!uri.getScheme().equalsIgnoreCase(SCHEME))
+                throw new IllegalArgumentException();
+        }
+
+        private void checkUri(URI uri) {
+            checkScheme(uri);
+            if (!uri.getSchemeSpecificPart().equals("///"))
+                throw new IllegalArgumentException();
+        }
+
+        @Override
+        public FileSystem newFileSystem(Path fakeRoot, Map<String,?> env)
+            throws IOException
+        {
+            if (env != null && env.keySet().contains("IOException")) {
+                triggerEx("IOException");
+            }
+
+            synchronized (FaultyFSProvider.class) {
+                if (delegate != null && delegate.isOpen())
+                    throw new FileSystemAlreadyExistsException();
+                FaultyFileSystem result = new FaultyFileSystem(fakeRoot);
+                delegate = result;
+                return result;
+            }
+        }
+
+        @Override
+        public FileSystem newFileSystem(URI uri, Map<String,?> env)
+            throws IOException
+        {
+            if (env != null && env.keySet().contains("IOException")) {
+                triggerEx("IOException");
+            }
+
+            checkUri(uri);
+            synchronized (FaultyFSProvider.class) {
+                if (delegate != null && delegate.isOpen())
+                    throw new FileSystemAlreadyExistsException();
+                FaultyFileSystem result = new FaultyFileSystem(null);
+                delegate = result;
+                return result;
+            }
+        }
+
+        @Override
+        public FileSystem getFileSystem(URI uri) {
+            checkUri(uri);
+            FileSystem result = delegate;
+            if (result == null)
+                throw new FileSystemNotFoundException();
+            return result;
+        }
+
+        @Override
+        public Path getPath(URI uri) {
+            checkScheme(uri);
+            if (delegate == null)
+                throw new FileSystemNotFoundException();
+
+            // only allow absolute path
+            String path = uri.getSchemeSpecificPart();
+            if (! path.startsWith("///")) {
+                throw new IllegalArgumentException();
+            }
+            return new PassThroughFileSystem.PassThroughPath(delegate, delegate.root.resolve(path.substring(3)));
+        }
+
+        @Override
+        public void setAttribute(Path file, String attribute, Object value, LinkOption... options)
+            throws IOException
+        {
+            triggerEx(file, "setAttribute");
+            Files.setAttribute(unwrap(file), attribute, value, options);
+        }
+
+        @Override
+        public Map<String,Object> readAttributes(Path file, String attributes, LinkOption... options)
+            throws IOException
+        {
+            triggerEx(file, "readAttributes");
+            return Files.readAttributes(unwrap(file), attributes, options);
+        }
+
+        @Override
+        public <V extends FileAttributeView> V getFileAttributeView(Path file,
+                                                                    Class<V> type,
+                                                                    LinkOption... options)
+        {
+            return Files.getFileAttributeView(unwrap(file), type, options);
+        }
+
+        @Override
+        public <A extends BasicFileAttributes> A readAttributes(Path file,
+                                                                Class<A> type,
+                                                                LinkOption... options)
+            throws IOException
+        {
+            triggerEx(file, "readAttributes");
+            return Files.readAttributes(unwrap(file), type, options);
+        }
+
+        @Override
+        public void delete(Path file) throws IOException {
+            triggerEx(file, "delete");
+            Files.delete(unwrap(file));
+        }
+
+        @Override
+        public void createSymbolicLink(Path link, Path target, FileAttribute<?>... attrs)
+            throws IOException
+        {
+            triggerEx(target, "createSymbolicLink");
+            Files.createSymbolicLink(unwrap(link), unwrap(target), attrs);
+        }
+
+        @Override
+        public void createLink(Path link, Path existing) throws IOException {
+            triggerEx(existing, "createLink");
+            Files.createLink(unwrap(link), unwrap(existing));
+        }
+
+        @Override
+        public Path readSymbolicLink(Path link) throws IOException {
+            Path target = Files.readSymbolicLink(unwrap(link));
+            triggerEx(target, "readSymbolicLink");
+            return new PassThroughFileSystem.PassThroughPath(delegate, target);
+        }
+
+
+        @Override
+        public void copy(Path source, Path target, CopyOption... options) throws IOException {
+            triggerEx(source, "copy");
+            Files.copy(unwrap(source), unwrap(target), options);
+        }
+
+        @Override
+        public void move(Path source, Path target, CopyOption... options) throws IOException {
+            triggerEx(source, "move");
+            Files.move(unwrap(source), unwrap(target), options);
+        }
+
+        private DirectoryStream<Path> wrap(final DirectoryStream<Path> stream) {
+            return new DirectoryStream<Path>() {
+                @Override
+                public Iterator<Path> iterator() {
+                    final Iterator<Path> itr = stream.iterator();
+                    return new Iterator<Path>() {
+                        private Path next = null;
+                        @Override
+                        public boolean hasNext() {
+                            if (next == null) {
+                                if (itr.hasNext()) {
+                                    next = itr.next();
+                                } else {
+                                    return false;
+                                }
+                            }
+                            if (next != null) {
+                                try {
+                                    triggerEx(next, "DirectoryIteratorException");
+                                } catch (IOException ioe) {
+                                    throw new DirectoryIteratorException(ioe);
+                                } catch (SecurityException se) {
+                                    // ??? Does DS throw SecurityException during iteration?
+                                    next = null;
+                                    return hasNext();
+                                }
+                            }
+                            return (next != null);
+                        }
+                        @Override
+                        public Path next() {
+                            try {
+                                if (next != null || hasNext()) {
+                                    return new PassThroughFileSystem.PassThroughPath(delegate, next);
+                                } else {
+                                    throw new NoSuchElementException();
+                                }
+                            } finally {
+                                next = null;
+                            }
+                        }
+
+                        @Override
+                        public void remove() {
+                            itr.remove();
+                        }
+                    };
+                }
+                @Override
+                public void close() throws IOException {
+                    stream.close();
+                }
+            };
+        }
+
+        @Override
+        public DirectoryStream<Path> newDirectoryStream(Path dir, DirectoryStream.Filter<? super Path> filter)
+            throws IOException
+        {
+            triggerEx(dir, "newDirectoryStream");
+            return wrap(Files.newDirectoryStream(unwrap(dir), filter));
+        }
+
+        @Override
+        public void createDirectory(Path dir, FileAttribute<?>... attrs)
+            throws IOException
+        {
+            triggerEx(dir, "createDirectory");
+            Files.createDirectory(unwrap(dir), attrs);
+        }
+
+        @Override
+        public SeekableByteChannel newByteChannel(Path file,
+                                                  Set<? extends OpenOption> options,
+                                                  FileAttribute<?>... attrs)
+            throws IOException
+        {
+            triggerEx(file, "newByteChannel");
+            return Files.newByteChannel(unwrap(file), options, attrs);
+        }
+
+
+        @Override
+        public boolean isHidden(Path file) throws IOException {
+            triggerEx(file, "isHidden");
+            return Files.isHidden(unwrap(file));
+        }
+
+        @Override
+        public FileStore getFileStore(Path file) throws IOException {
+            triggerEx(file, "getFileStore");
+            return Files.getFileStore(unwrap(file));
+        }
+
+        @Override
+        public boolean isSameFile(Path file, Path other) throws IOException {
+            triggerEx(file, "isSameFile");
+            return Files.isSameFile(unwrap(file), unwrap(other));
+        }
+
+        @Override
+        public void checkAccess(Path file, AccessMode... modes)
+            throws IOException
+        {
+            triggerEx(file, "checkAccess");
+            // hack
+            if (modes.length == 0) {
+                if (Files.exists(unwrap(file)))
+                    return;
+                else
+                    throw new NoSuchFileException(file.toString());
+            }
+            throw new RuntimeException("not implemented yet");
+        }
+    }
+}
--- a/jdk/test/java/nio/file/Files/PassThroughFileSystem.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/nio/file/Files/PassThroughFileSystem.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -304,7 +304,7 @@
         public DirectoryStream<Path> newDirectoryStream(Path dir, DirectoryStream.Filter<? super Path> filter)
             throws IOException
         {
-            return wrap(Files.newDirectoryStream(dir, filter));
+            return wrap(Files.newDirectoryStream(unwrap(dir), filter));
         }
 
         @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/Files/StreamTest.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,661 @@
+/*
+ * 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.
+ */
+
+/* @test
+ * @bug 8006884
+ * @summary Unit test for java.nio.file.Files
+ * @library ..
+ * @build PassThroughFileSystem FaultyFileSystem
+ * @run testng StreamTest
+ */
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.charset.Charset;
+import java.nio.charset.MalformedInputException;
+import java.nio.file.DirectoryIteratorException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.FileSystemLoopException;
+import java.nio.file.FileVisitOption;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.Arrays;
+import java.util.Comparators;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.function.BiPredicate;
+import java.util.stream.CloseableStream;
+import java.util.stream.Collectors;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+@Test(groups = "unit")
+public class StreamTest {
+    /**
+     * Default test folder
+     * testFolder - empty
+     *            - file
+     *            - dir - d1
+     *                  - f1
+     *                  - lnDir2 (../dir2)
+     *            - dir2
+     *            - linkDir (./dir)
+     *            - linkFile(./file)
+     */
+    static Path testFolder;
+    static boolean supportsLinks;
+    static Path[] level1;
+    static Path[] all;
+    static Path[] all_folowLinks;
+
+    @BeforeClass
+    void setupTestFolder() throws IOException {
+        testFolder = TestUtil.createTemporaryDirectory();
+        supportsLinks = TestUtil.supportsLinks(testFolder);
+        TreeSet<Path> set = new TreeSet<>();
+
+        // Level 1
+        Path empty = testFolder.resolve("empty");
+        Path file = testFolder.resolve("file");
+        Path dir = testFolder.resolve("dir");
+        Path dir2 = testFolder.resolve("dir2");
+        Files.createDirectory(empty);
+        Files.createFile(file);
+        Files.createDirectory(dir);
+        Files.createDirectory(dir2);
+        set.add(empty);
+        set.add(file);
+        set.add(dir);
+        set.add(dir2);
+        if (supportsLinks) {
+            Path tmp = testFolder.resolve("linkDir");
+            Files.createSymbolicLink(tmp, dir);
+            set.add(tmp);
+            tmp = testFolder.resolve("linkFile");
+            Files.createSymbolicLink(tmp, file);
+            set.add(tmp);
+        }
+        level1 = set.toArray(new Path[0]);
+
+        // Level 2
+        Path tmp = dir.resolve("d1");
+        Files.createDirectory(tmp);
+        set.add(tmp);
+        tmp = dir.resolve("f1");
+        Files.createFile(tmp);
+        set.add(tmp);
+        if (supportsLinks) {
+            tmp = dir.resolve("lnDir2");
+            Files.createSymbolicLink(tmp, dir2);
+            set.add(tmp);
+        }
+        // walk include starting folder
+        set.add(testFolder);
+        all = set.toArray(new Path[0]);
+
+        // Follow links
+        if (supportsLinks) {
+            tmp = testFolder.resolve("linkDir");
+            set.add(tmp.resolve("d1"));
+            set.add(tmp.resolve("f1"));
+            tmp = tmp.resolve("lnDir2");
+            set.add(tmp);
+        }
+        all_folowLinks = set.toArray(new Path[0]);
+    }
+
+    @AfterClass
+    void cleanupTestFolder() throws IOException {
+        TestUtil.removeAll(testFolder);
+    }
+
+    public void testBasic() {
+        try (CloseableStream<Path> s = Files.list(testFolder)) {
+            Object[] actual = s.sorted(Comparators.naturalOrder()).toArray();
+            assertEquals(actual, level1);
+        } catch (IOException ioe) {
+            fail("Unexpected IOException");
+        }
+
+        try (CloseableStream<Path> s = Files.list(testFolder.resolve("empty"))) {
+            int count = s.mapToInt(p -> 1).reduce(0, Integer::sum);
+            assertEquals(count, 0, "Expect empty stream.");
+        } catch (IOException ioe) {
+            fail("Unexpected IOException");
+        }
+    }
+
+    public void testWalk() {
+        try (CloseableStream<Path> s = Files.walk(testFolder)) {
+            Object[] actual = s.sorted(Comparators.naturalOrder()).toArray();
+            assertEquals(actual, all);
+        } catch (IOException ioe) {
+            fail("Unexpected IOException");
+        }
+    }
+
+    public void testWalkOneLevel() {
+        try (CloseableStream<Path> s = Files.walk(testFolder, 1)) {
+            Object[] actual = s.filter(path -> ! path.equals(testFolder))
+                               .sorted(Comparators.naturalOrder())
+                               .toArray();
+            assertEquals(actual, level1);
+        } catch (IOException ioe) {
+            fail("Unexpected IOException");
+        }
+    }
+
+    public void testWalkFollowLink() {
+        // If link is not supported, the directory structure won't have link.
+        // We still want to test the behavior with FOLLOW_LINKS option.
+        try (CloseableStream<Path> s = Files.walk(testFolder, FileVisitOption.FOLLOW_LINKS)) {
+            Object[] actual = s.sorted(Comparators.naturalOrder()).toArray();
+            assertEquals(actual, all_folowLinks);
+        } catch (IOException ioe) {
+            fail("Unexpected IOException");
+        }
+    }
+
+    private void validateFileSystemLoopException(Path start, Path... causes) {
+        try (CloseableStream<Path> s = Files.walk(start, FileVisitOption.FOLLOW_LINKS)) {
+            try {
+                int count = s.mapToInt(p -> 1).reduce(0, Integer::sum);
+                fail("Should got FileSystemLoopException, but got " + count + "elements.");
+            } catch (UncheckedIOException uioe) {
+                IOException ioe = uioe.getCause();
+                if (ioe instanceof FileSystemLoopException) {
+                    FileSystemLoopException fsle = (FileSystemLoopException) ioe;
+                    boolean match = false;
+                    for (Path cause: causes) {
+                        if (fsle.getFile().equals(cause.toString())) {
+                            match = true;
+                            break;
+                        }
+                    }
+                    assertTrue(match);
+                } else {
+                    fail("Unexpected UncheckedIOException cause " + ioe.toString());
+                }
+            }
+        } catch(IOException ex) {
+            fail("Unexpected IOException " + ex);
+        }
+    }
+
+    public void testWalkFollowLinkLoop() {
+        if (!supportsLinks) {
+            return;
+        }
+
+        // Loops.
+        try {
+            Path dir = testFolder.resolve("dir");
+            Path linkdir = testFolder.resolve("linkDir");
+            Path d1 = dir.resolve("d1");
+            Path cause = d1.resolve("lnSelf");
+            Files.createSymbolicLink(cause, d1);
+
+            // loop in descendant.
+            validateFileSystemLoopException(dir, cause);
+            // loop in self
+            validateFileSystemLoopException(d1, cause);
+            // start from other place via link
+            validateFileSystemLoopException(linkdir,
+                    linkdir.resolve(Paths.get("d1", "lnSelf")));
+            Files.delete(cause);
+
+            // loop to parent.
+            cause = d1.resolve("lnParent");
+            Files.createSymbolicLink(cause, dir);
+
+            // loop should be detected at test/dir/d1/lnParent/d1
+            validateFileSystemLoopException(d1, cause.resolve("d1"));
+            // loop should be detected at link
+            validateFileSystemLoopException(dir, cause);
+            // loop should be detected at test/linkdir/d1/lnParent
+            // which is test/dir we have visited via test/linkdir
+            validateFileSystemLoopException(linkdir,
+                    linkdir.resolve(Paths.get("d1", "lnParent")));
+            Files.delete(cause);
+
+            // cross loop
+            Path dir2 = testFolder.resolve("dir2");
+            cause = dir2.resolve("lnDir");
+            Files.createSymbolicLink(cause, dir);
+            validateFileSystemLoopException(dir,
+                    dir.resolve(Paths.get("lnDir2", "lnDir")));
+            validateFileSystemLoopException(dir2,
+                    dir2.resolve(Paths.get("lnDir", "lnDir2")));
+            validateFileSystemLoopException(linkdir,
+                    linkdir.resolve(Paths.get("lnDir2", "lnDir")));
+        } catch(IOException ioe) {
+            fail("Unexpected IOException " + ioe);
+        }
+    }
+
+    private static class PathBiPredicate implements BiPredicate<Path, BasicFileAttributes> {
+        private final BiPredicate<Path, BasicFileAttributes> pred;
+        private final Set<Path> visited = new TreeSet<Path>();
+
+        PathBiPredicate(BiPredicate<Path, BasicFileAttributes> pred) {
+            this.pred = Objects.requireNonNull(pred);
+        }
+
+        public boolean test(Path path, BasicFileAttributes attrs) {
+            visited.add(path);
+            return pred.test(path, attrs);
+        }
+
+        public Path[] visited() {
+            return visited.toArray(new Path[0]);
+        }
+    }
+
+    public void testFind() throws IOException {
+        PathBiPredicate pred = new PathBiPredicate((path, attrs) -> true);
+
+        try (CloseableStream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
+            Set<Path> result = s.collect(Collectors.toCollection(TreeSet::new));
+            assertEquals(pred.visited(), all);
+            assertEquals(result.toArray(new Path[0]), pred.visited());
+        }
+
+        pred = new PathBiPredicate((path, attrs) -> attrs.isSymbolicLink());
+        try (CloseableStream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
+            s.forEach(path -> assertTrue(Files.isSymbolicLink(path)));
+            assertEquals(pred.visited(), all);
+        }
+
+        pred = new PathBiPredicate((path, attrs) ->
+            path.getFileName().toString().startsWith("e"));
+        try (CloseableStream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
+            s.forEach(path -> assertEquals(path.getFileName().toString(), "empty"));
+            assertEquals(pred.visited(), all);
+        }
+
+        pred = new PathBiPredicate((path, attrs) ->
+            path.getFileName().toString().startsWith("l") && attrs.isRegularFile());
+        try (CloseableStream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
+            s.forEach(path -> fail("Expect empty stream"));
+            assertEquals(pred.visited(), all);
+        }
+    }
+
+    // Test borrowed from BytesAndLines
+    public void testLines() throws IOException {
+        final Charset US_ASCII = Charset.forName("US-ASCII");
+        Path tmpfile = Files.createTempFile("blah", "txt");
+
+        try {
+            // zero lines
+            assertTrue(Files.size(tmpfile) == 0, "File should be empty");
+            try (CloseableStream<String> s = Files.lines(tmpfile, US_ASCII)) {
+                assertEquals(s.mapToInt(l -> 1).reduce(0, Integer::sum), 0, "No line expected");
+            }
+
+            // one line
+            byte[] hi = { (byte)'h', (byte)'i' };
+            Files.write(tmpfile, hi);
+            try (CloseableStream<String> s = Files.lines(tmpfile, US_ASCII)) {
+                List<String> lines = s.collect(Collectors.toList());
+                assertTrue(lines.size() == 1, "One line expected");
+                assertTrue(lines.get(0).equals("hi"), "'Hi' expected");
+            }
+
+            // two lines using platform's line separator
+            List<String> expected = Arrays.asList("hi", "there");
+            Files.write(tmpfile, expected, US_ASCII);
+            assertTrue(Files.size(tmpfile) > 0, "File is empty");
+            try (CloseableStream<String> s = Files.lines(tmpfile, US_ASCII)) {
+                List<String> lines = s.collect(Collectors.toList());
+                assertTrue(lines.equals(expected), "Unexpected lines");
+            }
+
+            // MalformedInputException
+            byte[] bad = { (byte)0xff, (byte)0xff };
+            Files.write(tmpfile, bad);
+            try (CloseableStream<String> s = Files.lines(tmpfile, US_ASCII)) {
+                try {
+                    List<String> lines = s.collect(Collectors.toList());
+                    throw new RuntimeException("UncheckedIOException expected");
+                } catch (UncheckedIOException ex) {
+                    assertTrue(ex.getCause() instanceof MalformedInputException,
+                               "MalformedInputException expected");
+                }
+            }
+
+            // NullPointerException
+            try {
+                Files.lines(null, US_ASCII);
+                throw new RuntimeException("NullPointerException expected");
+            } catch (NullPointerException ignore) { }
+            try {
+                Files.lines(tmpfile, null);
+                throw new RuntimeException("NullPointerException expected");
+            } catch (NullPointerException ignore) { }
+
+        } finally {
+            Files.delete(tmpfile);
+        }
+    }
+
+    public void testDirectoryIteratorException() throws IOException {
+        Path dir = testFolder.resolve("dir2");
+        Path trigger = dir.resolve("DirectoryIteratorException");
+        Files.createFile(trigger);
+        FaultyFileSystem.FaultyFSProvider fsp = FaultyFileSystem.FaultyFSProvider.getInstance();
+        FaultyFileSystem fs = (FaultyFileSystem) fsp.newFileSystem(dir, null);
+
+        try {
+            fsp.setFaultyMode(false);
+            Path fakeRoot = fs.getRoot();
+            try {
+                try (CloseableStream<Path> s = Files.list(fakeRoot)) {
+                    s.forEach(path -> assertEquals(path.getFileName().toString(), "DirectoryIteratorException"));
+                }
+            } catch (UncheckedIOException uioe) {
+                fail("Unexpected exception.");
+            }
+
+            fsp.setFaultyMode(true);
+            try {
+                try (DirectoryStream<Path> ds = Files.newDirectoryStream(fakeRoot)) {
+                    Iterator<Path> itor = ds.iterator();
+                    while (itor.hasNext()) {
+                        itor.next();
+                    }
+                }
+                fail("Shoule throw DirectoryIteratorException");
+            } catch (DirectoryIteratorException die) {
+            }
+
+            try {
+                try (CloseableStream<Path> s = Files.list(fakeRoot)) {
+                    s.forEach(path -> fail("should not get here"));
+                }
+            } catch (UncheckedIOException uioe) {
+                assertTrue(uioe.getCause() instanceof FaultyFileSystem.FaultyException);
+            } catch (DirectoryIteratorException die) {
+                fail("Should have been converted into UncheckedIOException.");
+            }
+        } finally {
+            // Cleanup
+            if (fs != null) {
+                fs.close();
+            }
+            Files.delete(trigger);
+        }
+    }
+
+    public void testUncheckedIOException() throws IOException {
+        Path triggerFile = testFolder.resolve(Paths.get("dir2", "IOException"));
+        Files.createFile(triggerFile);
+        Path triggerDir = testFolder.resolve(Paths.get("empty", "IOException"));
+        Files.createDirectories(triggerDir);
+        Files.createFile(triggerDir.resolve("file"));
+        FaultyFileSystem.FaultyFSProvider fsp = FaultyFileSystem.FaultyFSProvider.getInstance();
+        FaultyFileSystem fs = (FaultyFileSystem) fsp.newFileSystem(testFolder, null);
+
+        try {
+            fsp.setFaultyMode(false);
+            Path fakeRoot = fs.getRoot();
+            try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
+                // only one file
+                s.forEach(path -> assertEquals(path.getFileName().toString(), "IOException"));
+            }
+
+            try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
+                String[] result = s.map(path -> path.getFileName().toString())
+                                   .toArray(String[]::new);
+                // ordered as depth-first
+                assertEquals(result, new String[] { "empty", "IOException", "file"});
+            }
+
+            fsp.setFaultyMode(true);
+            try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
+                s.forEach(path -> fail("should have caused exception"));
+            } catch (UncheckedIOException uioe) {
+                assertTrue(uioe.getCause() instanceof FaultyFileSystem.FaultyException);
+            }
+
+            try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
+                String[] result = s.map(path -> path.getFileName().toString())
+                                   .toArray(String[]::new);
+                fail("should not reach here due to IOException");
+            } catch (UncheckedIOException uioe) {
+                assertTrue(uioe.getCause() instanceof FaultyFileSystem.FaultyException);
+            }
+
+            try (CloseableStream<Path> s = Files.walk(
+                fakeRoot.resolve("empty").resolve("IOException")))
+            {
+                String[] result = s.map(path -> path.getFileName().toString())
+                                   .toArray(String[]::new);
+                fail("should not reach here due to IOException");
+            } catch (IOException ioe) {
+                assertTrue(ioe instanceof FaultyFileSystem.FaultyException);
+            } catch (UncheckedIOException ex) {
+                fail("Top level should be repored as is");
+            }
+         } finally {
+            // Cleanup
+            if (fs != null) {
+                fs.close();
+            }
+            Files.delete(triggerFile);
+            TestUtil.removeAll(triggerDir);
+        }
+    }
+
+    public void testSecurityException() throws IOException {
+        Path empty = testFolder.resolve("empty");
+        Path triggerFile = Files.createFile(empty.resolve("SecurityException"));
+        Path sampleFile = Files.createDirectories(empty.resolve("sample"));
+
+        Path dir2 = testFolder.resolve("dir2");
+        Path triggerDir = Files.createDirectories(dir2.resolve("SecurityException"));
+        Files.createFile(triggerDir.resolve("fileInSE"));
+        Path sample = Files.createFile(dir2.resolve("file"));
+
+        Path triggerLink = null;
+        Path linkTriggerDir = null;
+        Path linkTriggerFile = null;
+        if (supportsLinks) {
+            Path dir = testFolder.resolve("dir");
+            triggerLink = Files.createSymbolicLink(dir.resolve("SecurityException"), empty);
+            linkTriggerDir = Files.createSymbolicLink(dir.resolve("lnDirSE"), triggerDir);
+            linkTriggerFile = Files.createSymbolicLink(dir.resolve("lnFileSE"), triggerFile);
+        }
+
+        FaultyFileSystem.FaultyFSProvider fsp = FaultyFileSystem.FaultyFSProvider.getInstance();
+        FaultyFileSystem fs = (FaultyFileSystem) fsp.newFileSystem(testFolder, null);
+
+        try {
+            fsp.setFaultyMode(false);
+            Path fakeRoot = fs.getRoot();
+            // validate setting
+            try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("empty"))) {
+                String[] result = s.map(path -> path.getFileName().toString())
+                                   .toArray(String[]::new);
+                assertEqualsNoOrder(result, new String[] { "SecurityException", "sample" });
+            }
+
+            try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("dir2"))) {
+                String[] result = s.map(path -> path.getFileName().toString())
+                                   .toArray(String[]::new);
+                assertEqualsNoOrder(result, new String[] { "dir2", "SecurityException", "fileInSE", "file" });
+            }
+
+            if (supportsLinks) {
+                try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("dir"))) {
+                    String[] result = s.map(path -> path.getFileName().toString())
+                                       .toArray(String[]::new);
+                    assertEqualsNoOrder(result, new String[] { "d1", "f1", "lnDir2", "SecurityException", "lnDirSE", "lnFileSE" });
+                }
+            }
+
+            // execute test
+            fsp.setFaultyMode(true);
+            // ignore file cause SecurityException
+            try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
+                String[] result = s.map(path -> path.getFileName().toString())
+                                   .toArray(String[]::new);
+                assertEqualsNoOrder(result, new String[] { "empty", "sample" });
+            }
+            // skip folder cause SecurityException
+            try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("dir2"))) {
+                String[] result = s.map(path -> path.getFileName().toString())
+                                   .toArray(String[]::new);
+                assertEqualsNoOrder(result, new String[] { "dir2", "file" });
+            }
+
+            if (supportsLinks) {
+                // not following links
+                try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("dir"))) {
+                    String[] result = s.map(path -> path.getFileName().toString())
+                                       .toArray(String[]::new);
+                    assertEqualsNoOrder(result, new String[] { "dir", "d1", "f1", "lnDir2", "lnDirSE", "lnFileSE" });
+                }
+
+                // following links
+                try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("dir"), FileVisitOption.FOLLOW_LINKS)) {
+                    String[] result = s.map(path -> path.getFileName().toString())
+                                       .toArray(String[]::new);
+                    // ?? Should fileInSE show up?
+                    // With FaultyFS, it does as no exception thrown for link to "SecurityException" with read on "lnXxxSE"
+                    assertEqualsNoOrder(result, new String[] { "dir", "d1", "f1", "lnDir2", "file", "lnDirSE", "lnFileSE", "fileInSE" });
+                }
+            }
+
+            // list instead of walk
+            try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("empty"))) {
+                String[] result = s.map(path -> path.getFileName().toString())
+                                   .toArray(String[]::new);
+                assertEqualsNoOrder(result, new String[] { "sample" });
+            }
+            try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
+                String[] result = s.map(path -> path.getFileName().toString())
+                                   .toArray(String[]::new);
+                assertEqualsNoOrder(result, new String[] { "file" });
+            }
+
+            // root cause SecurityException should be reported
+            try (CloseableStream<Path> s = Files.walk(
+                fakeRoot.resolve("dir2").resolve("SecurityException")))
+            {
+                String[] result = s.map(path -> path.getFileName().toString())
+                                   .toArray(String[]::new);
+                fail("should not reach here due to SecurityException");
+            } catch (SecurityException se) {
+                assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException);
+            }
+
+            // Walk a file cause SecurityException, we should get SE
+            try (CloseableStream<Path> s = Files.walk(
+                fakeRoot.resolve("dir").resolve("SecurityException")))
+            {
+                String[] result = s.map(path -> path.getFileName().toString())
+                                   .toArray(String[]::new);
+                fail("should not reach here due to SecurityException");
+            } catch (SecurityException se) {
+                assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException);
+            }
+
+            // List a file cause SecurityException, we should get SE as cannot read attribute
+            try (CloseableStream<Path> s = Files.list(
+                fakeRoot.resolve("dir2").resolve("SecurityException")))
+            {
+                String[] result = s.map(path -> path.getFileName().toString())
+                                   .toArray(String[]::new);
+                fail("should not reach here due to SecurityException");
+            } catch (SecurityException se) {
+                assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException);
+            }
+
+            try (CloseableStream<Path> s = Files.list(
+                fakeRoot.resolve("dir").resolve("SecurityException")))
+            {
+                String[] result = s.map(path -> path.getFileName().toString())
+                                   .toArray(String[]::new);
+                fail("should not reach here due to SecurityException");
+            } catch (SecurityException se) {
+                assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException);
+            }
+         } finally {
+            // Cleanup
+            if (fs != null) {
+                fs.close();
+            }
+            if (supportsLinks) {
+                Files.delete(triggerLink);
+                Files.delete(linkTriggerDir);
+                Files.delete(linkTriggerFile);
+            }
+            Files.delete(triggerFile);
+            Files.delete(sampleFile);
+            Files.delete(sample);
+            TestUtil.removeAll(triggerDir);
+        }
+    }
+
+    public void testConstructException() {
+        try (CloseableStream<String> s = Files.lines(testFolder.resolve("notExist"), Charset.forName("UTF-8"))) {
+            s.forEach(l -> fail("File is not even exist!"));
+        } catch (IOException ioe) {
+            assertTrue(ioe instanceof NoSuchFileException);
+        }
+    }
+
+    public void testClosedStream() throws IOException {
+        try (CloseableStream<Path> s = Files.list(testFolder)) {
+            s.close();
+            Object[] actual = s.sorted(Comparators.naturalOrder()).toArray();
+            assertTrue(actual.length <= level1.length);
+        }
+
+        try (CloseableStream<Path> s = Files.walk(testFolder)) {
+            s.close();
+            Object[] actual = s.sorted(Comparators.naturalOrder()).toArray();
+            fail("Operate on closed stream should throw IllegalStateException");
+        } catch (IllegalStateException ex) {
+            // expected
+        }
+
+        try (CloseableStream<Path> s = Files.find(testFolder, Integer.MAX_VALUE,
+                    (p, attr) -> true)) {
+            s.close();
+            Object[] actual = s.sorted(Comparators.naturalOrder()).toArray();
+            fail("Operate on closed stream should throw IllegalStateException");
+        } catch (IllegalStateException ex) {
+            // expected
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/security/AccessController/LimitedDoPrivileged.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,215 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8014097
+ * @summary Test the limited privilege scope version of doPrivileged
+ */
+
+import java.security.*;
+import java.util.*;
+
+public class LimitedDoPrivileged {
+    /*
+     * Test variations of doPrivileged() and doPrivileged() with a limited privilege scope
+     * in a sandbox with the usual default permission to read the system properties for the
+     * file and path separators.
+     *
+     * By passing in an "assigned" AccessControlContext that has
+     * no default permissions we can test how code privileges are being scoped.
+     */
+
+    private static final ProtectionDomain domain =
+        new ProtectionDomain(null, null, null, null);
+    private static final AccessControlContext acc =
+        new AccessControlContext(new ProtectionDomain[] { domain });
+    private static final PropertyPermission pathPerm =
+        new PropertyPermission("path.separator", "read");
+    private static final PropertyPermission filePerm =
+        new PropertyPermission("file.separator", "read");
+
+    public static void main(String[] args) throws Exception {
+        /*
+         * Verify that we have the usual default property read permission.
+         */
+        AccessController.getContext().checkPermission(filePerm);
+        AccessController.getContext().checkPermission(pathPerm);
+        System.out.println("test 1 passed");
+
+        /*
+         * Inject the "no permission" AccessControlContext.
+         */
+        AccessController.doPrivileged(new PrivilegedAction() {
+            public Object run() {
+
+                /*
+                 * Verify that we no longer have the "file.separator" permission.
+                 */
+                try {
+                    AccessController.getContext().checkPermission(pathPerm);
+                } catch (AccessControlException ace) {
+                    System.out.println("test 2 passed");
+                }
+
+                /*
+                 * Verify that we can give ourselves limited privilege to read
+                 * any system property starting with "path.".
+                 */
+                AccessController.doPrivileged
+                    (new PrivilegedAction() {
+                        public Object run() {
+                            AccessController.getContext().checkPermission(pathPerm);
+                            return null;
+                        }
+                }, null, new PropertyPermission("path.*", "read"));
+                System.out.println("test 3 passed");
+
+                /*
+                 * Verify that if we give ourselves limited privilege to read
+                 * any system property starting with "path." it won't give us the
+                 * the ability to read "file.separator".
+                 */
+                try {
+                    AccessController.doPrivileged
+                        (new PrivilegedAction() {
+                            public Object run() {
+                                AccessController.getContext().checkPermission(filePerm);
+                                return null;
+                            }
+                    }, null, new PropertyPermission("path.*", "read"));
+                } catch (AccessControlException ace) {
+                    System.out.println("test 4 passed");
+                }
+
+                /*
+                 * Verify that capturing and passing in the context with no default
+                 * system property permission grants will prevent access that succeeded
+                 * earlier without the context assignment.
+                 */
+                final AccessControlContext context = AccessController.getContext();
+                try {
+                    AccessController.doPrivileged
+                        (new PrivilegedAction() {
+                            public Object run() {
+                                AccessController.getContext().checkPermission(pathPerm);
+                                return null;
+                            }
+                    }, context, new PropertyPermission("path.*", "read"));
+                } catch (AccessControlException ace) {
+                    System.out.println("test 5 passed");
+                }
+
+                /*
+                 * Verify that we can give ourselves full privilege to read
+                 * any system property starting with "path.".
+                 */
+                AccessController.doPrivileged
+                     (new PrivilegedAction() {
+                        public Object run() {
+                            AccessController.getContext().checkPermission(pathPerm);
+                            return null;
+                        }
+                });
+                System.out.println("test 6 passed");
+
+                /*
+                 * Verify that capturing and passing in the context with no default
+                 * system property permission grants will prevent access that succeeded
+                 * earlier without the context assignment.
+                 */
+                try {
+                    AccessController.doPrivileged
+                        (new PrivilegedAction() {
+                            public Object run() {
+                                AccessController.getContext().checkPermission(pathPerm);
+                                return null;
+                            }
+                    }, context);
+                } catch (AccessControlException ace) {
+                    System.out.println("test 7 passed");
+                }
+
+                /*
+                 * Verify that we can give ourselves limited privilege to read
+                 * any system property starting with "path." when a limited
+                 * privilege scope context is captured and passed to a regular
+                 * doPrivileged() as an assigned context.
+                 */
+                AccessController.doPrivileged
+                     (new PrivilegedAction() {
+                        public Object run() {
+
+                            /*
+                             * Capture the limited privilege scope and inject it into the
+                             * regular doPrivileged().
+                             */
+                            final AccessControlContext limitedContext = AccessController.getContext();
+                            AccessController.doPrivileged
+                                (new PrivilegedAction() {
+                                    public Object run() {
+                                        AccessController.getContext().checkPermission(pathPerm);
+                                        return null;
+                                }
+                            }, limitedContext);
+                            return null;
+                        }
+                }, null, new PropertyPermission("path.*", "read"));
+                System.out.println("test 8 passed");
+
+                /*
+                 * Verify that we can give ourselves limited privilege to read
+                 * any system property starting with "path." it won't give us the
+                 * the ability to read "file.separator" when a limited
+                 * privilege scope context is captured and passed to a regular
+                 * doPrivileged() as an assigned context.
+                 */
+                AccessController.doPrivileged
+                     (new PrivilegedAction() {
+                        public Object run() {
+
+                            /*
+                             * Capture the limited privilege scope and inject it into the
+                             * regular doPrivileged().
+                             */
+                            final AccessControlContext limitedContext = AccessController.getContext();
+                            try {
+                                AccessController.doPrivileged
+                                    (new PrivilegedAction() {
+                                        public Object run() {
+                                            AccessController.getContext().checkPermission(filePerm);
+                                            return null;
+                                    }
+                                }, limitedContext);
+                            } catch (AccessControlException ace) {
+                                System.out.println("test 9 passed");
+                            }
+                            return null;
+                        }
+                }, null, new PropertyPermission("path.*", "read"));
+
+                return null;
+            }
+        }, acc);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/text/Format/DateFormat/Bug7177315.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+/**
+ * @test
+ * @bug 7177315
+ * @summary Make sure that space characters are properly skipped when
+ *          parsing 2-digit year values.
+ */
+
+import java.text.*;
+import java.util.*;
+
+public class Bug7177315 {
+    private static final String EXPECTED = "01/01/2012";
+    private static final String[] DATA = {
+        "01/01/12",
+        "01/01/ 12",
+        "01/01/       12",
+        "1/1/12",
+        "1/1/  12"
+    };
+
+    public static void main (String[] args) throws ParseException {
+        SimpleDateFormat parseFormat = new SimpleDateFormat("MM/dd/yy", Locale.US);
+        Calendar cal = new GregorianCalendar(2012-80, Calendar.JANUARY, 1);
+        parseFormat.set2DigitYearStart(cal.getTime());
+        SimpleDateFormat fmtFormat = new SimpleDateFormat("MM/dd/yyyy", Locale.US);
+
+        for (String text : DATA) {
+            Date date = parseFormat.parse(text);
+            String got = fmtFormat.format(date);
+            if (!EXPECTED.equals(got)) {
+                throw new RuntimeException("got: " + got + ", expected: " + EXPECTED);
+            }
+        }
+    }
+}
--- a/jdk/test/java/text/Format/DateFormat/WeekDateTest.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/text/Format/DateFormat/WeekDateTest.java	Mon Jun 10 10:38:33 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,8 +32,8 @@
 import static java.util.GregorianCalendar.*;
 
 public class WeekDateTest {
-    static SimpleDateFormat ymdFormat = new SimpleDateFormat("yyyy-MM-dd");
-    static SimpleDateFormat ywdFormat = new SimpleDateFormat("YYYY-'W'ww-u");
+    static SimpleDateFormat ymdFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
+    static SimpleDateFormat ywdFormat = new SimpleDateFormat("YYYY-'W'ww-u", Locale.US);
     static {
         ymdFormat.setCalendar(newCalendar());
         ywdFormat.setCalendar(newCalendar());
--- a/jdk/test/java/util/Arrays/ParallelSorting.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/util/Arrays/ParallelSorting.java	Mon Jun 10 10:38:33 2013 +0100
@@ -50,11 +50,11 @@
 
     // Array lengths used in a long run (default)
     private static final int[] LONG_RUN_LENGTHS = {
-        1, 2, 3, 5, 8, 13, 21, 34, 55, 100, 1000, 10000, 100000, 1000000 };
+        1000, 10000, 100000, 1000000 };
 
     // Array lengths used in a short run
     private static final int[] SHORT_RUN_LENGTHS = {
-        1, 2, 3, 21, 55, 1000, 10000 };
+        5000, 9000, 10000, 12000 };
 
     // Random initial values used in a long run (default)
     private static final long[] LONG_RUN_RANDOMS = { 666, 0xC0FFEE, 999 };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Iterator/PrimitiveIteratorDefaults.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,115 @@
+/*
+ * 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 org.testng.annotations.Test;
+
+import java.util.PrimitiveIterator;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * @test
+ * @run testng PrimitiveIteratorDefaults
+ * @summary test default methods on PrimitiveIterator
+ */
+@Test
+public class PrimitiveIteratorDefaults {
+
+    public void testIntForEachRemainingWithNull() {
+        PrimitiveIterator.OfInt i = new PrimitiveIterator.OfInt() {
+            @Override
+            public int nextInt() {
+                return 0;
+            }
+
+            @Override
+            public boolean hasNext() {
+                return false;
+            }
+        };
+
+        executeAndCatch(() -> i.forEachRemaining((IntConsumer) null));
+        executeAndCatch(() -> i.forEachRemaining((Consumer<Integer>) null));
+    }
+
+    public void testLongForEachRemainingWithNull() {
+        PrimitiveIterator.OfLong i = new PrimitiveIterator.OfLong() {
+            @Override
+            public long nextLong() {
+                return 0;
+            }
+
+            @Override
+            public boolean hasNext() {
+                return false;
+            }
+        };
+
+        executeAndCatch(() -> i.forEachRemaining((LongConsumer) null));
+        executeAndCatch(() -> i.forEachRemaining((Consumer<Long>) null));
+    }
+
+    public void testDoubleForEachRemainingWithNull() {
+        PrimitiveIterator.OfDouble i = new PrimitiveIterator.OfDouble() {
+            @Override
+            public double nextDouble() {
+                return 0;
+            }
+
+            @Override
+            public boolean hasNext() {
+                return false;
+            }
+        };
+
+        executeAndCatch(() -> i.forEachRemaining((DoubleConsumer) null));
+        executeAndCatch(() -> i.forEachRemaining((Consumer<Double>) null));
+    }
+
+    private void executeAndCatch(Runnable r) {
+        executeAndCatch(NullPointerException.class, r);
+    }
+
+    private void executeAndCatch(Class<? extends Exception> expected, Runnable r) {
+        Exception caught = null;
+        try {
+            r.run();
+        }
+        catch (Exception e) {
+            caught = e;
+        }
+
+        assertNotNull(caught,
+                      String.format("No Exception was thrown, expected an Exception of %s to be thrown",
+                                    expected.getName()));
+        assertTrue(expected.isInstance(caught),
+                   String.format("Exception thrown %s not an instance of %s",
+                                 caught.getClass().getName(), expected.getName()));
+    }
+
+}
--- a/jdk/test/java/util/Locale/LocaleCategory.sh	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/util/Locale/LocaleCategory.sh	Mon Jun 10 10:38:33 2013 +0100
@@ -1,3 +1,4 @@
+#!/bin/sh
 #
 # Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -20,7 +21,6 @@
 # or visit www.oracle.com if you need additional information or have any
 # questions.
 #
-#!/bin/sh
 #
 # @test
 # @bug 4700857 6997928 7079486
--- a/jdk/test/java/util/Locale/LocaleProviders.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/util/Locale/LocaleProviders.java	Mon Jun 10 10:38:33 2013 +0100
@@ -64,6 +64,10 @@
                 bug8013086Test(args[1], args[2]);
                 break;
 
+            case "bug8013903Test":
+                bug8013903Test();
+                break;
+
             default:
                 throw new RuntimeException("Test method '"+methodName+"' not found.");
         }
@@ -195,4 +199,30 @@
             // ParseException is fine in this test, as it's not "UTC"
 }
     }
+
+    static void bug8013903Test() {
+        if (System.getProperty("os.name").startsWith("Windows")) {
+            Date sampleDate = new Date(0x10000000000L);
+            String fallbackResult = "Heisei 16.Nov.03 (Wed) AM 11:53:47";
+            String jreResult = "\u5e73\u6210 16.11.03 (\u6c34) \u5348\u524d 11:53:47";
+            Locale l = new Locale("ja", "JP", "JP");
+            SimpleDateFormat sdf = new SimpleDateFormat("GGGG yyyy.MMM.dd '('E')' a hh:mm:ss", l);
+            String result = sdf.format(sampleDate);
+            System.out.println(result);
+            if (LocaleProviderAdapter.getAdapterPreference()
+                .contains(LocaleProviderAdapter.Type.JRE)) {
+                if (!jreResult.equals(result)) {
+                    throw new RuntimeException("Format failed. result: \"" +
+                        result + "\", expected: \"" + jreResult);
+                }
+            } else {
+                // should be FALLBACK, as Windows HOST does not return
+                // display names
+                if (!fallbackResult.equals(result)) {
+                    throw new RuntimeException("Format failed. result: \"" +
+                        result + "\", expected: \"" + fallbackResult);
+                }
+            }
+        }
+    }
 }
--- a/jdk/test/java/util/Locale/LocaleProviders.sh	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/util/Locale/LocaleProviders.sh	Mon Jun 10 10:38:33 2013 +0100
@@ -1,3 +1,4 @@
+#!/bin/sh
 #
 # Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -20,11 +21,10 @@
 # or visit www.oracle.com if you need additional information or have any
 # questions.
 #
-#!/bin/sh
 #
 # @test
 # @bug 6336885 7196799 7197573 7198834 8000245 8000615 8001440 8010666
-#      8013086 8013233
+#      8013086 8013233 8013903
 # @summary tests for "java.locale.providers" system property
 # @compile -XDignore.symbol.file LocaleProviders.java
 # @run shell/timeout=600 LocaleProviders.sh
@@ -300,4 +300,18 @@
 PARAM3=
 runTest
 
+# testing 8013903 fix. (Windows only)
+METHODNAME=bug8013903Test
+PREFLIST=HOST,JRE
+PARAM1=
+PARAM2=
+PARAM3=
+runTest
+METHODNAME=bug8013903Test
+PREFLIST=HOST
+PARAM1=
+PARAM2=
+PARAM3=
+runTest
+
 exit $result
--- a/jdk/test/java/util/Locale/data/deflocale.sh	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/util/Locale/data/deflocale.sh	Mon Jun 10 10:38:33 2013 +0100
@@ -1,3 +1,4 @@
+#!/bin/sh
 # 
 # Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -20,7 +21,6 @@
 # or visit www.oracle.com if you need additional information or have any
 # questions.
 #
-#!/bin/sh
 #
 #
 #
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Map/CheckRandomHashSeed.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+/**
+ * @test
+ * @bug 8005698
+ * @summary Check operation of jdk.map.useRandomSeed property
+ * @run main CheckRandomHashSeed
+ * @run main/othervm -Djdk.map.useRandomSeed=false CheckRandomHashSeed
+ * @run main/othervm -Djdk.map.useRandomSeed=bogus CheckRandomHashSeed
+ * @run main/othervm -Djdk.map.useRandomSeed=true CheckRandomHashSeed true
+ * @author Brent Christian
+ */
+import java.lang.reflect.Field;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Hashtable;
+import java.util.WeakHashMap;
+
+public class CheckRandomHashSeed {
+    private final static String PROP_NAME = "jdk.map.useRandomSeed";
+    static boolean expectRandom = false;
+
+    public static void main(String[] args) {
+        if (args.length > 0 && args[0].equals("true")) {
+            expectRandom = true;
+        }
+        String hashSeedProp = System.getProperty(PROP_NAME);
+        boolean propSet = (null != hashSeedProp)
+                ? Boolean.parseBoolean(hashSeedProp) : false;
+        if (expectRandom != propSet) {
+            throw new Error("Error in test setup: " + (expectRandom ? "" : "not " ) + "expecting random hashSeed, but " + PROP_NAME + " is " + (propSet ? "" : "not ") + "enabled");
+        }
+
+        testMap(new HashMap());
+        testMap(new LinkedHashMap());
+        testMap(new WeakHashMap());
+        testMap(new Hashtable());
+    }
+
+    private static void testMap(Map map) {
+        int hashSeed = getHashSeed(map);
+        boolean hashSeedIsZero = (hashSeed == 0);
+
+        if (expectRandom != hashSeedIsZero) {
+            System.out.println("Test passed for " + map.getClass().getSimpleName() + " - expectRandom: " + expectRandom + ", hashSeed: " + hashSeed);
+        } else {
+            throw new Error ("Test FAILED for " + map.getClass().getSimpleName() + " -  expectRandom: " + expectRandom + ", hashSeed: " + hashSeed);
+        }
+    }
+
+    private static int getHashSeed(Map map) {
+        try {
+            if (map instanceof HashMap || map instanceof LinkedHashMap) {
+                map.put("Key", "Value");
+                Field hashSeedField = HashMap.class.getDeclaredField("hashSeed");
+                hashSeedField.setAccessible(true);
+                int hashSeed = hashSeedField.getInt(map);
+                return hashSeed;
+            } else {
+                map.put("Key", "Value");
+                Field hashSeedField = map.getClass().getDeclaredField("hashSeed");
+                hashSeedField.setAccessible(true);
+                int hashSeed = hashSeedField.getInt(map);
+                return hashSeed;
+            }
+        } catch(Exception e) {
+            e.printStackTrace();
+            throw new Error(e);
+        }
+    }
+}
--- a/jdk/test/java/util/Map/Collisions.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/util/Map/Collisions.java	Mon Jun 10 10:38:33 2013 +0100
@@ -26,6 +26,7 @@
  * @bug 7126277
  * @run main Collisions -shortrun
  * @run main/othervm -Djdk.map.althashing.threshold=0 Collisions -shortrun
+ * @run main/othervm -Djdk.map.useRandomSeed=true Collisions -shortrun
  * @summary Ensure Maps behave well with lots of hashCode() collisions.
  * @author Mike Duigou
  */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Map/InPlaceOpsCollisions.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,665 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8005698
+ * @run main InPlaceOpsCollisions -shortrun
+ * @run main/othervm -Djdk.map.randomseed=true InPlaceOpsCollisions -shortrun
+ * @summary Ensure overrides of in-place operations in Maps behave well with lots of collisions.
+ * @author Brent Christian
+ */
+import java.util.*;
+import java.util.function.*;
+
+public class InPlaceOpsCollisions {
+
+    /**
+     * Number of elements per map.
+     */
+    private static final int TEST_SIZE = 5000;
+
+    final static class HashableInteger implements Comparable<HashableInteger> {
+
+        final int value;
+        final int hashmask; //yes duplication
+
+        HashableInteger(int value, int hashmask) {
+            this.value = value;
+            this.hashmask = hashmask;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof HashableInteger) {
+                HashableInteger other = (HashableInteger) obj;
+
+                return other.value == value;
+            }
+
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return value % hashmask;
+        }
+
+        @Override
+        public int compareTo(HashableInteger o) {
+            return value - o.value;
+        }
+
+        @Override
+        public String toString() {
+            return Integer.toString(value);
+        }
+    }
+
+    static HashableInteger EXTRA_INT_VAL;
+    static String EXTRA_STRING_VAL;
+
+    private static Object[][] makeTestData(int size) {
+        HashableInteger UNIQUE_OBJECTS[] = new HashableInteger[size];
+        HashableInteger COLLIDING_OBJECTS[] = new HashableInteger[size];
+        String UNIQUE_STRINGS[] = new String[size];
+        String COLLIDING_STRINGS[] = new String[size];
+
+        for (int i = 0; i < size; i++) {
+            UNIQUE_OBJECTS[i] = new HashableInteger(i, Integer.MAX_VALUE);
+            COLLIDING_OBJECTS[i] = new HashableInteger(i, 10);
+            UNIQUE_STRINGS[i] = unhash(i);
+            COLLIDING_STRINGS[i] = (0 == i % 2)
+                    ? UNIQUE_STRINGS[i / 2]
+                    : "\u0000\u0000\u0000\u0000\u0000" + COLLIDING_STRINGS[i - 1];
+        }
+        EXTRA_INT_VAL = new HashableInteger(size, Integer.MAX_VALUE);
+        EXTRA_STRING_VAL = new String ("Extra Value");
+
+     return new Object[][] {
+            new Object[]{"Unique Objects", UNIQUE_OBJECTS},
+            new Object[]{"Colliding Objects", COLLIDING_OBJECTS},
+            new Object[]{"Unique Strings", UNIQUE_STRINGS},
+            new Object[]{"Colliding Strings", COLLIDING_STRINGS}
+        };
+    }
+
+    /**
+     * Returns a string with a hash equal to the argument.
+     *
+     * @return string with a hash equal to the argument.
+     */
+    public static String unhash(int target) {
+        StringBuilder answer = new StringBuilder();
+        if (target < 0) {
+            // String with hash of Integer.MIN_VALUE, 0x80000000
+            answer.append("\\u0915\\u0009\\u001e\\u000c\\u0002");
+
+            if (target == Integer.MIN_VALUE) {
+                return answer.toString();
+            }
+            // Find target without sign bit set
+            target = target & Integer.MAX_VALUE;
+        }
+
+        unhash0(answer, target);
+        return answer.toString();
+    }
+
+    private static void unhash0(StringBuilder partial, int target) {
+        int div = target / 31;
+        int rem = target % 31;
+
+        if (div <= Character.MAX_VALUE) {
+            if (div != 0) {
+                partial.append((char) div);
+            }
+            partial.append((char) rem);
+        } else {
+            unhash0(partial, div);
+            partial.append((char) rem);
+        }
+    }
+
+    private static void realMain(String[] args) throws Throwable {
+        boolean shortRun = args.length > 0 && args[0].equals("-shortrun");
+
+        Object[][] mapKeys = makeTestData(shortRun ? (TEST_SIZE / 2) : TEST_SIZE);
+
+        // loop through data sets
+        for (Object[] keys_desc : mapKeys) {
+            Map<Object, Object>[] maps = (Map<Object, Object>[]) new Map[]{
+                        new HashMap<>(),
+                        new LinkedHashMap<>(),
+                    };
+
+            // for each map type.
+            for (Map<Object, Object> map : maps) {
+                String desc = (String) keys_desc[0];
+                Object[] keys = (Object[]) keys_desc[1];
+                try {
+                    testInPlaceOps(map, desc, keys);
+                } catch(Exception all) {
+                    unexpected("Failed for " + map.getClass().getName() + " with " + desc, all);
+                }
+            }
+        }
+    }
+
+    private static <T> void testInsertion(Map<T, T> map, String keys_desc, T[] keys) {
+        check("map empty", (map.size() == 0) && map.isEmpty());
+
+        for (int i = 0; i < keys.length; i++) {
+            check(String.format("insertion: map expected size m%d != i%d", map.size(), i),
+                    map.size() == i);
+            check(String.format("insertion: put(%s[%d])", keys_desc, i), null == map.put(keys[i], keys[i]));
+            check(String.format("insertion: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]));
+            check(String.format("insertion: containsValue(%s[%d])", keys_desc, i), map.containsValue(keys[i]));
+        }
+
+        check(String.format("map expected size m%d != k%d", map.size(), keys.length),
+                map.size() == keys.length);
+    }
+
+
+    private static <T> void testInPlaceOps(Map<T, T> map, String keys_desc, T[] keys) {
+        System.out.println(map.getClass() + " : " + keys_desc + ", testInPlaceOps");
+        System.out.flush();
+
+        testInsertion(map, keys_desc, keys);
+        testPutIfAbsent(map, keys_desc, keys);
+
+        map.clear();
+        testInsertion(map, keys_desc, keys);
+        testRemoveMapping(map, keys_desc, keys);
+
+        map.clear();
+        testInsertion(map, keys_desc, keys);
+        testReplaceOldValue(map, keys_desc, keys);
+
+        map.clear();
+        testInsertion(map, keys_desc, keys);
+        testReplaceIfMapped(map, keys_desc, keys);
+
+        map.clear();
+        testInsertion(map, keys_desc, keys);
+        testComputeIfAbsent(map, keys_desc, keys, (k) -> getExtraVal(keys[0]));
+
+        map.clear();
+        testInsertion(map, keys_desc, keys);
+        testComputeIfAbsent(map, keys_desc, keys, (k) -> null);
+
+        map.clear();
+        testInsertion(map, keys_desc, keys);
+        testComputeIfPresent(map, keys_desc, keys, (k, v) -> getExtraVal(keys[0]));
+
+        map.clear();
+        testInsertion(map, keys_desc, keys);
+        testComputeIfPresent(map, keys_desc, keys, (k, v) -> null);
+
+        if (!keys_desc.contains("Strings")) { // avoid parseInt() number format error
+            map.clear();
+            testInsertion(map, keys_desc, keys);
+            testComputeNonNull(map, keys_desc, keys);
+        }
+
+        map.clear();
+        testInsertion(map, keys_desc, keys);
+        testComputeNull(map, keys_desc, keys);
+
+        if (!keys_desc.contains("Strings")) { // avoid parseInt() number format error
+            map.clear();
+            testInsertion(map, keys_desc, keys);
+            testMergeNonNull(map, keys_desc, keys);
+        }
+
+        map.clear();
+        testInsertion(map, keys_desc, keys);
+        testMergeNull(map, keys_desc, keys);
+    }
+
+
+
+    private static <T> void testPutIfAbsent(Map<T, T> map, String keys_desc, T[] keys) {
+        T extraVal = getExtraVal(keys[0]);
+        T retVal;
+        removeOddKeys(map, keys);
+        for (int i = 0; i < keys.length; i++) {
+            retVal = map.putIfAbsent(keys[i], extraVal);
+            if (i % 2 == 0) { // even: not absent, not put
+                check(String.format("putIfAbsent: (%s[%d]) retVal", keys_desc, i), retVal == keys[i]);
+                check(String.format("putIfAbsent: get(%s[%d])", keys_desc, i), keys[i] == map.get(keys[i]));
+                check(String.format("putIfAbsent: containsValue(%s[%d])", keys_desc, i), map.containsValue(keys[i]));
+            } else { // odd: absent, was put
+                check(String.format("putIfAbsent: (%s[%d]) retVal", keys_desc, i), retVal == null);
+                check(String.format("putIfAbsent: get(%s[%d])", keys_desc, i), extraVal == map.get(keys[i]));
+                check(String.format("putIfAbsent: !containsValue(%s[%d])", keys_desc, i), !map.containsValue(keys[i]));
+            }
+            check(String.format("insertion: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]));
+        }
+        check(String.format("map expected size m%d != k%d", map.size(), keys.length),
+                map.size() == keys.length);
+    }
+
+    private static <T> void testRemoveMapping(Map<T, T> map, String keys_desc, T[] keys) {
+        T extraVal = getExtraVal(keys[0]);
+        boolean removed;
+        int removes = 0;
+        remapOddKeys(map, keys);
+        for (int i = 0; i < keys.length; i++) {
+            removed = map.remove(keys[i], keys[i]);
+            if (i % 2 == 0) { // even: original mapping, should be removed
+                check(String.format("removeMapping: retVal(%s[%d])", keys_desc, i), removed);
+                check(String.format("removeMapping: get(%s[%d])", keys_desc, i), null == map.get(keys[i]));
+                check(String.format("removeMapping: !containsKey(%s[%d])", keys_desc, i), !map.containsKey(keys[i]));
+                check(String.format("removeMapping: !containsValue(%s[%d])", keys_desc, i), !map.containsValue(keys[i]));
+                removes++;
+            } else { // odd: new mapping, not removed
+                check(String.format("removeMapping: retVal(%s[%d])", keys_desc, i), !removed);
+                check(String.format("removeMapping: get(%s[%d])", keys_desc, i), extraVal == map.get(keys[i]));
+                check(String.format("removeMapping: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]));
+                check(String.format("removeMapping: containsValue(%s[%d])", keys_desc, i), map.containsValue(extraVal));
+            }
+        }
+        check(String.format("map expected size m%d != k%d", map.size(), keys.length - removes),
+                map.size() == keys.length - removes);
+    }
+
+    private static <T> void testReplaceOldValue(Map<T, T> map, String keys_desc, T[] keys) {
+        // remap odds to extraVal
+        // call replace to replace for extraVal, for all keys
+        // check that all keys map to value from keys array
+        T extraVal = getExtraVal(keys[0]);
+        boolean replaced;
+        remapOddKeys(map, keys);
+
+        for (int i = 0; i < keys.length; i++) {
+            replaced = map.replace(keys[i], extraVal, keys[i]);
+            if (i % 2 == 0) { // even: original mapping, should not be replaced
+                check(String.format("replaceOldValue: retVal(%s[%d])", keys_desc, i), !replaced);
+            } else { // odd: new mapping, should be replaced
+                check(String.format("replaceOldValue: get(%s[%d])", keys_desc, i), replaced);
+            }
+            check(String.format("replaceOldValue: get(%s[%d])", keys_desc, i), keys[i] == map.get(keys[i]));
+            check(String.format("replaceOldValue: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]));
+            check(String.format("replaceOldValue: containsValue(%s[%d])", keys_desc, i), map.containsValue(keys[i]));
+//            removes++;
+        }
+        check(String.format("replaceOldValue: !containsValue(%s[%s])", keys_desc, extraVal.toString()), !map.containsValue(extraVal));
+        check(String.format("map expected size m%d != k%d", map.size(), keys.length),
+                map.size() == keys.length);
+    }
+
+    // TODO: Test case for key mapped to null value
+    private static <T> void testReplaceIfMapped(Map<T, T> map, String keys_desc, T[] keys) {
+        // remove odd keys
+        // call replace for all keys[]
+        // odd keys should remain absent, even keys should be mapped to EXTRA, no value from keys[] should be in map
+        T extraVal = getExtraVal(keys[0]);
+        int expectedSize1 = 0;
+        removeOddKeys(map, keys);
+        int expectedSize2 = map.size();
+
+        for (int i = 0; i < keys.length; i++) {
+            T retVal = map.replace(keys[i], extraVal);
+            if (i % 2 == 0) { // even: still in map, should be replaced
+                check(String.format("replaceIfMapped: retVal(%s[%d])", keys_desc, i), retVal == keys[i]);
+                check(String.format("replaceIfMapped: get(%s[%d])", keys_desc, i), extraVal == map.get(keys[i]));
+                check(String.format("replaceIfMapped: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]));
+                expectedSize1++;
+            } else { // odd: was removed, should not be replaced
+                check(String.format("replaceIfMapped: retVal(%s[%d])", keys_desc, i), retVal == null);
+                check(String.format("replaceIfMapped: get(%s[%d])", keys_desc, i), null == map.get(keys[i]));
+                check(String.format("replaceIfMapped: containsKey(%s[%d])", keys_desc, i), !map.containsKey(keys[i]));
+            }
+            check(String.format("replaceIfMapped: !containsValue(%s[%d])", keys_desc, i), !map.containsValue(keys[i]));
+        }
+        check(String.format("replaceIfMapped: containsValue(%s[%s])", keys_desc, extraVal.toString()), map.containsValue(extraVal));
+        check(String.format("map expected size#1 m%d != k%d", map.size(), expectedSize1),
+                map.size() == expectedSize1);
+        check(String.format("map expected size#2 m%d != k%d", map.size(), expectedSize2),
+                map.size() == expectedSize2);
+
+    }
+
+    private static <T> void testComputeIfAbsent(Map<T, T> map, String keys_desc, T[] keys,
+                                                Function<T,T> mappingFunction) {
+        // remove a third of the keys
+        // call computeIfAbsent for all keys, func returns EXTRA
+        // check that removed keys now -> EXTRA, other keys -> original val
+        T expectedVal = mappingFunction.apply(keys[0]);
+        T retVal;
+        int expectedSize = 0;
+        removeThirdKeys(map, keys);
+        for (int i = 0; i < keys.length; i++) {
+            retVal = map.computeIfAbsent(keys[i], mappingFunction);
+            if (i % 3 != 2) { // key present, not computed
+                check(String.format("computeIfAbsent: (%s[%d]) retVal", keys_desc, i), retVal == keys[i]);
+                check(String.format("computeIfAbsent: get(%s[%d])", keys_desc, i), keys[i] == map.get(keys[i]));
+                check(String.format("computeIfAbsent: containsValue(%s[%d])", keys_desc, i), map.containsValue(keys[i]));
+                check(String.format("insertion: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]));
+                expectedSize++;
+            } else { // key absent, computed unless function return null
+                check(String.format("computeIfAbsent: (%s[%d]) retVal", keys_desc, i), retVal == expectedVal);
+                check(String.format("computeIfAbsent: get(%s[%d])", keys_desc, i), expectedVal == map.get(keys[i]));
+                check(String.format("computeIfAbsent: !containsValue(%s[%d])", keys_desc, i), !map.containsValue(keys[i]));
+                // mapping should not be added if function returns null
+                check(String.format("insertion: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]) != (expectedVal == null));
+                if (expectedVal != null) { expectedSize++; }
+            }
+        }
+        if (expectedVal != null) {
+            check(String.format("computeIfAbsent: containsValue(%s[%s])", keys_desc, expectedVal), map.containsValue(expectedVal));
+        }
+        check(String.format("map expected size m%d != k%d", map.size(), expectedSize),
+                map.size() == expectedSize);
+    }
+
+    private static <T> void testComputeIfPresent(Map<T, T> map, String keys_desc, T[] keys,
+                                                BiFunction<T,T,T> mappingFunction) {
+        // remove a third of the keys
+        // call testComputeIfPresent for all keys[]
+        // removed keys should remain absent, even keys should be mapped to $RESULT
+        // no value from keys[] should be in map
+        T funcResult = mappingFunction.apply(keys[0], keys[0]);
+        int expectedSize1 = 0;
+        removeThirdKeys(map, keys);
+
+        for (int i = 0; i < keys.length; i++) {
+            T retVal = map.computeIfPresent(keys[i], mappingFunction);
+            if (i % 3 != 2) { // key present
+                if (funcResult == null) { // was removed
+                    check(String.format("replaceIfMapped: containsKey(%s[%d])", keys_desc, i), !map.containsKey(keys[i]));
+                } else { // value was replaced
+                    check(String.format("replaceIfMapped: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]));
+                    expectedSize1++;
+                }
+                check(String.format("computeIfPresent: retVal(%s[%s])", keys_desc, i), retVal == funcResult);
+                check(String.format("replaceIfMapped: get(%s[%d])", keys_desc, i), funcResult == map.get(keys[i]));
+
+            } else { // odd: was removed, should not be replaced
+                check(String.format("replaceIfMapped: retVal(%s[%d])", keys_desc, i), retVal == null);
+                check(String.format("replaceIfMapped: get(%s[%d])", keys_desc, i), null == map.get(keys[i]));
+                check(String.format("replaceIfMapped: containsKey(%s[%d])", keys_desc, i), !map.containsKey(keys[i]));
+            }
+            check(String.format("replaceIfMapped: !containsValue(%s[%d])", keys_desc, i), !map.containsValue(keys[i]));
+        }
+        check(String.format("map expected size#1 m%d != k%d", map.size(), expectedSize1),
+                map.size() == expectedSize1);
+    }
+
+    private static <T> void testComputeNonNull(Map<T, T> map, String keys_desc, T[] keys) {
+        // remove a third of the keys
+        // call compute() for all keys[]
+        // all keys should be present: removed keys -> EXTRA, others to k-1
+        BiFunction<T,T,T> mappingFunction = (k, v) -> {
+                if (v == null) {
+                    return getExtraVal(keys[0]);
+                } else {
+                    return keys[Integer.parseInt(k.toString()) - 1];
+                }
+            };
+        T extraVal = getExtraVal(keys[0]);
+        removeThirdKeys(map, keys);
+        for (int i = 1; i < keys.length; i++) {
+            T retVal = map.compute(keys[i], mappingFunction);
+            if (i % 3 != 2) { // key present, should be mapped to k-1
+                check(String.format("compute: retVal(%s[%d])", keys_desc, i), retVal == keys[i-1]);
+                check(String.format("compute: get(%s[%d])", keys_desc, i), keys[i-1] == map.get(keys[i]));
+            } else { // odd: was removed, should be replaced with EXTRA
+                check(String.format("compute: retVal(%s[%d])", keys_desc, i), retVal == extraVal);
+                check(String.format("compute: get(%s[%d])", keys_desc, i), extraVal == map.get(keys[i]));
+            }
+            check(String.format("compute: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]));
+        }
+        check(String.format("map expected size#1 m%d != k%d", map.size(), keys.length),
+                map.size() == keys.length);
+        check(String.format("compute: containsValue(%s[%s])", keys_desc, extraVal.toString()), map.containsValue(extraVal));
+        check(String.format("compute: !containsValue(%s,[null])", keys_desc), !map.containsValue(null));
+    }
+
+    private static <T> void testComputeNull(Map<T, T> map, String keys_desc, T[] keys) {
+        // remove a third of the keys
+        // call compute() for all keys[]
+        // removed keys should -> EXTRA
+        // for other keys: func returns null, should have no mapping
+        BiFunction<T,T,T> mappingFunction = (k, v) -> {
+            // if absent/null -> EXTRA
+            // if present -> null
+            if (v == null) {
+                return getExtraVal(keys[0]);
+            } else {
+                return null;
+            }
+        };
+        T extraVal = getExtraVal(keys[0]);
+        int expectedSize = 0;
+        removeThirdKeys(map, keys);
+        for (int i = 0; i < keys.length; i++) {
+            T retVal = map.compute(keys[i], mappingFunction);
+            if (i % 3 != 2) { // key present, func returned null, should be absent from map
+                check(String.format("compute: retVal(%s[%d])", keys_desc, i), retVal == null);
+                check(String.format("compute: get(%s[%d])", keys_desc, i), null == map.get(keys[i]));
+                check(String.format("compute: containsKey(%s[%d])", keys_desc, i), !map.containsKey(keys[i]));
+                check(String.format("compute: containsValue(%s[%s])", keys_desc, i), !map.containsValue(keys[i]));
+            } else { // odd: was removed, should now be mapped to EXTRA
+                check(String.format("compute: retVal(%s[%d])", keys_desc, i), retVal == extraVal);
+                check(String.format("compute: get(%s[%d])", keys_desc, i), extraVal == map.get(keys[i]));
+                check(String.format("compute: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]));
+                expectedSize++;
+            }
+        }
+        check(String.format("compute: containsValue(%s[%s])", keys_desc, extraVal.toString()), map.containsValue(extraVal));
+        check(String.format("map expected size#1 m%d != k%d", map.size(), expectedSize),
+                map.size() == expectedSize);
+    }
+
+    private static <T> void testMergeNonNull(Map<T, T> map, String keys_desc, T[] keys) {
+        // remove a third of the keys
+        // call merge() for all keys[]
+        // all keys should be present: removed keys now -> EXTRA, other keys -> k-1
+
+        // Map to preceding key
+        BiFunction<T,T,T> mappingFunction = (k, v) -> keys[Integer.parseInt(k.toString()) - 1];
+        T extraVal = getExtraVal(keys[0]);
+        removeThirdKeys(map, keys);
+        for (int i = 1; i < keys.length; i++) {
+            T retVal = map.merge(keys[i], extraVal, mappingFunction);
+            if (i % 3 != 2) { // key present, should be mapped to k-1
+                check(String.format("compute: retVal(%s[%d])", keys_desc, i), retVal == keys[i-1]);
+                check(String.format("compute: get(%s[%d])", keys_desc, i), keys[i-1] == map.get(keys[i]));
+            } else { // odd: was removed, should be replaced with EXTRA
+                check(String.format("compute: retVal(%s[%d])", keys_desc, i), retVal == extraVal);
+                check(String.format("compute: get(%s[%d])", keys_desc, i), extraVal == map.get(keys[i]));
+            }
+            check(String.format("compute: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]));
+        }
+
+        check(String.format("map expected size#1 m%d != k%d", map.size(), keys.length),
+                map.size() == keys.length);
+        check(String.format("compute: containsValue(%s[%s])", keys_desc, extraVal.toString()), map.containsValue(extraVal));
+        check(String.format("compute: !containsValue(%s,[null])", keys_desc), !map.containsValue(null));
+
+    }
+
+    private static <T> void testMergeNull(Map<T, T> map, String keys_desc, T[] keys) {
+        // remove a third of the keys
+        // call merge() for all keys[]
+        // result: removed keys -> EXTRA, other keys absent
+
+        BiFunction<T,T,T> mappingFunction = (k, v) -> null;
+        T extraVal = getExtraVal(keys[0]);
+        int expectedSize = 0;
+        removeThirdKeys(map, keys);
+        for (int i = 0; i < keys.length; i++) {
+            T retVal = map.merge(keys[i], extraVal, mappingFunction);
+            if (i % 3 != 2) { // key present, func returned null, should be absent from map
+                check(String.format("compute: retVal(%s[%d])", keys_desc, i), retVal == null);
+                check(String.format("compute: get(%s[%d])", keys_desc, i), null == map.get(keys[i]));
+                check(String.format("compute: containsKey(%s[%d])", keys_desc, i), !map.containsKey(keys[i]));
+            } else { // odd: was removed, should now be mapped to EXTRA
+                check(String.format("compute: retVal(%s[%d])", keys_desc, i), retVal == extraVal);
+                check(String.format("compute: get(%s[%d])", keys_desc, i), extraVal == map.get(keys[i]));
+                check(String.format("compute: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]));
+                expectedSize++;
+            }
+            check(String.format("compute: containsValue(%s[%s])", keys_desc, i), !map.containsValue(keys[i]));
+        }
+        check(String.format("compute: containsValue(%s[%s])", keys_desc, extraVal.toString()), map.containsValue(extraVal));
+        check(String.format("map expected size#1 m%d != k%d", map.size(), expectedSize),
+                map.size() == expectedSize);
+    }
+
+    /*
+     * Return the EXTRA val for the key type being used
+     */
+    private static <T> T getExtraVal(T key) {
+        if (key instanceof HashableInteger) {
+            return (T)EXTRA_INT_VAL;
+        } else {
+            return (T)EXTRA_STRING_VAL;
+        }
+    }
+
+    /*
+     * Remove half of the keys
+     */
+    private static <T> void removeOddKeys(Map<T, T> map, /*String keys_desc, */ T[] keys) {
+        int removes = 0;
+        for (int i = 0; i < keys.length; i++) {
+            if (i % 2 != 0) {
+                map.remove(keys[i]);
+                removes++;
+            }
+        }
+        check(String.format("map expected size m%d != k%d", map.size(), keys.length - removes),
+                map.size() == keys.length - removes);
+    }
+
+    /*
+     * Remove every third key
+     * This will hopefully leave some removed keys in TreeBins for, e.g., computeIfAbsent
+     * w/ a func that returns null.
+     *
+     * TODO: consider using this in other tests (and maybe adding a remapThirdKeys)
+     */
+    private static <T> void removeThirdKeys(Map<T, T> map, /*String keys_desc, */ T[] keys) {
+        int removes = 0;
+        for (int i = 0; i < keys.length; i++) {
+            if (i % 3 == 2) {
+                map.remove(keys[i]);
+                removes++;
+            }
+        }
+        check(String.format("map expected size m%d != k%d", map.size(), keys.length - removes),
+                map.size() == keys.length - removes);
+    }
+
+    /*
+     * Re-map the odd-numbered keys to map to the EXTRA value
+     */
+    private static <T> void remapOddKeys(Map<T, T> map, /*String keys_desc, */ T[] keys) {
+        T extraVal = getExtraVal(keys[0]);
+        for (int i = 0; i < keys.length; i++) {
+            if (i % 2 != 0) {
+                map.put(keys[i], extraVal);
+            }
+        }
+    }
+
+    //--------------------- Infrastructure ---------------------------
+    static volatile int passed = 0, failed = 0;
+
+    static void pass() {
+        passed++;
+    }
+
+    static void fail() {
+        failed++;
+        (new Error("Failure")).printStackTrace(System.err);
+    }
+
+    static void fail(String msg) {
+        failed++;
+        (new Error("Failure: " + msg)).printStackTrace(System.err);
+    }
+
+    static void abort() {
+        fail();
+        System.exit(1);
+    }
+
+    static void abort(String msg) {
+        fail(msg);
+        System.exit(1);
+    }
+
+    static void unexpected(String msg, Throwable t) {
+        System.err.println("Unexpected: " + msg);
+        unexpected(t);
+    }
+
+    static void unexpected(Throwable t) {
+        failed++;
+        t.printStackTrace(System.err);
+    }
+
+    static void check(boolean cond) {
+        if (cond) {
+            pass();
+        } else {
+            fail();
+        }
+    }
+
+    static void check(String desc, boolean cond) {
+        if (cond) {
+            pass();
+        } else {
+            fail(desc);
+        }
+    }
+
+    static void equal(Object x, Object y) {
+        if (Objects.equals(x, y)) {
+            pass();
+        } else {
+            fail(x + " not equal to " + y);
+        }
+    }
+
+    public static void main(String[] args) throws Throwable {
+        Thread.currentThread().setName(Collisions.class.getName());
+//        Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
+        try {
+            realMain(args);
+        } catch (Throwable t) {
+            unexpected(t);
+        }
+
+        System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
+        if (failed > 0) {
+            throw new Error("Some tests failed");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Map/TreeBinSplitBackToEntries.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,255 @@
+/*
+ * 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.*;
+import java.lang.reflect.Field;
+
+/*
+ * @test
+ * @bug 8005698
+ * @summary Test the case where TreeBin.splitTreeBin() converts a bin back to an Entry list
+ * @run main TreeBinSplitBackToEntries unused
+ * @author Brent Christian
+ */
+
+public class TreeBinSplitBackToEntries {
+    private static int EXPECTED_TREE_THRESHOLD = 16;
+
+    // Easiest if this covers one bit higher then 'bit' in splitTreeBin() on the
+    // call where the TreeBin is converted back to an Entry list
+    private static int HASHMASK = 0x7F;
+    private static boolean verbose = false;
+    private static boolean fastFail = false;
+    private static boolean failed = false;
+
+    static void printlnIfVerbose(String msg) {
+        if (verbose) {System.out.println(msg); }
+    }
+
+    public static void main(String[] args) {
+        for (String arg : args) {
+            switch(arg) {
+                case "-verbose":
+                    verbose = true;
+                    break;
+                case "-fastfail":
+                    fastFail = true;
+                    break;
+            }
+        }
+        checkTreeThreshold();
+        testMapHiTree();
+        testMapLoTree();
+        if (failed) {
+            System.out.println("Test Failed");
+            System.exit(1);
+        } else {
+            System.out.println("Test Passed");
+        }
+    }
+
+    public static void checkTreeThreshold() {
+        int threshold = -1;
+        try {
+            Class treeBinClass = Class.forName("java.util.HashMap$TreeBin");
+            Field treeThreshold = treeBinClass.getDeclaredField("TREE_THRESHOLD");
+            treeThreshold.setAccessible(true);
+            threshold = treeThreshold.getInt(treeBinClass);
+        } catch (ClassNotFoundException|NoSuchFieldException|IllegalAccessException e) {
+            e.printStackTrace();
+            throw new Error("Problem accessing TreeBin.TREE_THRESHOLD", e);
+        }
+        check("Expected TREE_THRESHOLD: " + EXPECTED_TREE_THRESHOLD +", found: " + threshold,
+              threshold == EXPECTED_TREE_THRESHOLD);
+        printlnIfVerbose("TREE_THRESHOLD: " + threshold);
+    }
+
+    public static void testMapHiTree() {
+        Object[][] mapKeys = makeHiTreeTestData();
+        testMapsForKeys(mapKeys, "hiTree");
+    }
+
+    public static void testMapLoTree() {
+        Object[][] mapKeys = makeLoTreeTestData();
+
+        testMapsForKeys(mapKeys, "loTree");
+    }
+
+    public static void testMapsForKeys(Object[][] mapKeys, String desc) {
+        // loop through data sets
+        for (Object[] keys_desc : mapKeys) {
+            Map<Object, Object>[] maps = (Map<Object, Object>[]) new Map[]{
+              new HashMap<>(4, 0.8f),
+              new LinkedHashMap<>(4, 0.8f),
+            };
+            // for each map type.
+            for (Map<Object, Object> map : maps) {
+                Object[] keys = (Object[]) keys_desc[1];
+                System.out.println(desc + ": testPutThenGet() for " + map.getClass());
+                testPutThenGet(map, keys);
+            }
+        }
+    }
+
+    private static <T> void testPutThenGet(Map<T, T> map, T[] keys) {
+        for (T key : keys) {
+            printlnIfVerbose("put()ing 0x" + Integer.toHexString(Integer.parseInt(key.toString())) + ", hashCode=" + Integer.toHexString(key.hashCode()));
+            map.put(key, key);
+        }
+        for (T key : keys) {
+            check("key: 0x" + Integer.toHexString(Integer.parseInt(key.toString())) + " not found in resulting " + map.getClass().getSimpleName(), map.get(key) != null);
+        }
+    }
+
+    /* Data to force a non-empty loTree in TreeBin.splitTreeBin() to be converted back
+     * into an Entry list
+     */
+    private static Object[][] makeLoTreeTestData() {
+        HashableInteger COLLIDING_OBJECTS[] = new HashableInteger[] {
+            new HashableInteger( 0x23, HASHMASK),
+            new HashableInteger( 0x123, HASHMASK),
+            new HashableInteger( 0x323, HASHMASK),
+            new HashableInteger( 0x523, HASHMASK),
+
+            new HashableInteger( 0x723, HASHMASK),
+            new HashableInteger( 0x923, HASHMASK),
+            new HashableInteger( 0xB23, HASHMASK),
+            new HashableInteger( 0xD23, HASHMASK),
+
+            new HashableInteger( 0xF23, HASHMASK),
+            new HashableInteger( 0xF123, HASHMASK),
+            new HashableInteger( 0x1023, HASHMASK),
+            new HashableInteger( 0x1123, HASHMASK),
+
+            new HashableInteger( 0x1323, HASHMASK),
+            new HashableInteger( 0x1523, HASHMASK),
+            new HashableInteger( 0x1723, HASHMASK),
+            new HashableInteger( 0x1923, HASHMASK),
+
+            new HashableInteger( 0x1B23, HASHMASK),
+            new HashableInteger( 0x1D23, HASHMASK),
+            new HashableInteger( 0x3123, HASHMASK),
+            new HashableInteger( 0x3323, HASHMASK),
+            new HashableInteger( 0x3523, HASHMASK),
+
+            new HashableInteger( 0x3723, HASHMASK),
+            new HashableInteger( 0x1001, HASHMASK),
+            new HashableInteger( 0x4001, HASHMASK),
+            new HashableInteger( 0x1, HASHMASK),
+        };
+        return new Object[][] {
+            new Object[]{"Colliding Objects", COLLIDING_OBJECTS},
+        };
+    }
+
+    /* Data to force the hiTree in TreeBin.splitTreeBin() to be converted back
+     * into an Entry list
+     */
+    private static Object[][] makeHiTreeTestData() {
+        HashableInteger COLLIDING_OBJECTS[] = new HashableInteger[] {
+            new HashableInteger( 0x1, HASHMASK),
+            new HashableInteger( 0x101, HASHMASK),
+            new HashableInteger( 0x301, HASHMASK),
+            new HashableInteger( 0x501, HASHMASK),
+            new HashableInteger( 0x701, HASHMASK),
+
+            new HashableInteger( 0x1001, HASHMASK),
+            new HashableInteger( 0x1101, HASHMASK),
+            new HashableInteger( 0x1301, HASHMASK),
+
+            new HashableInteger( 0x1501, HASHMASK),
+            new HashableInteger( 0x1701, HASHMASK),
+            new HashableInteger( 0x4001, HASHMASK),
+            new HashableInteger( 0x4101, HASHMASK),
+            new HashableInteger( 0x4301, HASHMASK),
+
+            new HashableInteger( 0x4501, HASHMASK),
+            new HashableInteger( 0x4701, HASHMASK),
+            new HashableInteger( 0x8001, HASHMASK),
+            new HashableInteger( 0x8101, HASHMASK),
+
+
+            new HashableInteger( 0x8301, HASHMASK),
+            new HashableInteger( 0x8501, HASHMASK),
+            new HashableInteger( 0x8701, HASHMASK),
+            new HashableInteger( 0x9001, HASHMASK),
+
+            new HashableInteger( 0x23, HASHMASK),
+            new HashableInteger( 0x123, HASHMASK),
+            new HashableInteger( 0x323, HASHMASK),
+            new HashableInteger( 0x523, HASHMASK),
+        };
+        return new Object[][] {
+            new Object[]{"Colliding Objects", COLLIDING_OBJECTS},
+        };
+    }
+
+    static void check(String desc, boolean cond) {
+        if (!cond) {
+            fail(desc);
+        }
+    }
+
+    static void fail(String msg) {
+        failed = true;
+        (new Error("Failure: " + msg)).printStackTrace(System.err);
+        if (fastFail) {
+            System.exit(1);
+        }
+    }
+
+    final static class HashableInteger implements Comparable<HashableInteger> {
+        final int value;
+        final int hashmask; //yes duplication
+
+        HashableInteger(int value, int hashmask) {
+            this.value = value;
+            this.hashmask = hashmask;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof HashableInteger) {
+                HashableInteger other = (HashableInteger) obj;
+                return other.value == value;
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            // This version ANDs the mask
+            return value & hashmask;
+        }
+
+        @Override
+        public int compareTo(HashableInteger o) {
+            return value - o.value;
+        }
+
+        @Override
+        public String toString() {
+            return Integer.toString(value);
+        }
+    }
+}
--- a/jdk/test/java/util/PluggableLocale/BreakIteratorProviderTest.sh	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/util/PluggableLocale/BreakIteratorProviderTest.sh	Mon Jun 10 10:38:33 2013 +0100
@@ -1,3 +1,4 @@
+#!/bin/sh
 # 
 # Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -20,7 +21,6 @@
 # or visit www.oracle.com if you need additional information or have any
 # questions.
 #
-#!/bin/sh
 #
 # @test
 # @bug 4052440
--- a/jdk/test/java/util/PluggableLocale/CalendarDataProviderTest.sh	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/util/PluggableLocale/CalendarDataProviderTest.sh	Mon Jun 10 10:38:33 2013 +0100
@@ -1,3 +1,4 @@
+#!/bin/sh
 # 
 # Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -20,7 +21,6 @@
 # or visit www.oracle.com if you need additional information or have any
 # questions.
 #
-#!/bin/sh
 #
 # @test
 # @bug 7058207 8000986
--- a/jdk/test/java/util/PluggableLocale/ClasspathTest.sh	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/util/PluggableLocale/ClasspathTest.sh	Mon Jun 10 10:38:33 2013 +0100
@@ -1,3 +1,4 @@
+#!/bin/sh
 # 
 # Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -20,7 +21,6 @@
 # or visit www.oracle.com if you need additional information or have any
 # questions.
 #
-#!/bin/sh
 #
 # @test
 # @bug 6388652
--- a/jdk/test/java/util/PluggableLocale/CollatorProviderTest.sh	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/util/PluggableLocale/CollatorProviderTest.sh	Mon Jun 10 10:38:33 2013 +0100
@@ -1,3 +1,4 @@
+#!/bin/sh
 # 
 # Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -20,7 +21,6 @@
 # or visit www.oracle.com if you need additional information or have any
 # questions.
 #
-#!/bin/sh
 #
 # @test
 # @bug 4052440
--- a/jdk/test/java/util/PluggableLocale/CurrencyNameProviderTest.sh	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/util/PluggableLocale/CurrencyNameProviderTest.sh	Mon Jun 10 10:38:33 2013 +0100
@@ -1,3 +1,4 @@
+#!/bin/sh
 # 
 # Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -20,7 +21,6 @@
 # or visit www.oracle.com if you need additional information or have any
 # questions.
 #
-#!/bin/sh
 #
 # @test
 # @bug 4052440 7199750 8000997
--- a/jdk/test/java/util/PluggableLocale/DateFormatProviderTest.sh	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/util/PluggableLocale/DateFormatProviderTest.sh	Mon Jun 10 10:38:33 2013 +0100
@@ -1,3 +1,4 @@
+#!/bin/sh
 # 
 # Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -20,7 +21,6 @@
 # or visit www.oracle.com if you need additional information or have any
 # questions.
 #
-#!/bin/sh
 #
 # @test
 # @bug 4052440 7003643
--- a/jdk/test/java/util/PluggableLocale/DateFormatSymbolsProviderTest.sh	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/util/PluggableLocale/DateFormatSymbolsProviderTest.sh	Mon Jun 10 10:38:33 2013 +0100
@@ -1,3 +1,4 @@
+#!/bin/sh
 # 
 # Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -20,7 +21,6 @@
 # or visit www.oracle.com if you need additional information or have any
 # questions.
 #
-#!/bin/sh
 #
 # @test
 # @bug 4052440 7200341
--- a/jdk/test/java/util/PluggableLocale/DecimalFormatSymbolsProviderTest.sh	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/util/PluggableLocale/DecimalFormatSymbolsProviderTest.sh	Mon Jun 10 10:38:33 2013 +0100
@@ -1,3 +1,4 @@
+#!/bin/sh
 # 
 # Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -20,7 +21,6 @@
 # or visit www.oracle.com if you need additional information or have any
 # questions.
 #
-#!/bin/sh
 #
 # @test
 # @bug 4052440
--- a/jdk/test/java/util/PluggableLocale/ExecTest.sh	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/util/PluggableLocale/ExecTest.sh	Mon Jun 10 10:38:33 2013 +0100
@@ -1,3 +1,4 @@
+#!/bin/sh
 #
 # Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -20,7 +21,6 @@
 # or visit www.oracle.com if you need additional information or have any
 # questions.
 #
-#!/bin/sh
 #
 #
 #
--- a/jdk/test/java/util/PluggableLocale/GenericTest.sh	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/util/PluggableLocale/GenericTest.sh	Mon Jun 10 10:38:33 2013 +0100
@@ -1,3 +1,4 @@
+#!/bin/sh
 # 
 # Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -20,7 +21,6 @@
 # or visit www.oracle.com if you need additional information or have any
 # questions.
 #
-#!/bin/sh
 #
 # @test
 # @bug 4052440
--- a/jdk/test/java/util/PluggableLocale/LocaleNameProviderTest.sh	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/util/PluggableLocale/LocaleNameProviderTest.sh	Mon Jun 10 10:38:33 2013 +0100
@@ -1,3 +1,4 @@
+#!/bin/sh
 # 
 # Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -20,7 +21,6 @@
 # or visit www.oracle.com if you need additional information or have any
 # questions.
 #
-#!/bin/sh
 #
 # @test
 # @bug 4052440 8000273
--- a/jdk/test/java/util/PluggableLocale/NumberFormatProviderTest.sh	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/util/PluggableLocale/NumberFormatProviderTest.sh	Mon Jun 10 10:38:33 2013 +0100
@@ -1,3 +1,4 @@
+#!/bin/sh
 # 
 # Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -20,7 +21,6 @@
 # or visit www.oracle.com if you need additional information or have any
 # questions.
 #
-#!/bin/sh
 #
 # @test
 # @bug 4052440 7003643
--- a/jdk/test/java/util/PluggableLocale/TimeZoneNameProviderTest.sh	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/util/PluggableLocale/TimeZoneNameProviderTest.sh	Mon Jun 10 10:38:33 2013 +0100
@@ -1,3 +1,4 @@
+#!/bin/sh
 # 
 # Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -20,7 +21,6 @@
 # or visit www.oracle.com if you need additional information or have any
 # questions.
 #
-#!/bin/sh
 #
 # @test
 # @bug 4052440 8003267
--- a/jdk/test/java/util/ResourceBundle/Bug6299235Test.sh	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/util/ResourceBundle/Bug6299235Test.sh	Mon Jun 10 10:38:33 2013 +0100
@@ -1,4 +1,4 @@
-#
+#!/bin/sh
 # Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Spliterator/SpliteratorCollisions.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,707 @@
+/*
+ * 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.
+ */
+
+/**
+ * @test
+ * @bug 8005698
+ * @run testng SpliteratorCollisions
+ * @summary Spliterator traversing and splitting hash maps containing colliding hashes
+ * @author Brent Christian
+ */
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Spliterator;
+import java.util.TreeSet;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.LongConsumer;
+import java.util.function.Supplier;
+import java.util.function.UnaryOperator;
+
+import static org.testng.Assert.*;
+import static org.testng.Assert.assertEquals;
+
+@Test
+public class SpliteratorCollisions {
+
+    private static List<Integer> SIZES = Arrays.asList(0, 1, 10, 100, 1000);
+
+    private static class SpliteratorDataBuilder<T> {
+        List<Object[]> data;
+        List<T> exp;
+        Map<T, T> mExp;
+
+        SpliteratorDataBuilder(List<Object[]> data, List<T> exp) {
+            this.data = data;
+            this.exp = exp;
+            this.mExp = createMap(exp);
+        }
+
+        Map<T, T> createMap(List<T> l) {
+            Map<T, T> m = new LinkedHashMap<>();
+            for (T t : l) {
+                m.put(t, t);
+            }
+            return m;
+        }
+
+        void add(String description, Collection<?> expected, Supplier<Spliterator<?>> s) {
+            description = joiner(description).toString();
+            data.add(new Object[]{description, expected, s});
+        }
+
+        void add(String description, Supplier<Spliterator<?>> s) {
+            add(description, exp, s);
+        }
+
+        void addCollection(Function<Collection<T>, ? extends Collection<T>> c) {
+            add("new " + c.apply(Collections.<T>emptyList()).getClass().getName() + ".spliterator()",
+                () -> c.apply(exp).spliterator());
+        }
+
+        void addList(Function<Collection<T>, ? extends List<T>> l) {
+            // @@@ If collection is instance of List then add sub-list tests
+            addCollection(l);
+        }
+
+        void addMap(Function<Map<T, T>, ? extends Map<T, T>> m) {
+            String description = "new " + m.apply(Collections.<T, T>emptyMap()).getClass().getName();
+            add(description + ".keySet().spliterator()", () -> m.apply(mExp).keySet().spliterator());
+            add(description + ".values().spliterator()", () -> m.apply(mExp).values().spliterator());
+            add(description + ".entrySet().spliterator()", mExp.entrySet(), () -> m.apply(mExp).entrySet().spliterator());
+        }
+
+        StringBuilder joiner(String description) {
+            return new StringBuilder(description).
+                    append(" {").
+                    append("size=").append(exp.size()).
+                    append("}");
+        }
+    }
+
+    static Object[][] spliteratorDataProvider;
+
+    @DataProvider(name = "HashableIntSpliterator")
+    public static Object[][] spliteratorDataProvider() {
+        if (spliteratorDataProvider != null) {
+            return spliteratorDataProvider;
+        }
+
+        List<Object[]> data = new ArrayList<>();
+        for (int size : SIZES) {
+            List<HashableInteger> exp = listIntRange(size, false);
+            SpliteratorDataBuilder<HashableInteger> db = new SpliteratorDataBuilder<>(data, exp);
+
+            // Maps
+            db.addMap(HashMap::new);
+            db.addMap(LinkedHashMap::new);
+
+            // Collections that use HashMap
+            db.addCollection(HashSet::new);
+            db.addCollection(LinkedHashSet::new);
+            db.addCollection(TreeSet::new);
+        }
+        return spliteratorDataProvider = data.toArray(new Object[0][]);
+    }
+
+    static Object[][] spliteratorDataProviderWithNull;
+
+    @DataProvider(name = "HashableIntSpliteratorWithNull")
+    public static Object[][] spliteratorNullDataProvider() {
+        if (spliteratorDataProviderWithNull != null) {
+            return spliteratorDataProviderWithNull;
+        }
+
+        List<Object[]> data = new ArrayList<>();
+        for (int size : SIZES) {
+            List<HashableInteger> exp = listIntRange(size, true);
+            exp.add(0, null);
+            SpliteratorDataBuilder<HashableInteger> db = new SpliteratorDataBuilder<>(data, exp);
+
+            // Maps
+            db.addMap(HashMap::new);
+            db.addMap(LinkedHashMap::new);
+            // TODO: add this back in if we decide to keep TreeBin in WeakHashMap
+            //db.addMap(WeakHashMap::new);
+
+            // Collections that use HashMap
+            db.addCollection(HashSet::new);
+            db.addCollection(LinkedHashSet::new);
+//            db.addCollection(TreeSet::new);
+
+        }
+        return spliteratorDataProviderWithNull = data.toArray(new Object[0][]);
+    }
+
+    final static class HashableInteger implements Comparable<HashableInteger> {
+
+        final int value;
+        final int hashmask; //yes duplication
+
+        HashableInteger(int value, int hashmask) {
+            this.value = value;
+            this.hashmask = hashmask;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof HashableInteger) {
+                HashableInteger other = (HashableInteger) obj;
+
+                return other.value == value;
+            }
+
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return value % hashmask;
+        }
+
+        @Override
+        public int compareTo(HashableInteger o) {
+            return value - o.value;
+        }
+
+        @Override
+        public String toString() {
+            return Integer.toString(value);
+        }
+    }
+
+    private static List<HashableInteger> listIntRange(int upTo, boolean withNull) {
+        List<HashableInteger> exp = new ArrayList<>();
+        if (withNull) {
+            exp.add(null);
+        }
+        for (int i = 0; i < upTo; i++) {
+            exp.add(new HashableInteger(i, 10));
+        }
+        return Collections.unmodifiableList(exp);
+    }
+
+    @Test(dataProvider = "HashableIntSpliterator")
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public void testNullPointerException(String description, Collection exp, Supplier<Spliterator> s) {
+        executeAndCatch(NullPointerException.class, () -> s.get().forEachRemaining(null));
+        executeAndCatch(NullPointerException.class, () -> s.get().tryAdvance(null));
+    }
+
+    @Test(dataProvider = "HashableIntSpliteratorWithNull")
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public void testNullPointerExceptionWithNull(String description, Collection exp, Supplier<Spliterator> s) {
+        executeAndCatch(NullPointerException.class, () -> s.get().forEachRemaining(null));
+        executeAndCatch(NullPointerException.class, () -> s.get().tryAdvance(null));
+    }
+
+
+    @Test(dataProvider = "HashableIntSpliterator")
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public void testForEach(String description, Collection exp, Supplier<Spliterator> s) {
+        testForEach(exp, s, (Consumer<Object> b) -> b);
+    }
+
+    @Test(dataProvider = "HashableIntSpliteratorWithNull")
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public void testForEachWithNull(String description, Collection exp, Supplier<Spliterator> s) {
+        testForEach(exp, s, (Consumer<Object> b) -> b);
+    }
+
+
+    @Test(dataProvider = "HashableIntSpliterator")
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public void testTryAdvance(String description, Collection exp, Supplier<Spliterator> s) {
+        testTryAdvance(exp, s, (Consumer<Object> b) -> b);
+    }
+
+    @Test(dataProvider = "HashableIntSpliteratorWithNull")
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public void testTryAdvanceWithNull(String description, Collection exp, Supplier<Spliterator> s) {
+        testTryAdvance(exp, s, (Consumer<Object> b) -> b);
+    }
+
+/* skip this test until 8013649 is fixed
+    @Test(dataProvider = "HashableIntSpliterator")
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public void testMixedTryAdvanceForEach(String description, Collection exp, Supplier<Spliterator> s) {
+        testMixedTryAdvanceForEach(exp, s, (Consumer<Object> b) -> b);
+    }
+
+    @Test(dataProvider = "HashableIntSpliteratorWithNull")
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public void testMixedTryAdvanceForEachWithNull(String description, Collection exp, Supplier<Spliterator> s) {
+        testMixedTryAdvanceForEach(exp, s, (Consumer<Object> b) -> b);
+    }
+*/
+
+    @Test(dataProvider = "HashableIntSpliterator")
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public void testSplitAfterFullTraversal(String description, Collection exp, Supplier<Spliterator> s) {
+        testSplitAfterFullTraversal(s, (Consumer<Object> b) -> b);
+    }
+
+    @Test(dataProvider = "HashableIntSpliteratorWithNull")
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public void testSplitAfterFullTraversalWithNull(String description, Collection exp, Supplier<Spliterator> s) {
+        testSplitAfterFullTraversal(s, (Consumer<Object> b) -> b);
+    }
+
+
+    @Test(dataProvider = "HashableIntSpliterator")
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public void testSplitOnce(String description, Collection exp, Supplier<Spliterator> s) {
+        testSplitOnce(exp, s, (Consumer<Object> b) -> b);
+    }
+
+    @Test(dataProvider = "HashableIntSpliteratorWithNull")
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public void testSplitOnceWithNull(String description, Collection exp, Supplier<Spliterator> s) {
+        testSplitOnce(exp, s, (Consumer<Object> b) -> b);
+    }
+
+    @Test(dataProvider = "HashableIntSpliterator")
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public void testSplitSixDeep(String description, Collection exp, Supplier<Spliterator> s) {
+        testSplitSixDeep(exp, s, (Consumer<Object> b) -> b);
+    }
+
+    @Test(dataProvider = "HashableIntSpliteratorWithNull")
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public void testSplitSixDeepWithNull(String description, Collection exp, Supplier<Spliterator> s) {
+        testSplitSixDeep(exp, s, (Consumer<Object> b) -> b);
+    }
+
+    @Test(dataProvider = "HashableIntSpliterator")
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public void testSplitUntilNull(String description, Collection exp, Supplier<Spliterator> s) {
+        testSplitUntilNull(exp, s, (Consumer<Object> b) -> b);
+    }
+
+    @Test(dataProvider = "HashableIntSpliteratorWithNull")
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public void testSplitUntilNullWithNull(String description, Collection exp, Supplier<Spliterator> s) {
+        testSplitUntilNull(exp, s, (Consumer<Object> b) -> b);
+    }
+
+    private static <T, S extends Spliterator<T>> void testForEach(
+            Collection<T> exp,
+            Supplier<S> supplier,
+            UnaryOperator<Consumer<T>> boxingAdapter) {
+        S spliterator = supplier.get();
+        long sizeIfKnown = spliterator.getExactSizeIfKnown();
+        boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
+
+        ArrayList<T> fromForEach = new ArrayList<>();
+        spliterator = supplier.get();
+        Consumer<T> addToFromForEach = boxingAdapter.apply(fromForEach::add);
+        spliterator.forEachRemaining(addToFromForEach);
+
+        // Assert that forEach now produces no elements
+        spliterator.forEachRemaining(boxingAdapter.apply(e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e)));
+        // Assert that tryAdvance now produce no elements
+        spliterator.tryAdvance(boxingAdapter.apply(e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e)));
+
+        // assert that size, tryAdvance, and forEach are consistent
+        if (sizeIfKnown >= 0) {
+            assertEquals(sizeIfKnown, exp.size());
+        }
+        if (exp.contains(null)) {
+            assertTrue(fromForEach.contains(null));
+        }
+        assertEquals(fromForEach.size(), exp.size());
+
+        assertContents(fromForEach, exp, isOrdered);
+    }
+
+    private static <T, S extends Spliterator<T>> void testTryAdvance(
+            Collection<T> exp,
+            Supplier<S> supplier,
+            UnaryOperator<Consumer<T>> boxingAdapter) {
+        S spliterator = supplier.get();
+        long sizeIfKnown = spliterator.getExactSizeIfKnown();
+        boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
+
+        spliterator = supplier.get();
+        ArrayList<T> fromTryAdvance = new ArrayList<>();
+        Consumer<T> addToFromTryAdvance = boxingAdapter.apply(fromTryAdvance::add);
+        while (spliterator.tryAdvance(addToFromTryAdvance)) { }
+
+        // Assert that forEach now produces no elements
+        spliterator.forEachRemaining(boxingAdapter.apply(e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e)));
+        // Assert that tryAdvance now produce no elements
+        spliterator.tryAdvance(boxingAdapter.apply(e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e)));
+
+        // assert that size, tryAdvance, and forEach are consistent
+        if (sizeIfKnown >= 0) {
+            assertEquals(sizeIfKnown, exp.size());
+        }
+        assertEquals(fromTryAdvance.size(), exp.size());
+
+        assertContents(fromTryAdvance, exp, isOrdered);
+    }
+
+    private static <T, S extends Spliterator<T>> void testMixedTryAdvanceForEach(
+            Collection<T> exp,
+            Supplier<S> supplier,
+            UnaryOperator<Consumer<T>> boxingAdapter) {
+        S spliterator = supplier.get();
+        long sizeIfKnown = spliterator.getExactSizeIfKnown();
+        boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
+
+        // tryAdvance first few elements, then forEach rest
+        ArrayList<T> dest = new ArrayList<>();
+        spliterator = supplier.get();
+        Consumer<T> addToDest = boxingAdapter.apply(dest::add);
+        for (int i = 0; i < 10 && spliterator.tryAdvance(addToDest); i++) { }
+        spliterator.forEachRemaining(addToDest);
+
+        // Assert that forEach now produces no elements
+        spliterator.forEachRemaining(boxingAdapter.apply(e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e)));
+        // Assert that tryAdvance now produce no elements
+        spliterator.tryAdvance(boxingAdapter.apply(e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e)));
+
+        if (sizeIfKnown >= 0) {
+            assertEquals(sizeIfKnown, dest.size());
+        }
+        assertEquals(dest.size(), exp.size());
+
+        if (isOrdered) {
+            assertEquals(dest, exp);
+        }
+        else {
+            assertContentsUnordered(dest, exp);
+        }
+    }
+
+    private static <T, S extends Spliterator<T>> void testSplitAfterFullTraversal(
+            Supplier<S> supplier,
+            UnaryOperator<Consumer<T>> boxingAdapter) {
+        // Full traversal using tryAdvance
+        Spliterator<T> spliterator = supplier.get();
+        while (spliterator.tryAdvance(boxingAdapter.apply(e -> { }))) { }
+        Spliterator<T> split = spliterator.trySplit();
+        assertNull(split);
+
+        // Full traversal using forEach
+        spliterator = supplier.get();
+        spliterator.forEachRemaining(boxingAdapter.apply(e -> {
+        }));
+        split = spliterator.trySplit();
+        assertNull(split);
+
+        // Full traversal using tryAdvance then forEach
+        spliterator = supplier.get();
+        spliterator.tryAdvance(boxingAdapter.apply(e -> { }));
+        spliterator.forEachRemaining(boxingAdapter.apply(e -> {
+        }));
+        split = spliterator.trySplit();
+        assertNull(split);
+    }
+
+    private static <T, S extends Spliterator<T>> void testSplitOnce(
+            Collection<T> exp,
+            Supplier<S> supplier,
+            UnaryOperator<Consumer<T>> boxingAdapter) {
+        S spliterator = supplier.get();
+        long sizeIfKnown = spliterator.getExactSizeIfKnown();
+        boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
+
+        ArrayList<T> fromSplit = new ArrayList<>();
+        Spliterator<T> s1 = supplier.get();
+        Spliterator<T> s2 = s1.trySplit();
+        long s1Size = s1.getExactSizeIfKnown();
+        long s2Size = (s2 != null) ? s2.getExactSizeIfKnown() : 0;
+
+        Consumer<T> addToFromSplit = boxingAdapter.apply(fromSplit::add);
+        if (s2 != null)
+            s2.forEachRemaining(addToFromSplit);
+        s1.forEachRemaining(addToFromSplit);
+
+        if (sizeIfKnown >= 0) {
+            assertEquals(sizeIfKnown, fromSplit.size());
+            if (s1Size >= 0 && s2Size >= 0)
+                assertEquals(sizeIfKnown, s1Size + s2Size);
+        }
+        assertContents(fromSplit, exp, isOrdered);
+    }
+
+    private static <T, S extends Spliterator<T>> void testSplitSixDeep(
+            Collection<T> exp,
+            Supplier<S> supplier,
+            UnaryOperator<Consumer<T>> boxingAdapter) {
+        S spliterator = supplier.get();
+        boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
+
+        for (int depth=0; depth < 6; depth++) {
+            List<T> dest = new ArrayList<>();
+            spliterator = supplier.get();
+
+            assertSpliterator(spliterator);
+
+            // verify splitting with forEach
+            visit(depth, 0, dest, spliterator, boxingAdapter, spliterator.characteristics(), false);
+            assertContents(dest, exp, isOrdered);
+
+            // verify splitting with tryAdvance
+            dest.clear();
+            spliterator = supplier.get();
+            visit(depth, 0, dest, spliterator, boxingAdapter, spliterator.characteristics(), true);
+            assertContents(dest, exp, isOrdered);
+        }
+    }
+
+    private static <T, S extends Spliterator<T>> void visit(int depth, int curLevel,
+                                                            List<T> dest, S spliterator, UnaryOperator<Consumer<T>> boxingAdapter,
+                                                            int rootCharacteristics, boolean useTryAdvance) {
+        if (curLevel < depth) {
+            long beforeSize = spliterator.getExactSizeIfKnown();
+            Spliterator<T> split = spliterator.trySplit();
+            if (split != null) {
+                assertSpliterator(split, rootCharacteristics);
+                assertSpliterator(spliterator, rootCharacteristics);
+
+                if ((rootCharacteristics & Spliterator.SUBSIZED) != 0 &&
+                    (rootCharacteristics & Spliterator.SIZED) != 0) {
+                    assertEquals(beforeSize, split.estimateSize() + spliterator.estimateSize());
+                }
+                visit(depth, curLevel + 1, dest, split, boxingAdapter, rootCharacteristics, useTryAdvance);
+            }
+            visit(depth, curLevel + 1, dest, spliterator, boxingAdapter, rootCharacteristics, useTryAdvance);
+        }
+        else {
+            long sizeIfKnown = spliterator.getExactSizeIfKnown();
+            if (useTryAdvance) {
+                Consumer<T> addToDest = boxingAdapter.apply(dest::add);
+                int count = 0;
+                while (spliterator.tryAdvance(addToDest)) {
+                    ++count;
+                }
+
+                if (sizeIfKnown >= 0)
+                    assertEquals(sizeIfKnown, count);
+
+                // Assert that forEach now produces no elements
+                spliterator.forEachRemaining(boxingAdapter.apply(e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e)));
+
+                Spliterator<T> split = spliterator.trySplit();
+                assertNull(split);
+            }
+            else {
+                List<T> leafDest = new ArrayList<>();
+                Consumer<T> addToLeafDest = boxingAdapter.apply(leafDest::add);
+                spliterator.forEachRemaining(addToLeafDest);
+
+                if (sizeIfKnown >= 0)
+                    assertEquals(sizeIfKnown, leafDest.size());
+
+                // Assert that forEach now produces no elements
+                spliterator.tryAdvance(boxingAdapter.apply(e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e)));
+
+                Spliterator<T> split = spliterator.trySplit();
+                assertNull(split);
+
+                dest.addAll(leafDest);
+            }
+        }
+    }
+
+    private static <T, S extends Spliterator<T>> void testSplitUntilNull(
+            Collection<T> exp,
+            Supplier<S> supplier,
+            UnaryOperator<Consumer<T>> boxingAdapter) {
+        Spliterator<T> s = supplier.get();
+        boolean isOrdered = s.hasCharacteristics(Spliterator.ORDERED);
+        assertSpliterator(s);
+
+        List<T> splits = new ArrayList<>();
+        Consumer<T> c = boxingAdapter.apply(splits::add);
+
+        testSplitUntilNull(new SplitNode<T>(c, s));
+        assertContents(splits, exp, isOrdered);
+    }
+
+    private static class SplitNode<T> {
+        // Constant for every node
+        final Consumer<T> c;
+        final int rootCharacteristics;
+
+        final Spliterator<T> s;
+
+        SplitNode(Consumer<T> c, Spliterator<T> s) {
+            this(c, s.characteristics(), s);
+        }
+
+        private SplitNode(Consumer<T> c, int rootCharacteristics, Spliterator<T> s) {
+            this.c = c;
+            this.rootCharacteristics = rootCharacteristics;
+            this.s = s;
+        }
+
+        SplitNode<T> fromSplit(Spliterator<T> split) {
+            return new SplitNode<>(c, rootCharacteristics, split);
+        }
+    }
+
+    /**
+     * Set the maximum stack capacity to 0.25MB. This should be more than enough to detect a bad spliterator
+     * while not unduly disrupting test infrastructure given the test data sizes that are used are small.
+     * Note that j.u.c.ForkJoinPool sets the max queue size to 64M (1 << 26).
+     */
+    private static final int MAXIMUM_STACK_CAPACITY = 1 << 18; // 0.25MB
+
+    private static <T> void testSplitUntilNull(SplitNode<T> e) {
+        // Use an explicit stack to avoid a StackOverflowException when testing a Spliterator
+        // that when repeatedly split produces a right-balanced (and maybe degenerate) tree, or
+        // for a spliterator that is badly behaved.
+        Deque<SplitNode<T>> stack = new ArrayDeque<>();
+        stack.push(e);
+
+        int iteration = 0;
+        while (!stack.isEmpty()) {
+            assertTrue(iteration++ < MAXIMUM_STACK_CAPACITY, "Exceeded maximum stack modification count of 1 << 18");
+
+            e = stack.pop();
+            Spliterator<T> parentAndRightSplit = e.s;
+
+            long parentEstimateSize = parentAndRightSplit.estimateSize();
+            assertTrue(parentEstimateSize >= 0,
+                       String.format("Split size estimate %d < 0", parentEstimateSize));
+
+            long parentSize = parentAndRightSplit.getExactSizeIfKnown();
+            Spliterator<T> leftSplit = parentAndRightSplit.trySplit();
+            if (leftSplit == null) {
+                parentAndRightSplit.forEachRemaining(e.c);
+                continue;
+            }
+
+            assertSpliterator(leftSplit, e.rootCharacteristics);
+            assertSpliterator(parentAndRightSplit, e.rootCharacteristics);
+
+            if (parentEstimateSize != Long.MAX_VALUE && leftSplit.estimateSize() > 0 && parentAndRightSplit.estimateSize() > 0) {
+                assertTrue(leftSplit.estimateSize() < parentEstimateSize,
+                           String.format("Left split size estimate %d >= parent split size estimate %d", leftSplit.estimateSize(), parentEstimateSize));
+                assertTrue(parentAndRightSplit.estimateSize() < parentEstimateSize,
+                           String.format("Right split size estimate %d >= parent split size estimate %d", leftSplit.estimateSize(), parentEstimateSize));
+            }
+            else {
+                assertTrue(leftSplit.estimateSize() <= parentEstimateSize,
+                           String.format("Left split size estimate %d > parent split size estimate %d", leftSplit.estimateSize(), parentEstimateSize));
+                assertTrue(parentAndRightSplit.estimateSize() <= parentEstimateSize,
+                           String.format("Right split size estimate %d > parent split size estimate %d", leftSplit.estimateSize(), parentEstimateSize));
+            }
+
+            long leftSize = leftSplit.getExactSizeIfKnown();
+            long rightSize = parentAndRightSplit.getExactSizeIfKnown();
+            if (parentSize >= 0 && leftSize >= 0 && rightSize >= 0)
+                assertEquals(parentSize, leftSize + rightSize,
+                             String.format("exact left split size %d + exact right split size %d != parent exact split size %d",
+                                           leftSize, rightSize, parentSize));
+
+            // Add right side to stack first so left side is popped off first
+            stack.push(e.fromSplit(parentAndRightSplit));
+            stack.push(e.fromSplit(leftSplit));
+        }
+    }
+
+    private static void assertSpliterator(Spliterator<?> s, int rootCharacteristics) {
+        if ((rootCharacteristics & Spliterator.SUBSIZED) != 0) {
+            assertTrue(s.hasCharacteristics(Spliterator.SUBSIZED),
+                       "Child split is not SUBSIZED when root split is SUBSIZED");
+        }
+        assertSpliterator(s);
+    }
+
+    private static void assertSpliterator(Spliterator<?> s) {
+        if (s.hasCharacteristics(Spliterator.SUBSIZED)) {
+            assertTrue(s.hasCharacteristics(Spliterator.SIZED));
+        }
+        if (s.hasCharacteristics(Spliterator.SIZED)) {
+            assertTrue(s.estimateSize() != Long.MAX_VALUE);
+            assertTrue(s.getExactSizeIfKnown() >= 0);
+        }
+        try {
+            s.getComparator();
+            assertTrue(s.hasCharacteristics(Spliterator.SORTED));
+        } catch (IllegalStateException e) {
+            assertFalse(s.hasCharacteristics(Spliterator.SORTED));
+        }
+    }
+
+    private static<T> void assertContents(Collection<T> actual, Collection<T> expected, boolean isOrdered) {
+        if (isOrdered) {
+            assertEquals(actual, expected);
+        }
+        else {
+            assertContentsUnordered(actual, expected);
+        }
+    }
+
+    private static<T> void assertContentsUnordered(Iterable<T> actual, Iterable<T> expected) {
+        assertEquals(toBoxedMultiset(actual), toBoxedMultiset(expected));
+    }
+
+    private static <T> Map<T, HashableInteger> toBoxedMultiset(Iterable<T> c) {
+        Map<T, HashableInteger> result = new HashMap<>();
+        c.forEach((Consumer) e -> {
+            if (result.containsKey((T)e)) {
+                result.put((T)e, new HashableInteger(((HashableInteger)result.get(e)).value + 1, 10));
+            } else {
+                result.put((T)e, new HashableInteger(1, 10));
+            }
+        });
+        return result;
+    }
+
+    private void executeAndCatch(Class<? extends Exception> expected, Runnable r) {
+        Exception caught = null;
+        try {
+            r.run();
+        }
+        catch (Exception e) {
+            caught = e;
+        }
+
+        assertNotNull(caught,
+                      String.format("No Exception was thrown, expected an Exception of %s to be thrown",
+                                    expected.getName()));
+        assertTrue(expected.isInstance(caught),
+                   String.format("Exception thrown %s not an instance of %s",
+                                 caught.getClass().getName(), expected.getName()));
+    }
+
+}
--- a/jdk/test/java/util/Spliterator/SpliteratorTraversingAndSplittingTest.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/util/Spliterator/SpliteratorTraversingAndSplittingTest.java	Mon Jun 10 10:38:33 2013 +0100
@@ -128,6 +128,10 @@
 
         void addMap(Function<Map<T, T>, ? extends Map<T, T>> m) {
             String description = "new " + m.apply(Collections.<T, T>emptyMap()).getClass().getName();
+            addMap(m, description);
+        }
+
+        void addMap(Function<Map<T, T>, ? extends Map<T, T>> m, String description) {
             add(description + ".keySet().spliterator()", () -> m.apply(mExp).keySet().spliterator());
             add(description + ".values().spliterator()", () -> m.apply(mExp).values().spliterator());
             add(description + ".entrySet().spliterator()", mExp.entrySet(), () -> m.apply(mExp).entrySet().spliterator());
@@ -399,12 +403,36 @@
 
             db.addMap(HashMap::new);
 
+            db.addMap(m -> {
+                // Create a Map ensuring that for large sizes
+                // buckets will contain 2 or more entries
+                HashMap<Integer, Integer> cm = new HashMap<>(1, m.size() + 1);
+                // Don't use putAll which inflates the table by
+                // m.size() * loadFactor, thus creating a very sparse
+                // map for 1000 entries defeating the purpose of this test,
+                // in addition it will cause the split until null test to fail
+                // because the number of valid splits is larger than the
+                // threshold
+                for (Map.Entry<Integer, Integer> e : m.entrySet())
+                    cm.put(e.getKey(), e.getValue());
+                return cm;
+            }, "new java.util.HashMap(1, size + 1)");
+
             db.addMap(LinkedHashMap::new);
 
             db.addMap(IdentityHashMap::new);
 
             db.addMap(WeakHashMap::new);
 
+            db.addMap(m -> {
+                // Create a Map ensuring that for large sizes
+                // buckets will be consist of 2 or more entries
+                WeakHashMap<Integer, Integer> cm = new WeakHashMap<>(1, m.size() + 1);
+                for (Map.Entry<Integer, Integer> e : m.entrySet())
+                    cm.put(e.getKey(), e.getValue());
+                return cm;
+            }, "new java.util.WeakHashMap(1, size + 1)");
+
             // @@@  Descending maps etc
             db.addMap(TreeMap::new);
 
--- a/jdk/test/java/util/jar/TestExtra.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/util/jar/TestExtra.java	Mon Jun 10 10:38:33 2013 +0100
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @bug 6480504
+ * @bug 6480504 6303183
  * @summary Test that client-provided data in the extra field is written and
  * read correctly, taking into account the JAR_MAGIC written into the extra
  * field of the first entry of JAR files.
@@ -117,8 +117,7 @@
         ZipInputStream zis = getInputStream();
 
         ze = zis.getNextEntry();
-        byte[] e = ze.getExtra();
-        check(e.length == 8, "expected extra length is 8, got " + e.length);
+        checkExtra(data, ze.getExtra());
         checkEntry(ze, 0, 0);
     }
 
@@ -140,10 +139,43 @@
         ZipInputStream zis = getInputStream();
         ze = zis.getNextEntry();
         byte[] e = ze.getExtra();
-        check(e.length == 8, "expected extra length is 8, got " + e.length);
+        checkExtra(data, ze.getExtra());
         checkEntry(ze, 0, 0);
     }
 
+    // check if all "expected" extra fields equal to their
+    // corresponding fields in "extra". The "extra" might have
+    // timestamp fields added by ZOS.
+    static void checkExtra(byte[] expected, byte[] extra) {
+        if (expected == null)
+            return;
+        int off = 0;
+        int len = expected.length;
+        while (off + 4 < len) {
+            int tag = get16(expected, off);
+            int sz = get16(expected, off + 2);
+            int off0 = 0;
+            int len0 = extra.length;
+            boolean matched = false;
+            while (off0 + 4 < len0) {
+                int tag0 = get16(extra, off0);
+                int sz0 = get16(extra, off0 + 2);
+                if (tag == tag0 && sz == sz0) {
+                    matched = true;
+                    for (int i = 0; i < sz; i++) {
+                        if (expected[off + i] != extra[off0 +i])
+                            matched = false;
+                    }
+                    break;
+                }
+                off0 += (4 + sz0);
+            }
+            if (!matched) {
+                fail("Expected extra data [tag=" + tag + "sz=" + sz + "] check failed");
+            }
+            off += (4 + sz);
+        }
+    }
 
     /** Check that the entry's extra data is correct. */
     void checkEntry(ZipEntry ze, int count, int dataLength) {
--- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/SpliteratorLateBindingFailFastTest.java	Fri May 31 10:34:25 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,358 +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.
- */
-package org.openjdk.tests.java.util.stream;
-
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.ConcurrentModificationException;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.PriorityQueue;
-import java.util.Set;
-import java.util.Spliterator;
-import java.util.Stack;
-import java.util.TreeMap;
-import java.util.TreeSet;
-import java.util.Vector;
-import java.util.WeakHashMap;
-import java.util.function.Consumer;
-import java.util.function.Function;
-import java.util.function.Supplier;
-
-import static org.testng.Assert.*;
-
-/**
- * @test
- * @summary Spliterator last-binding and fail-fast tests
- * @run testng SpliteratorLateBindingFailFastTest
- */
-
-@Test(groups = { "serialization-hostile" })
-public class SpliteratorLateBindingFailFastTest {
-
-    private interface Source<T> {
-        Collection<T> asCollection();
-        void update();
-    }
-
-    private static class SpliteratorDataBuilder<T> {
-        final List<Object[]> data;
-
-        final T newValue;
-
-        final List<T> exp;
-
-        final Map<T, T> mExp;
-
-        SpliteratorDataBuilder(List<Object[]> data, T newValue, List<T> exp) {
-            this.data = data;
-            this.newValue = newValue;
-            this.exp = exp;
-            this.mExp = createMap(exp);
-        }
-
-        Map<T, T> createMap(List<T> l) {
-            Map<T, T> m = new LinkedHashMap<>();
-            for (T t : l) {
-                m.put(t, t);
-            }
-            return m;
-        }
-
-        void add(String description, Supplier<Source<?>> s) {
-            description = joiner(description).toString();
-            data.add(new Object[]{description, s});
-        }
-
-        void addCollection(Function<Collection<T>, ? extends Collection<T>> f) {
-            class CollectionSource implements Source<T> {
-                final Collection<T> c = f.apply(exp);
-
-                final Consumer<Collection<T>> updater;
-
-                CollectionSource(Consumer<Collection<T>> updater) {
-                    this.updater = updater;
-                }
-
-                @Override
-                public Collection<T> asCollection() {
-                    return c;
-                }
-
-                @Override
-                public void update() {
-                    updater.accept(c);
-                }
-            }
-
-            String description = "new " + f.apply(Collections.<T>emptyList()).getClass().getName() + ".spliterator() ";
-            add(description + "ADD", () -> new CollectionSource(c -> c.add(newValue)));
-            add(description + "REMOVE", () -> new CollectionSource(c -> c.remove(c.iterator().next())));
-        }
-
-        void addList(Function<Collection<T>, ? extends List<T>> l) {
-            // @@@ If collection is instance of List then add sub-list tests
-            addCollection(l);
-        }
-
-        void addMap(Function<Map<T, T>, ? extends Map<T, T>> mapConstructor) {
-            class MapSource<U> implements Source<U> {
-                final Map<T, T> m = mapConstructor.apply(mExp);
-
-                final Collection<U> c;
-
-                final Consumer<Map<T, T>> updater;
-
-                MapSource(Function<Map<T, T>, Collection<U>> f, Consumer<Map<T, T>> updater) {
-                    this.c = f.apply(m);
-                    this.updater = updater;
-                }
-
-                @Override
-                public Collection<U> asCollection() {
-                    return c;
-                }
-
-                @Override
-                public void update() {
-                    updater.accept(m);
-                }
-            }
-
-            Map<String, Consumer<Map<T, T>>> actions = new HashMap<>();
-            actions.put("ADD", m -> m.put(newValue, newValue));
-            actions.put("REMOVE", m -> m.remove(m.keySet().iterator().next()));
-
-            String description = "new " + mapConstructor.apply(Collections.<T, T>emptyMap()).getClass().getName();
-            for (Map.Entry<String, Consumer<Map<T, T>>> e : actions.entrySet()) {
-                add(description + ".keySet().spliterator() " + e.getKey(),
-                    () -> new MapSource<T>(m -> m.keySet(), e.getValue()));
-                add(description + ".values().spliterator() " + e.getKey(),
-                    () -> new MapSource<T>(m -> m.values(), e.getValue()));
-                add(description + ".entrySet().spliterator() " + e.getKey(),
-                    () -> new MapSource<Map.Entry<T, T>>(m -> m.entrySet(), e.getValue()));
-            }
-        }
-
-        StringBuilder joiner(String description) {
-            return new StringBuilder(description).
-                    append(" {").
-                    append("size=").append(exp.size()).
-                    append("}");
-        }
-    }
-
-    static Object[][] spliteratorDataProvider;
-
-    @DataProvider(name = "Source")
-    public static Object[][] spliteratorDataProvider() {
-        if (spliteratorDataProvider != null) {
-            return spliteratorDataProvider;
-        }
-
-        List<Object[]> data = new ArrayList<>();
-        SpliteratorDataBuilder<Integer> db = new SpliteratorDataBuilder<>(data, 5, Arrays.asList(1, 2, 3, 4));
-
-        // Collections
-
-        db.addList(ArrayList::new);
-
-        db.addList(LinkedList::new);
-
-        db.addList(Vector::new);
-
-
-        db.addCollection(HashSet::new);
-
-        db.addCollection(LinkedHashSet::new);
-
-        db.addCollection(TreeSet::new);
-
-
-        db.addCollection(c -> { Stack<Integer> s = new Stack<>(); s.addAll(c); return s;});
-
-        db.addCollection(PriorityQueue::new);
-
-        // ArrayDeque fails some tests since it's fail-fast support is weaker
-        // than other collections and limited to detecting most, but not all,
-        // removals.  It probably requires it's own test since it is difficult
-        // to abstract out the conditions under which it fails-fast.
-//        db.addCollection(ArrayDeque::new);
-
-        // Maps
-
-        db.addMap(HashMap::new);
-
-        db.addMap(LinkedHashMap::new);
-
-        // This fails when run through jrteg but passes when run though
-        // ant
-//        db.addMap(IdentityHashMap::new);
-
-        db.addMap(WeakHashMap::new);
-
-        // @@@  Descending maps etc
-        db.addMap(TreeMap::new);
-
-        return spliteratorDataProvider = data.toArray(new Object[0][]);
-    }
-
-    @Test(dataProvider = "Source")
-    public <T> void lateBindingTestWithForEach(String description, Supplier<Source<T>> ss) {
-        Source<T> source = ss.get();
-        Collection<T> c = source.asCollection();
-        Spliterator<T> s = c.spliterator();
-
-        source.update();
-
-        Set<T> r = new HashSet<>();
-        s.forEachRemaining(r::add);
-
-        assertEquals(r, new HashSet<>(c));
-    }
-
-    @Test(dataProvider = "Source")
-    public <T> void lateBindingTestWithTryAdvance(String description, Supplier<Source<T>> ss) {
-        Source<T> source = ss.get();
-        Collection<T> c = source.asCollection();
-        Spliterator<T> s = c.spliterator();
-
-        source.update();
-
-        Set<T> r = new HashSet<>();
-        while (s.tryAdvance(r::add)) { }
-
-        assertEquals(r, new HashSet<>(c));
-    }
-
-    @Test(dataProvider = "Source")
-    public <T> void lateBindingTestWithCharacteritics(String description, Supplier<Source<T>> ss) {
-        Source<T> source = ss.get();
-        Collection<T> c = source.asCollection();
-        Spliterator<T> s = c.spliterator();
-        s.characteristics();
-
-        Set<T> r = new HashSet<>();
-        s.forEachRemaining(r::add);
-
-        assertEquals(r, new HashSet<>(c));
-    }
-
-
-    @Test(dataProvider = "Source")
-    public <T> void testFailFastTestWithTryAdvance(String description, Supplier<Source<T>> ss) {
-        {
-            Source<T> source = ss.get();
-            Collection<T> c = source.asCollection();
-            Spliterator<T> s = c.spliterator();
-
-            s.tryAdvance(e -> {
-            });
-            source.update();
-
-            executeAndCatch(() -> s.tryAdvance(e -> { }));
-        }
-
-        {
-            Source<T> source = ss.get();
-            Collection<T> c = source.asCollection();
-            Spliterator<T> s = c.spliterator();
-
-            s.tryAdvance(e -> {
-            });
-            source.update();
-
-            executeAndCatch(() -> s.forEachRemaining(e -> {
-            }));
-        }
-    }
-
-    @Test(dataProvider = "Source")
-    public <T> void testFailFastTestWithForEach(String description, Supplier<Source<T>> ss) {
-        Source<T> source = ss.get();
-        Collection<T> c = source.asCollection();
-        Spliterator<T> s = c.spliterator();
-
-        executeAndCatch(() -> s.forEachRemaining(e -> {
-            source.update();
-        }));
-    }
-
-    @Test(dataProvider = "Source")
-    public <T> void testFailFastTestWithEstimateSize(String description, Supplier<Source<T>> ss) {
-        {
-            Source<T> source = ss.get();
-            Collection<T> c = source.asCollection();
-            Spliterator<T> s = c.spliterator();
-
-            s.estimateSize();
-            source.update();
-
-            executeAndCatch(() -> s.tryAdvance(e -> { }));
-        }
-
-        {
-            Source<T> source = ss.get();
-            Collection<T> c = source.asCollection();
-            Spliterator<T> s = c.spliterator();
-
-            s.estimateSize();
-            source.update();
-
-            executeAndCatch(() -> s.forEachRemaining(e -> {
-            }));
-        }
-    }
-
-    private void executeAndCatch(Runnable r) {
-        executeAndCatch(ConcurrentModificationException.class, r);
-    }
-
-    private void executeAndCatch(Class<? extends Exception> expected, Runnable r) {
-        Exception caught = null;
-        try {
-            r.run();
-        }
-        catch (Exception e) {
-            caught = e;
-        }
-
-        assertNotNull(caught,
-                      String.format("No Exception was thrown, expected an Exception of %s to be thrown",
-                                    expected.getName()));
-        assertTrue(expected.isInstance(caught),
-                   String.format("Exception thrown %s not an instance of %s",
-                                 caught.getClass().getName(), expected.getName()));
-    }
-
-}
--- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/SpliteratorTraversingAndSplittingTest.java	Fri May 31 10:34:25 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1411 +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.
- */
-package org.openjdk.tests.java.util.stream;
-
-/**
- * @test
- * @summary Spliterator traversing and splitting tests
- * @run testng SpliteratorTraversingAndSplittingTest
- */
-
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
-
-import java.util.AbstractCollection;
-import java.util.AbstractList;
-import java.util.AbstractSet;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Deque;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.IdentityHashMap;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.PriorityQueue;
-import java.util.Set;
-import java.util.SortedSet;
-import java.util.Spliterator;
-import java.util.Spliterators;
-import java.util.Stack;
-import java.util.TreeMap;
-import java.util.TreeSet;
-import java.util.Vector;
-import java.util.WeakHashMap;
-import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.ConcurrentSkipListMap;
-import java.util.concurrent.ConcurrentSkipListSet;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.CopyOnWriteArraySet;
-import java.util.concurrent.LinkedBlockingDeque;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.LinkedTransferQueue;
-import java.util.concurrent.PriorityBlockingQueue;
-import java.util.function.Consumer;
-import java.util.function.DoubleConsumer;
-import java.util.function.Function;
-import java.util.function.IntConsumer;
-import java.util.function.LongConsumer;
-import java.util.function.Supplier;
-import java.util.function.UnaryOperator;
-
-import static org.testng.Assert.*;
-import static org.testng.Assert.assertEquals;
-
-@Test(groups = { "serialization-hostile" })
-public class SpliteratorTraversingAndSplittingTest {
-
-    private static List<Integer> SIZES = Arrays.asList(0, 1, 10, 100, 1000);
-
-    private static class SpliteratorDataBuilder<T> {
-        List<Object[]> data;
-
-        List<T> exp;
-
-        Map<T, T> mExp;
-
-        SpliteratorDataBuilder(List<Object[]> data, List<T> exp) {
-            this.data = data;
-            this.exp = exp;
-            this.mExp = createMap(exp);
-        }
-
-        Map<T, T> createMap(List<T> l) {
-            Map<T, T> m = new LinkedHashMap<>();
-            for (T t : l) {
-                m.put(t, t);
-            }
-            return m;
-        }
-
-        void add(String description, Collection<?> expected, Supplier<Spliterator<?>> s) {
-            description = joiner(description).toString();
-            data.add(new Object[]{description, expected, s});
-        }
-
-        void add(String description, Supplier<Spliterator<?>> s) {
-            add(description, exp, s);
-        }
-
-        void addCollection(Function<Collection<T>, ? extends Collection<T>> c) {
-            add("new " + c.apply(Collections.<T>emptyList()).getClass().getName() + ".spliterator()",
-                () -> c.apply(exp).spliterator());
-        }
-
-        void addList(Function<Collection<T>, ? extends List<T>> l) {
-            // @@@ If collection is instance of List then add sub-list tests
-            addCollection(l);
-        }
-
-        void addMap(Function<Map<T, T>, ? extends Map<T, T>> m) {
-            String description = "new " + m.apply(Collections.<T, T>emptyMap()).getClass().getName();
-            add(description + ".keySet().spliterator()", () -> m.apply(mExp).keySet().spliterator());
-            add(description + ".values().spliterator()", () -> m.apply(mExp).values().spliterator());
-            add(description + ".entrySet().spliterator()", mExp.entrySet(), () -> m.apply(mExp).entrySet().spliterator());
-        }
-
-        StringBuilder joiner(String description) {
-            return new StringBuilder(description).
-                    append(" {").
-                    append("size=").append(exp.size()).
-                    append("}");
-        }
-    }
-
-    static Object[][] spliteratorDataProvider;
-
-    @DataProvider(name = "Spliterator<Integer>")
-    public static Object[][] spliteratorDataProvider() {
-        if (spliteratorDataProvider != null) {
-            return spliteratorDataProvider;
-        }
-
-        List<Object[]> data = new ArrayList<>();
-        for (int size : SIZES) {
-            List<Integer> exp = listIntRange(size);
-            SpliteratorDataBuilder<Integer> db = new SpliteratorDataBuilder<>(data, exp);
-
-            // Direct spliterator methods
-
-            db.add("Spliterators.spliterator(Collection, ...)",
-                   () -> Spliterators.spliterator(exp, 0));
-
-            db.add("Spliterators.spliterator(Iterator, ...)",
-                   () -> Spliterators.spliterator(exp.iterator(), exp.size(), 0));
-
-            db.add("Spliterators.spliteratorUnknownSize(Iterator, ...)",
-                   () -> Spliterators.spliteratorUnknownSize(exp.iterator(), 0));
-
-            db.add("Spliterators.spliterator(Spliterators.iteratorFromSpliterator(Spliterator ), ...)",
-                   () -> Spliterators.spliterator(Spliterators.iteratorFromSpliterator(exp.spliterator()), exp.size(), 0));
-
-            db.add("Spliterators.spliterator(T[], ...)",
-                   () -> Spliterators.spliterator(exp.toArray(new Integer[0]), 0));
-
-            db.add("Arrays.spliterator(T[], ...)",
-                   () -> Arrays.spliterator(exp.toArray(new Integer[0])));
-
-            class SpliteratorFromIterator extends Spliterators.AbstractSpliterator<Integer> {
-                Iterator<Integer> it;
-
-                SpliteratorFromIterator(Iterator<Integer> it, long est) {
-                    super(est, Spliterator.SIZED);
-                    this.it = it;
-                }
-
-                @Override
-                public boolean tryAdvance(Consumer<? super Integer> action) {
-                    if (action == null)
-                        throw new NullPointerException();
-                    if (it.hasNext()) {
-                        action.accept(it.next());
-                        return true;
-                    }
-                    else {
-                        return false;
-                    }
-                }
-            }
-            db.add("new Spliterators.AbstractSpliterator()",
-                   () -> new SpliteratorFromIterator(exp.iterator(), exp.size()));
-
-            // Collections
-
-            // default method implementations
-
-            class AbstractCollectionImpl extends AbstractCollection<Integer> {
-                Collection<Integer> c;
-
-                AbstractCollectionImpl(Collection<Integer> c) {
-                    this.c = c;
-                }
-
-                @Override
-                public Iterator<Integer> iterator() {
-                    return c.iterator();
-                }
-
-                @Override
-                public int size() {
-                    return c.size();
-                }
-            }
-            db.addCollection(
-                    c -> new AbstractCollectionImpl(c));
-
-            class AbstractListImpl extends AbstractList<Integer> {
-                List<Integer> l;
-
-                AbstractListImpl(Collection<Integer> c) {
-                    this.l = new ArrayList<>(c);
-                }
-
-                @Override
-                public Integer get(int index) {
-                    return l.get(index);
-                }
-
-                @Override
-                public int size() {
-                    return l.size();
-                }
-            }
-            db.addCollection(
-                    c -> new AbstractListImpl(c));
-
-            class AbstractSetImpl extends AbstractSet<Integer> {
-                Set<Integer> s;
-
-                AbstractSetImpl(Collection<Integer> c) {
-                    this.s = new HashSet<>(c);
-                }
-
-                @Override
-                public Iterator<Integer> iterator() {
-                    return s.iterator();
-                }
-
-                @Override
-                public int size() {
-                    return s.size();
-                }
-            }
-            db.addCollection(
-                    c -> new AbstractSetImpl(c));
-
-            class AbstractSortedSetImpl extends AbstractSet<Integer> implements SortedSet<Integer> {
-                SortedSet<Integer> s;
-
-                AbstractSortedSetImpl(Collection<Integer> c) {
-                    this.s = new TreeSet<>(c);
-                }
-
-                @Override
-                public Iterator<Integer> iterator() {
-                    return s.iterator();
-                }
-
-                @Override
-                public int size() {
-                    return s.size();
-                }
-
-                @Override
-                public Comparator<? super Integer> comparator() {
-                    return s.comparator();
-                }
-
-                @Override
-                public SortedSet<Integer> subSet(Integer fromElement, Integer toElement) {
-                    return s.subSet(fromElement, toElement);
-                }
-
-                @Override
-                public SortedSet<Integer> headSet(Integer toElement) {
-                    return s.headSet(toElement);
-                }
-
-                @Override
-                public SortedSet<Integer> tailSet(Integer fromElement) {
-                    return s.tailSet(fromElement);
-                }
-
-                @Override
-                public Integer first() {
-                    return s.first();
-                }
-
-                @Override
-                public Integer last() {
-                    return s.last();
-                }
-
-                @Override
-                public Spliterator<Integer> spliterator() {
-                    return SortedSet.super.spliterator();
-                }
-            }
-            db.addCollection(
-                    c -> new AbstractSortedSetImpl(c));
-
-            //
-
-            db.add("Arrays.asList().spliterator()",
-                   () -> Spliterators.spliterator(Arrays.asList(exp.toArray(new Integer[0])), 0));
-
-            db.addList(ArrayList::new);
-
-            db.addList(LinkedList::new);
-
-            db.addList(Vector::new);
-
-
-            db.addCollection(HashSet::new);
-
-            db.addCollection(LinkedHashSet::new);
-
-            db.addCollection(TreeSet::new);
-
-
-            db.addCollection(c -> { Stack<Integer> s = new Stack<>(); s.addAll(c); return s;});
-
-            db.addCollection(PriorityQueue::new);
-
-            db.addCollection(ArrayDeque::new);
-
-
-            db.addCollection(ConcurrentSkipListSet::new);
-
-            if (size > 0) {
-                db.addCollection(c -> {
-                    ArrayBlockingQueue<Integer> abq = new ArrayBlockingQueue<>(size);
-                    abq.addAll(c);
-                    return abq;
-                });
-            }
-
-            db.addCollection(PriorityBlockingQueue::new);
-
-            db.addCollection(LinkedBlockingQueue::new);
-
-            db.addCollection(LinkedTransferQueue::new);
-
-            db.addCollection(ConcurrentLinkedQueue::new);
-
-            db.addCollection(LinkedBlockingDeque::new);
-
-            db.addCollection(CopyOnWriteArrayList::new);
-
-            db.addCollection(CopyOnWriteArraySet::new);
-
-            if (size == 1) {
-                db.addCollection(c -> Collections.singleton(exp.get(0)));
-                db.addCollection(c -> Collections.singletonList(exp.get(0)));
-            }
-
-            // Collections.synchronized/unmodifiable/checked wrappers
-            db.addCollection(Collections::unmodifiableCollection);
-            db.addCollection(c -> Collections.unmodifiableSet(new HashSet<>(c)));
-            db.addCollection(c -> Collections.unmodifiableSortedSet(new TreeSet<>(c)));
-            db.addList(c -> Collections.unmodifiableList(new ArrayList<>(c)));
-            db.addMap(Collections::unmodifiableMap);
-            db.addMap(m -> Collections.unmodifiableSortedMap(new TreeMap<>(m)));
-
-            db.addCollection(Collections::synchronizedCollection);
-            db.addCollection(c -> Collections.synchronizedSet(new HashSet<>(c)));
-            db.addCollection(c -> Collections.synchronizedSortedSet(new TreeSet<>(c)));
-            db.addList(c -> Collections.synchronizedList(new ArrayList<>(c)));
-            db.addMap(Collections::synchronizedMap);
-            db.addMap(m -> Collections.synchronizedSortedMap(new TreeMap<>(m)));
-
-            db.addCollection(c -> Collections.checkedCollection(c, Integer.class));
-            db.addCollection(c -> Collections.checkedQueue(new ArrayDeque<>(c), Integer.class));
-            db.addCollection(c -> Collections.checkedSet(new HashSet<>(c), Integer.class));
-            db.addCollection(c -> Collections.checkedSortedSet(new TreeSet<>(c), Integer.class));
-            db.addList(c -> Collections.checkedList(new ArrayList<>(c), Integer.class));
-            db.addMap(c -> Collections.checkedMap(c, Integer.class, Integer.class));
-            db.addMap(m -> Collections.checkedSortedMap(new TreeMap<>(m), Integer.class, Integer.class));
-
-            // Maps
-
-            db.addMap(HashMap::new);
-
-            db.addMap(LinkedHashMap::new);
-
-            db.addMap(IdentityHashMap::new);
-
-            db.addMap(WeakHashMap::new);
-
-            // @@@  Descending maps etc
-            db.addMap(TreeMap::new);
-
-            db.addMap(ConcurrentHashMap::new);
-
-            db.addMap(ConcurrentSkipListMap::new);
-        }
-
-        return spliteratorDataProvider = data.toArray(new Object[0][]);
-    }
-
-    private static List<Integer> listIntRange(int upTo) {
-        List<Integer> exp = new ArrayList<>();
-        for (int i = 0; i < upTo; i++)
-            exp.add(i);
-        return Collections.unmodifiableList(exp);
-    }
-
-    @Test(dataProvider = "Spliterator<Integer>")
-    @SuppressWarnings({"unchecked", "rawtypes"})
-    public void testNullPointerException(String description, Collection exp, Supplier<Spliterator> s) {
-        executeAndCatch(NullPointerException.class, () -> s.get().forEachRemaining(null));
-        executeAndCatch(NullPointerException.class, () -> s.get().tryAdvance(null));
-    }
-
-    @Test(dataProvider = "Spliterator<Integer>")
-    @SuppressWarnings({"unchecked", "rawtypes"})
-    public void testForEach(String description, Collection exp, Supplier<Spliterator> s) {
-        testForEach(exp, s, (Consumer<Object> b) -> b);
-    }
-
-    @Test(dataProvider = "Spliterator<Integer>")
-    @SuppressWarnings({"unchecked", "rawtypes"})
-    public void testTryAdvance(String description, Collection exp, Supplier<Spliterator> s) {
-        testTryAdvance(exp, s, (Consumer<Object> b) -> b);
-    }
-
-    @Test(dataProvider = "Spliterator<Integer>")
-    @SuppressWarnings({"unchecked", "rawtypes"})
-    public void testMixedTryAdvanceForEach(String description, Collection exp, Supplier<Spliterator> s) {
-        testMixedTryAdvanceForEach(exp, s, (Consumer<Object> b) -> b);
-    }
-
-    @Test(dataProvider = "Spliterator<Integer>")
-    @SuppressWarnings({"unchecked", "rawtypes"})
-    public void testMixedTraverseAndSplit(String description, Collection exp, Supplier<Spliterator> s) {
-        testMixedTraverseAndSplit(exp, s, (Consumer<Object> b) -> b);
-    }
-
-    @Test(dataProvider = "Spliterator<Integer>")
-    @SuppressWarnings({"unchecked", "rawtypes"})
-    public void testSplitAfterFullTraversal(String description, Collection exp, Supplier<Spliterator> s) {
-        testSplitAfterFullTraversal(s, (Consumer<Object> b) -> b);
-    }
-
-    @Test(dataProvider = "Spliterator<Integer>")
-    @SuppressWarnings({"unchecked", "rawtypes"})
-    public void testSplitOnce(String description, Collection exp, Supplier<Spliterator> s) {
-        testSplitOnce(exp, s, (Consumer<Object> b) -> b);
-    }
-
-    @Test(dataProvider = "Spliterator<Integer>")
-    @SuppressWarnings({"unchecked", "rawtypes"})
-    public void testSplitSixDeep(String description, Collection exp, Supplier<Spliterator> s) {
-        testSplitSixDeep(exp, s, (Consumer<Object> b) -> b);
-    }
-
-    @Test(dataProvider = "Spliterator<Integer>")
-    @SuppressWarnings({"unchecked", "rawtypes"})
-    public void testSplitUntilNull(String description, Collection exp, Supplier<Spliterator> s) {
-        testSplitUntilNull(exp, s, (Consumer<Object> b) -> b);
-    }
-
-    //
-
-    private static class SpliteratorOfIntDataBuilder {
-        List<Object[]> data;
-
-        List<Integer> exp;
-
-        SpliteratorOfIntDataBuilder(List<Object[]> data, List<Integer> exp) {
-            this.data = data;
-            this.exp = exp;
-        }
-
-        void add(String description, List<Integer> expected, Supplier<Spliterator.OfInt> s) {
-            description = joiner(description).toString();
-            data.add(new Object[]{description, expected, s});
-        }
-
-        void add(String description, Supplier<Spliterator.OfInt> s) {
-            add(description, exp, s);
-        }
-
-        StringBuilder joiner(String description) {
-            return new StringBuilder(description).
-                    append(" {").
-                    append("size=").append(exp.size()).
-                    append("}");
-        }
-    }
-
-    static Object[][] spliteratorOfIntDataProvider;
-
-    @DataProvider(name = "Spliterator.OfInt")
-    public static Object[][] spliteratorOfIntDataProvider() {
-        if (spliteratorOfIntDataProvider != null) {
-            return spliteratorOfIntDataProvider;
-        }
-
-        List<Object[]> data = new ArrayList<>();
-        for (int size : SIZES) {
-            int exp[] = arrayIntRange(size);
-            SpliteratorOfIntDataBuilder db = new SpliteratorOfIntDataBuilder(data, listIntRange(size));
-
-            db.add("Spliterators.spliterator(int[], ...)",
-                   () -> Spliterators.spliterator(exp, 0));
-
-            db.add("Arrays.spliterator(int[], ...)",
-                   () -> Arrays.spliterator(exp));
-
-            db.add("Spliterators.spliterator(PrimitiveIterator.OfInt, ...)",
-                   () -> Spliterators.spliterator(Spliterators.iteratorFromSpliterator(Arrays.spliterator(exp)), exp.length, 0));
-
-            db.add("Spliterators.spliteratorUnknownSize(PrimitiveIterator.OfInt, ...)",
-                   () -> Spliterators.spliteratorUnknownSize(Spliterators.iteratorFromSpliterator(Arrays.spliterator(exp)), 0));
-
-            class IntSpliteratorFromArray extends Spliterators.AbstractIntSpliterator {
-                int[] a;
-                int index = 0;
-
-                IntSpliteratorFromArray(int[] a) {
-                    super(a.length, Spliterator.SIZED);
-                    this.a = a;
-                }
-
-                @Override
-                public boolean tryAdvance(IntConsumer action) {
-                    if (action == null)
-                        throw new NullPointerException();
-                    if (index < a.length) {
-                        action.accept(a[index++]);
-                        return true;
-                    }
-                    else {
-                        return false;
-                    }
-                }
-            }
-            db.add("new Spliterators.AbstractIntAdvancingSpliterator()",
-                   () -> new IntSpliteratorFromArray(exp));
-        }
-
-        return spliteratorOfIntDataProvider = data.toArray(new Object[0][]);
-    }
-
-    private static int[] arrayIntRange(int upTo) {
-        int[] exp = new int[upTo];
-        for (int i = 0; i < upTo; i++)
-            exp[i] = i;
-        return exp;
-    }
-
-    private static UnaryOperator<Consumer<Integer>> intBoxingConsumer() {
-        class BoxingAdapter implements Consumer<Integer>, IntConsumer {
-            private final Consumer<Integer> b;
-
-            BoxingAdapter(Consumer<Integer> b) {
-                this.b = b;
-            }
-
-            @Override
-            public void accept(Integer value) {
-                throw new IllegalStateException();
-            }
-
-            @Override
-            public void accept(int value) {
-                b.accept(value);
-            }
-        }
-
-        return b -> new BoxingAdapter(b);
-    }
-
-    @Test(dataProvider = "Spliterator.OfInt")
-    public void testIntNullPointerException(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) {
-        executeAndCatch(NullPointerException.class, () -> s.get().forEachRemaining((IntConsumer) null));
-        executeAndCatch(NullPointerException.class, () -> s.get().tryAdvance((IntConsumer) null));
-    }
-
-    @Test(dataProvider = "Spliterator.OfInt")
-    public void testIntForEach(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) {
-        testForEach(exp, s, intBoxingConsumer());
-    }
-
-    @Test(dataProvider = "Spliterator.OfInt")
-    public void testIntTryAdvance(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) {
-        testTryAdvance(exp, s, intBoxingConsumer());
-    }
-
-    @Test(dataProvider = "Spliterator.OfInt")
-    public void testIntMixedTryAdvanceForEach(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) {
-        testMixedTryAdvanceForEach(exp, s, intBoxingConsumer());
-    }
-
-    @Test(dataProvider = "Spliterator.OfInt")
-    public void testIntMixedTraverseAndSplit(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) {
-        testMixedTraverseAndSplit(exp, s, intBoxingConsumer());
-    }
-
-    @Test(dataProvider = "Spliterator.OfInt")
-    public void testIntSplitAfterFullTraversal(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) {
-        testSplitAfterFullTraversal(s, intBoxingConsumer());
-    }
-
-    @Test(dataProvider = "Spliterator.OfInt")
-    public void testIntSplitOnce(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) {
-        testSplitOnce(exp, s, intBoxingConsumer());
-    }
-
-    @Test(dataProvider = "Spliterator.OfInt")
-    public void testIntSplitSixDeep(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) {
-        testSplitSixDeep(exp, s, intBoxingConsumer());
-    }
-
-    @Test(dataProvider = "Spliterator.OfInt")
-    public void testIntSplitUntilNull(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) {
-        testSplitUntilNull(exp, s, intBoxingConsumer());
-    }
-
-    //
-
-    private static class SpliteratorOfLongDataBuilder {
-        List<Object[]> data;
-
-        List<Long> exp;
-
-        SpliteratorOfLongDataBuilder(List<Object[]> data, List<Long> exp) {
-            this.data = data;
-            this.exp = exp;
-        }
-
-        void add(String description, List<Long> expected, Supplier<Spliterator.OfLong> s) {
-            description = joiner(description).toString();
-            data.add(new Object[]{description, expected, s});
-        }
-
-        void add(String description, Supplier<Spliterator.OfLong> s) {
-            add(description, exp, s);
-        }
-
-        StringBuilder joiner(String description) {
-            return new StringBuilder(description).
-                    append(" {").
-                    append("size=").append(exp.size()).
-                    append("}");
-        }
-    }
-
-    static Object[][] spliteratorOfLongDataProvider;
-
-    @DataProvider(name = "Spliterator.OfLong")
-    public static Object[][] spliteratorOfLongDataProvider() {
-        if (spliteratorOfLongDataProvider != null) {
-            return spliteratorOfLongDataProvider;
-        }
-
-        List<Object[]> data = new ArrayList<>();
-        for (int size : SIZES) {
-            long exp[] = arrayLongRange(size);
-            SpliteratorOfLongDataBuilder db = new SpliteratorOfLongDataBuilder(data, listLongRange(size));
-
-            db.add("Spliterators.spliterator(long[], ...)",
-                   () -> Spliterators.spliterator(exp, 0));
-
-            db.add("Arrays.spliterator(long[], ...)",
-                   () -> Arrays.spliterator(exp));
-
-            db.add("Spliterators.spliterator(PrimitiveIterator.OfLong, ...)",
-                   () -> Spliterators.spliterator(Spliterators.iteratorFromSpliterator(Arrays.spliterator(exp)), exp.length, 0));
-
-            db.add("Spliterators.spliteratorUnknownSize(PrimitiveIterator.OfLong, ...)",
-                   () -> Spliterators.spliteratorUnknownSize(Spliterators.iteratorFromSpliterator(Arrays.spliterator(exp)), 0));
-
-            class LongSpliteratorFromArray extends Spliterators.AbstractLongSpliterator {
-                long[] a;
-                int index = 0;
-
-                LongSpliteratorFromArray(long[] a) {
-                    super(a.length, Spliterator.SIZED);
-                    this.a = a;
-                }
-
-                @Override
-                public boolean tryAdvance(LongConsumer action) {
-                    if (action == null)
-                        throw new NullPointerException();
-                    if (index < a.length) {
-                        action.accept(a[index++]);
-                        return true;
-                    }
-                    else {
-                        return false;
-                    }
-                }
-            }
-            db.add("new Spliterators.AbstractLongAdvancingSpliterator()",
-                   () -> new LongSpliteratorFromArray(exp));
-        }
-
-        return spliteratorOfLongDataProvider = data.toArray(new Object[0][]);
-    }
-
-    private static List<Long> listLongRange(int upTo) {
-        List<Long> exp = new ArrayList<>();
-        for (long i = 0; i < upTo; i++)
-            exp.add(i);
-        return Collections.unmodifiableList(exp);
-    }
-
-    private static long[] arrayLongRange(int upTo) {
-        long[] exp = new long[upTo];
-        for (int i = 0; i < upTo; i++)
-            exp[i] = i;
-        return exp;
-    }
-
-    private static UnaryOperator<Consumer<Long>> longBoxingConsumer() {
-        class BoxingAdapter implements Consumer<Long>, LongConsumer {
-            private final Consumer<Long> b;
-
-            BoxingAdapter(Consumer<Long> b) {
-                this.b = b;
-            }
-
-            @Override
-            public void accept(Long value) {
-                throw new IllegalStateException();
-            }
-
-            @Override
-            public void accept(long value) {
-                b.accept(value);
-            }
-        }
-
-        return b -> new BoxingAdapter(b);
-    }
-
-    @Test(dataProvider = "Spliterator.OfLong")
-    public void testLongNullPointerException(String description, Collection<Long> exp, Supplier<Spliterator.OfLong> s) {
-        executeAndCatch(NullPointerException.class, () -> s.get().forEachRemaining((LongConsumer) null));
-        executeAndCatch(NullPointerException.class, () -> s.get().tryAdvance((LongConsumer) null));
-    }
-
-    @Test(dataProvider = "Spliterator.OfLong")
-    public void testLongForEach(String description, Collection<Long> exp, Supplier<Spliterator.OfLong> s) {
-        testForEach(exp, s, longBoxingConsumer());
-    }
-
-    @Test(dataProvider = "Spliterator.OfLong")
-    public void testLongTryAdvance(String description, Collection<Long> exp, Supplier<Spliterator.OfLong> s) {
-        testTryAdvance(exp, s, longBoxingConsumer());
-    }
-
-    @Test(dataProvider = "Spliterator.OfLong")
-    public void testLongMixedTryAdvanceForEach(String description, Collection<Long> exp, Supplier<Spliterator.OfLong> s) {
-        testMixedTryAdvanceForEach(exp, s, longBoxingConsumer());
-    }
-
-    @Test(dataProvider = "Spliterator.OfLong")
-    public void testLongMixedTraverseAndSplit(String description, Collection<Long> exp, Supplier<Spliterator.OfLong> s) {
-        testMixedTraverseAndSplit(exp, s, longBoxingConsumer());
-    }
-
-    @Test(dataProvider = "Spliterator.OfLong")
-    public void testLongSplitAfterFullTraversal(String description, Collection<Long> exp, Supplier<Spliterator.OfLong> s) {
-        testSplitAfterFullTraversal(s, longBoxingConsumer());
-    }
-
-    @Test(dataProvider = "Spliterator.OfLong")
-    public void testLongSplitOnce(String description, Collection<Long> exp, Supplier<Spliterator.OfLong> s) {
-        testSplitOnce(exp, s, longBoxingConsumer());
-    }
-
-    @Test(dataProvider = "Spliterator.OfLong")
-    public void testLongSplitSixDeep(String description, Collection<Long> exp, Supplier<Spliterator.OfLong> s) {
-        testSplitSixDeep(exp, s, longBoxingConsumer());
-    }
-
-    @Test(dataProvider = "Spliterator.OfLong")
-    public void testLongSplitUntilNull(String description, Collection<Long> exp, Supplier<Spliterator.OfLong> s) {
-        testSplitUntilNull(exp, s, longBoxingConsumer());
-    }
-
-    //
-
-    private static class SpliteratorOfDoubleDataBuilder {
-        List<Object[]> data;
-
-        List<Double> exp;
-
-        SpliteratorOfDoubleDataBuilder(List<Object[]> data, List<Double> exp) {
-            this.data = data;
-            this.exp = exp;
-        }
-
-        void add(String description, List<Double> expected, Supplier<Spliterator.OfDouble> s) {
-            description = joiner(description).toString();
-            data.add(new Object[]{description, expected, s});
-        }
-
-        void add(String description, Supplier<Spliterator.OfDouble> s) {
-            add(description, exp, s);
-        }
-
-        StringBuilder joiner(String description) {
-            return new StringBuilder(description).
-                    append(" {").
-                    append("size=").append(exp.size()).
-                    append("}");
-        }
-    }
-
-    static Object[][] spliteratorOfDoubleDataProvider;
-
-    @DataProvider(name = "Spliterator.OfDouble")
-    public static Object[][] spliteratorOfDoubleDataProvider() {
-        if (spliteratorOfDoubleDataProvider != null) {
-            return spliteratorOfDoubleDataProvider;
-        }
-
-        List<Object[]> data = new ArrayList<>();
-        for (int size : SIZES) {
-            double exp[] = arrayDoubleRange(size);
-            SpliteratorOfDoubleDataBuilder db = new SpliteratorOfDoubleDataBuilder(data, listDoubleRange(size));
-
-            db.add("Spliterators.spliterator(double[], ...)",
-                   () -> Spliterators.spliterator(exp, 0));
-
-            db.add("Arrays.spliterator(double[], ...)",
-                   () -> Arrays.spliterator(exp));
-
-            db.add("Spliterators.spliterator(PrimitiveIterator.OfDouble, ...)",
-                   () -> Spliterators.spliterator(Spliterators.iteratorFromSpliterator(Arrays.spliterator(exp)), exp.length, 0));
-
-            db.add("Spliterators.spliteratorUnknownSize(PrimitiveIterator.OfDouble, ...)",
-                   () -> Spliterators.spliteratorUnknownSize(Spliterators.iteratorFromSpliterator(Arrays.spliterator(exp)), 0));
-
-            class DoubleSpliteratorFromArray extends Spliterators.AbstractDoubleSpliterator {
-                double[] a;
-                int index = 0;
-
-                DoubleSpliteratorFromArray(double[] a) {
-                    super(a.length, Spliterator.SIZED);
-                    this.a = a;
-                }
-
-                @Override
-                public boolean tryAdvance(DoubleConsumer action) {
-                    if (action == null)
-                        throw new NullPointerException();
-                    if (index < a.length) {
-                        action.accept(a[index++]);
-                        return true;
-                    }
-                    else {
-                        return false;
-                    }
-                }
-            }
-            db.add("new Spliterators.AbstractDoubleAdvancingSpliterator()",
-                   () -> new DoubleSpliteratorFromArray(exp));
-        }
-
-        return spliteratorOfDoubleDataProvider = data.toArray(new Object[0][]);
-    }
-
-    private static List<Double> listDoubleRange(int upTo) {
-        List<Double> exp = new ArrayList<>();
-        for (double i = 0; i < upTo; i++)
-            exp.add(i);
-        return Collections.unmodifiableList(exp);
-    }
-
-    private static double[] arrayDoubleRange(int upTo) {
-        double[] exp = new double[upTo];
-        for (int i = 0; i < upTo; i++)
-            exp[i] = i;
-        return exp;
-    }
-
-    private static UnaryOperator<Consumer<Double>> doubleBoxingConsumer() {
-        class BoxingAdapter implements Consumer<Double>, DoubleConsumer {
-            private final Consumer<Double> b;
-
-            BoxingAdapter(Consumer<Double> b) {
-                this.b = b;
-            }
-
-            @Override
-            public void accept(Double value) {
-                throw new IllegalStateException();
-            }
-
-            @Override
-            public void accept(double value) {
-                b.accept(value);
-            }
-        }
-
-        return b -> new BoxingAdapter(b);
-    }
-
-    @Test(dataProvider = "Spliterator.OfDouble")
-    public void testDoubleNullPointerException(String description, Collection<Double> exp, Supplier<Spliterator.OfDouble> s) {
-        executeAndCatch(NullPointerException.class, () -> s.get().forEachRemaining((DoubleConsumer) null));
-        executeAndCatch(NullPointerException.class, () -> s.get().tryAdvance((DoubleConsumer) null));
-    }
-
-    @Test(dataProvider = "Spliterator.OfDouble")
-    public void testDoubleForEach(String description, Collection<Double> exp, Supplier<Spliterator.OfDouble> s) {
-        testForEach(exp, s, doubleBoxingConsumer());
-    }
-
-    @Test(dataProvider = "Spliterator.OfDouble")
-    public void testDoubleTryAdvance(String description, Collection<Double> exp, Supplier<Spliterator.OfDouble> s) {
-        testTryAdvance(exp, s, doubleBoxingConsumer());
-    }
-
-    @Test(dataProvider = "Spliterator.OfDouble")
-    public void testDoubleMixedTryAdvanceForEach(String description, Collection<Double> exp, Supplier<Spliterator.OfDouble> s) {
-        testMixedTryAdvanceForEach(exp, s, doubleBoxingConsumer());
-    }
-
-    @Test(dataProvider = "Spliterator.OfDouble")
-    public void testDoubleMixedTraverseAndSplit(String description, Collection<Double> exp, Supplier<Spliterator.OfDouble> s) {
-        testMixedTraverseAndSplit(exp, s, doubleBoxingConsumer());
-    }
-
-    @Test(dataProvider = "Spliterator.OfDouble")
-    public void testDoubleSplitAfterFullTraversal(String description, Collection<Double> exp, Supplier<Spliterator.OfDouble> s) {
-        testSplitAfterFullTraversal(s, doubleBoxingConsumer());
-    }
-
-    @Test(dataProvider = "Spliterator.OfDouble")
-    public void testDoubleSplitOnce(String description, Collection<Double> exp, Supplier<Spliterator.OfDouble> s) {
-        testSplitOnce(exp, s, doubleBoxingConsumer());
-    }
-
-    @Test(dataProvider = "Spliterator.OfDouble")
-    public void testDoubleSplitSixDeep(String description, Collection<Double> exp, Supplier<Spliterator.OfDouble> s) {
-        testSplitSixDeep(exp, s, doubleBoxingConsumer());
-    }
-
-    @Test(dataProvider = "Spliterator.OfDouble")
-    public void testDoubleSplitUntilNull(String description, Collection<Double> exp, Supplier<Spliterator.OfDouble> s) {
-        testSplitUntilNull(exp, s, doubleBoxingConsumer());
-    }
-
-    //
-
-    private static <T, S extends Spliterator<T>> void testForEach(
-            Collection<T> exp,
-            Supplier<S> supplier,
-            UnaryOperator<Consumer<T>> boxingAdapter) {
-        S spliterator = supplier.get();
-        long sizeIfKnown = spliterator.getExactSizeIfKnown();
-        boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
-
-        ArrayList<T> fromForEach = new ArrayList<>();
-        spliterator = supplier.get();
-        Consumer<T> addToFromForEach = boxingAdapter.apply(fromForEach::add);
-        spliterator.forEachRemaining(addToFromForEach);
-
-        // Assert that forEach now produces no elements
-        spliterator.forEachRemaining(boxingAdapter.apply(
-                e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e)));
-        // Assert that tryAdvance now produce no elements
-        spliterator.tryAdvance(boxingAdapter.apply(
-                e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e)));
-
-        // assert that size, tryAdvance, and forEach are consistent
-        if (sizeIfKnown >= 0) {
-            assertEquals(sizeIfKnown, exp.size());
-        }
-        assertEquals(fromForEach.size(), exp.size());
-
-        assertContents(fromForEach, exp, isOrdered);
-    }
-
-    private static <T, S extends Spliterator<T>> void testTryAdvance(
-            Collection<T> exp,
-            Supplier<S> supplier,
-            UnaryOperator<Consumer<T>> boxingAdapter) {
-        S spliterator = supplier.get();
-        long sizeIfKnown = spliterator.getExactSizeIfKnown();
-        boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
-
-        spliterator = supplier.get();
-        ArrayList<T> fromTryAdvance = new ArrayList<>();
-        Consumer<T> addToFromTryAdvance = boxingAdapter.apply(fromTryAdvance::add);
-        while (spliterator.tryAdvance(addToFromTryAdvance)) { }
-
-        // Assert that forEach now produces no elements
-        spliterator.forEachRemaining(boxingAdapter.apply(
-                e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e)));
-        // Assert that tryAdvance now produce no elements
-        spliterator.tryAdvance(boxingAdapter.apply(
-                e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e)));
-
-        // assert that size, tryAdvance, and forEach are consistent
-        if (sizeIfKnown >= 0) {
-            assertEquals(sizeIfKnown, exp.size());
-        }
-        assertEquals(fromTryAdvance.size(), exp.size());
-
-        assertContents(fromTryAdvance, exp, isOrdered);
-    }
-
-    private static <T, S extends Spliterator<T>> void testMixedTryAdvanceForEach(
-            Collection<T> exp,
-            Supplier<S> supplier,
-            UnaryOperator<Consumer<T>> boxingAdapter) {
-        S spliterator = supplier.get();
-        long sizeIfKnown = spliterator.getExactSizeIfKnown();
-        boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
-
-        // tryAdvance first few elements, then forEach rest
-        ArrayList<T> dest = new ArrayList<>();
-        spliterator = supplier.get();
-        Consumer<T> addToDest = boxingAdapter.apply(dest::add);
-        for (int i = 0; i < 10 && spliterator.tryAdvance(addToDest); i++) { }
-        spliterator.forEachRemaining(addToDest);
-
-        // Assert that forEach now produces no elements
-        spliterator.forEachRemaining(boxingAdapter.apply(
-                e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e)));
-        // Assert that tryAdvance now produce no elements
-        spliterator.tryAdvance(boxingAdapter.apply(
-                e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e)));
-
-        if (sizeIfKnown >= 0) {
-            assertEquals(sizeIfKnown, dest.size());
-        }
-        assertEquals(dest.size(), exp.size());
-
-        if (isOrdered) {
-            assertEquals(dest, exp);
-        }
-        else {
-            assertContentsUnordered(dest, exp);
-        }
-    }
-
-    private static <T, S extends Spliterator<T>> void testMixedTraverseAndSplit(
-            Collection<T> exp,
-            Supplier<S> supplier,
-            UnaryOperator<Consumer<T>> boxingAdapter) {
-        S spliterator = supplier.get();
-        long sizeIfKnown = spliterator.getExactSizeIfKnown();
-        boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
-
-        ArrayList<T> dest = new ArrayList<>();
-        spliterator = supplier.get();
-        Consumer<T> b = boxingAdapter.apply(dest::add);
-
-        Spliterator<T> spl1, spl2, spl3;
-        spliterator.tryAdvance(b);
-        spl2 = spliterator.trySplit();
-        if (spl2 != null) {
-            spl2.tryAdvance(b);
-            spl1 = spl2.trySplit();
-            if (spl1 != null) {
-                spl1.tryAdvance(b);
-                spl1.forEachRemaining(b);
-            }
-            spl2.tryAdvance(b);
-            spl2.forEachRemaining(b);
-        }
-        spliterator.tryAdvance(b);
-        spl3 = spliterator.trySplit();
-        if (spl3 != null) {
-            spl3.tryAdvance(b);
-            spl3.forEachRemaining(b);
-        }
-        spliterator.tryAdvance(b);
-        spliterator.forEachRemaining(b);
-
-        if (sizeIfKnown >= 0) {
-            assertEquals(sizeIfKnown, dest.size());
-        }
-        assertEquals(dest.size(), exp.size());
-
-        if (isOrdered) {
-            assertEquals(dest, exp);
-        }
-        else {
-            assertContentsUnordered(dest, exp);
-        }
-    }
-
-    private static <T, S extends Spliterator<T>> void testSplitAfterFullTraversal(
-            Supplier<S> supplier,
-            UnaryOperator<Consumer<T>> boxingAdapter) {
-        // Full traversal using tryAdvance
-        Spliterator<T> spliterator = supplier.get();
-        while (spliterator.tryAdvance(boxingAdapter.apply(e -> { }))) { }
-        Spliterator<T> split = spliterator.trySplit();
-        assertNull(split);
-
-        // Full traversal using forEach
-        spliterator = supplier.get();
-        spliterator.forEachRemaining(boxingAdapter.apply(e -> {
-        }));
-        split = spliterator.trySplit();
-        assertNull(split);
-
-        // Full traversal using tryAdvance then forEach
-        spliterator = supplier.get();
-        spliterator.tryAdvance(boxingAdapter.apply(e -> { }));
-        spliterator.forEachRemaining(boxingAdapter.apply(e -> {
-        }));
-        split = spliterator.trySplit();
-        assertNull(split);
-    }
-
-    private static <T, S extends Spliterator<T>> void testSplitOnce(
-            Collection<T> exp,
-            Supplier<S> supplier,
-            UnaryOperator<Consumer<T>> boxingAdapter) {
-        S spliterator = supplier.get();
-        long sizeIfKnown = spliterator.getExactSizeIfKnown();
-        boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
-
-        ArrayList<T> fromSplit = new ArrayList<>();
-        Spliterator<T> s1 = supplier.get();
-        Spliterator<T> s2 = s1.trySplit();
-        long s1Size = s1.getExactSizeIfKnown();
-        long s2Size = (s2 != null) ? s2.getExactSizeIfKnown() : 0;
-        Consumer<T> addToFromSplit = boxingAdapter.apply(fromSplit::add);
-        if (s2 != null)
-            s2.forEachRemaining(addToFromSplit);
-        s1.forEachRemaining(addToFromSplit);
-
-        if (sizeIfKnown >= 0) {
-            assertEquals(sizeIfKnown, fromSplit.size());
-            if (s1Size >= 0 && s2Size >= 0)
-                assertEquals(sizeIfKnown, s1Size + s2Size);
-        }
-        assertContents(fromSplit, exp, isOrdered);
-    }
-
-    private static <T, S extends Spliterator<T>> void testSplitSixDeep(
-            Collection<T> exp,
-            Supplier<S> supplier,
-            UnaryOperator<Consumer<T>> boxingAdapter) {
-        S spliterator = supplier.get();
-        boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
-
-        for (int depth=0; depth < 6; depth++) {
-            List<T> dest = new ArrayList<>();
-            spliterator = supplier.get();
-
-            assertSpliterator(spliterator);
-
-            // verify splitting with forEach
-            visit(depth, 0, dest, spliterator, boxingAdapter, spliterator.characteristics(), false);
-            assertContents(dest, exp, isOrdered);
-
-            // verify splitting with tryAdvance
-            dest.clear();
-            spliterator = supplier.get();
-            visit(depth, 0, dest, spliterator, boxingAdapter, spliterator.characteristics(), true);
-            assertContents(dest, exp, isOrdered);
-        }
-    }
-
-    private static <T, S extends Spliterator<T>>
-    void visit(int depth, int curLevel,
-               List<T> dest, S spliterator, UnaryOperator<Consumer<T>> boxingAdapter,
-               int rootCharacteristics, boolean useTryAdvance) {
-        if (curLevel < depth) {
-            long beforeSize = spliterator.getExactSizeIfKnown();
-            Spliterator<T> split = spliterator.trySplit();
-            if (split != null) {
-                assertSpliterator(split, rootCharacteristics);
-                assertSpliterator(spliterator, rootCharacteristics);
-
-                if ((rootCharacteristics & Spliterator.SUBSIZED) != 0 &&
-                    (rootCharacteristics & Spliterator.SIZED) != 0) {
-                    assertEquals(beforeSize, split.estimateSize() + spliterator.estimateSize());
-                }
-                visit(depth, curLevel + 1, dest, split, boxingAdapter, rootCharacteristics, useTryAdvance);
-            }
-            visit(depth, curLevel + 1, dest, spliterator, boxingAdapter, rootCharacteristics, useTryAdvance);
-        }
-        else {
-            long sizeIfKnown = spliterator.getExactSizeIfKnown();
-            if (useTryAdvance) {
-                Consumer<T> addToDest = boxingAdapter.apply(dest::add);
-                int count = 0;
-                while (spliterator.tryAdvance(addToDest)) {
-                    ++count;
-                }
-
-                if (sizeIfKnown >= 0)
-                    assertEquals(sizeIfKnown, count);
-
-                // Assert that forEach now produces no elements
-                spliterator.forEachRemaining(boxingAdapter.apply(
-                        e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e)));
-
-                Spliterator<T> split = spliterator.trySplit();
-                assertNull(split);
-            }
-            else {
-                List<T> leafDest = new ArrayList<>();
-                Consumer<T> addToLeafDest = boxingAdapter.apply(leafDest::add);
-                spliterator.forEachRemaining(addToLeafDest);
-
-                if (sizeIfKnown >= 0)
-                    assertEquals(sizeIfKnown, leafDest.size());
-
-                // Assert that forEach now produces no elements
-                spliterator.tryAdvance(boxingAdapter.apply(
-                        e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e)));
-
-                Spliterator<T> split = spliterator.trySplit();
-                assertNull(split);
-
-                dest.addAll(leafDest);
-            }
-        }
-    }
-
-    private static <T, S extends Spliterator<T>> void testSplitUntilNull(
-            Collection<T> exp,
-            Supplier<S> supplier,
-            UnaryOperator<Consumer<T>> boxingAdapter) {
-        Spliterator<T> s = supplier.get();
-        boolean isOrdered = s.hasCharacteristics(Spliterator.ORDERED);
-        assertSpliterator(s);
-
-        List<T> splits = new ArrayList<>();
-        Consumer<T> c = boxingAdapter.apply(splits::add);
-
-        testSplitUntilNull(new SplitNode<T>(c, s));
-        assertContents(splits, exp, isOrdered);
-    }
-
-    private static class SplitNode<T> {
-        // Constant for every node
-        final Consumer<T> c;
-        final int rootCharacteristics;
-
-        final Spliterator<T> s;
-
-        SplitNode(Consumer<T> c, Spliterator<T> s) {
-            this(c, s.characteristics(), s);
-        }
-
-        private SplitNode(Consumer<T> c, int rootCharacteristics, Spliterator<T> s) {
-            this.c = c;
-            this.rootCharacteristics = rootCharacteristics;
-            this.s = s;
-        }
-
-        SplitNode<T> fromSplit(Spliterator<T> split) {
-            return new SplitNode<>(c, rootCharacteristics, split);
-        }
-    }
-
-    /**
-     * Set the maximum stack capacity to 0.25MB. This should be more than enough to detect a bad spliterator
-     * while not unduly disrupting test infrastructure given the test data sizes that are used are small.
-     * Note that j.u.c.ForkJoinPool sets the max queue size to 64M (1 << 26).
-     */
-    private static final int MAXIMUM_STACK_CAPACITY = 1 << 18; // 0.25MB
-
-    private static <T> void testSplitUntilNull(SplitNode<T> e) {
-        // Use an explicit stack to avoid a StackOverflowException when testing a Spliterator
-        // that when repeatedly split produces a right-balanced (and maybe degenerate) tree, or
-        // for a spliterator that is badly behaved.
-        Deque<SplitNode<T>> stack = new ArrayDeque<>();
-        stack.push(e);
-
-        int iteration = 0;
-        while (!stack.isEmpty()) {
-            assertTrue(iteration++ < MAXIMUM_STACK_CAPACITY, "Exceeded maximum stack modification count of 1 << 18");
-
-            e = stack.pop();
-            Spliterator<T> parentAndRightSplit = e.s;
-
-            long parentEstimateSize = parentAndRightSplit.estimateSize();
-            assertTrue(parentEstimateSize >= 0,
-                       String.format("Split size estimate %d < 0", parentEstimateSize));
-
-            long parentSize = parentAndRightSplit.getExactSizeIfKnown();
-            Spliterator<T> leftSplit = parentAndRightSplit.trySplit();
-            if (leftSplit == null) {
-                parentAndRightSplit.forEachRemaining(e.c);
-                continue;
-            }
-
-            assertSpliterator(leftSplit, e.rootCharacteristics);
-            assertSpliterator(parentAndRightSplit, e.rootCharacteristics);
-
-            if (parentEstimateSize != Long.MAX_VALUE && leftSplit.estimateSize() > 0 && parentAndRightSplit.estimateSize() > 0) {
-                assertTrue(leftSplit.estimateSize() < parentEstimateSize,
-                           String.format("Left split size estimate %d >= parent split size estimate %d",
-                                         leftSplit.estimateSize(), parentEstimateSize));
-                assertTrue(parentAndRightSplit.estimateSize() < parentEstimateSize,
-                           String.format("Right split size estimate %d >= parent split size estimate %d",
-                                         leftSplit.estimateSize(), parentEstimateSize));
-            }
-            else {
-                assertTrue(leftSplit.estimateSize() <= parentEstimateSize,
-                           String.format("Left split size estimate %d > parent split size estimate %d",
-                                         leftSplit.estimateSize(), parentEstimateSize));
-                assertTrue(parentAndRightSplit.estimateSize() <= parentEstimateSize,
-                           String.format("Right split size estimate %d > parent split size estimate %d",
-                                         leftSplit.estimateSize(), parentEstimateSize));
-            }
-
-            long leftSize = leftSplit.getExactSizeIfKnown();
-            long rightSize = parentAndRightSplit.getExactSizeIfKnown();
-            if (parentSize >= 0 && leftSize >= 0 && rightSize >= 0)
-                assertEquals(parentSize, leftSize + rightSize,
-                             String.format("exact left split size %d + exact right split size %d != parent exact split size %d",
-                                           leftSize, rightSize, parentSize));
-
-            // Add right side to stack first so left side is popped off first
-            stack.push(e.fromSplit(parentAndRightSplit));
-            stack.push(e.fromSplit(leftSplit));
-        }
-    }
-
-    private static void assertSpliterator(Spliterator<?> s, int rootCharacteristics) {
-        if ((rootCharacteristics & Spliterator.SUBSIZED) != 0) {
-            assertTrue(s.hasCharacteristics(Spliterator.SUBSIZED),
-                       "Child split is not SUBSIZED when root split is SUBSIZED");
-        }
-        assertSpliterator(s);
-    }
-
-    private static void assertSpliterator(Spliterator<?> s) {
-        if (s.hasCharacteristics(Spliterator.SUBSIZED)) {
-            assertTrue(s.hasCharacteristics(Spliterator.SIZED));
-        }
-        if (s.hasCharacteristics(Spliterator.SIZED)) {
-            assertTrue(s.estimateSize() != Long.MAX_VALUE);
-            assertTrue(s.getExactSizeIfKnown() >= 0);
-        }
-        try {
-            s.getComparator();
-            assertTrue(s.hasCharacteristics(Spliterator.SORTED));
-        } catch (IllegalStateException e) {
-            assertFalse(s.hasCharacteristics(Spliterator.SORTED));
-        }
-    }
-
-    private static<T> void assertContents(Collection<T> actual, Collection<T> expected, boolean isOrdered) {
-        if (isOrdered) {
-            assertEquals(actual, expected);
-        }
-        else {
-            assertContentsUnordered(actual, expected);
-        }
-    }
-
-    private static<T> void assertContentsUnordered(Iterable<T> actual, Iterable<T> expected) {
-        assertEquals(toBoxedMultiset(actual), toBoxedMultiset(expected));
-    }
-
-    private static <T> Map<T, Integer> toBoxedMultiset(Iterable<T> c) {
-        Map<T, Integer> result = new HashMap<>();
-        c.forEach(e -> {
-            if (result.containsKey(e)) result.put(e, result.get(e) + 1);
-            else result.put(e, 1);
-        });
-        return result;
-    }
-
-    private void executeAndCatch(Class<? extends Exception> expected, Runnable r) {
-        Exception caught = null;
-        try {
-            r.run();
-        }
-        catch (Exception e) {
-            caught = e;
-        }
-
-        assertNotNull(caught,
-                      String.format("No Exception was thrown, expected an Exception of %s to be thrown",
-                                    expected.getName()));
-        assertTrue(expected.isInstance(caught),
-                   String.format("Exception thrown %s not an instance of %s",
-                                 caught.getClass().getName(), expected.getName()));
-    }
-
-}
--- a/jdk/test/java/util/zip/StoredCRC.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/util/zip/StoredCRC.java	Mon Jun 10 10:38:33 2013 +0100
@@ -77,9 +77,9 @@
                 unexpected(t);
             }
 
-            // Test that data corruption is detected.  Offset 39 was
+            // Test that data corruption is detected.  "offset" was
             // determined to be in the entry's uncompressed data.
-            data[39] ^= 1;
+            data[getDataOffset(data) + 4] ^= 1;
 
             zis = new ZipInputStream(
                 new ByteArrayInputStream(data));
@@ -97,6 +97,15 @@
         }
     }
 
+    public static final int getDataOffset(byte b[]) {
+        final int LOCHDR = 30;       // LOC header size
+        final int LOCEXT = 28;       // extra field length
+        final int LOCNAM = 26;       // filename length
+        int lenExt = Byte.toUnsignedInt(b[LOCEXT]) | (Byte.toUnsignedInt(b[LOCEXT + 1]) << 8);
+        int lenNam = Byte.toUnsignedInt(b[LOCNAM]) | (Byte.toUnsignedInt(b[LOCNAM + 1]) << 8);
+        return LOCHDR + lenExt + lenNam;
+    }
+
     //--------------------- Infrastructure ---------------------------
     static volatile int passed = 0, failed = 0;
     static boolean pass() {passed++; return true;}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/zip/TestExtraTime.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+/**
+ * @test
+ * @bug 4759491 6303183 7012868
+ * @summary Test ZOS and ZIS timestamp in extra field correctly
+ */
+
+import java.io.*;
+import java.util.TimeZone;
+import java.util.concurrent.TimeUnit;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+
+
+public class TestExtraTime {
+
+    public static void main(String[] args) throws Throwable{
+
+        File src = new File(System.getProperty("test.src", "."), "TestExtraTime.java");
+        if (src.exists()) {
+            long mtime = src.lastModified();
+            test(mtime, null);
+            test(10, null);  // ms-dos 1980 epoch problem
+            test(mtime, TimeZone.getTimeZone("Asia/Shanghai"));
+        }
+    }
+
+    private static void test(long mtime, TimeZone tz) throws Throwable {
+        TimeZone tz0 = TimeZone.getDefault();
+        if (tz != null) {
+            TimeZone.setDefault(tz);
+        }
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ZipOutputStream zos = new ZipOutputStream(baos);
+        ZipEntry ze = new ZipEntry("TestExtreTime.java");
+
+        ze.setTime(mtime);
+        zos.putNextEntry(ze);
+        zos.write(new byte[] { 1,2 ,3, 4});
+        zos.close();
+        if (tz != null) {
+            TimeZone.setDefault(tz0);
+        }
+        ZipInputStream zis = new ZipInputStream(
+                                 new ByteArrayInputStream(baos.toByteArray()));
+        ze = zis.getNextEntry();
+        zis.close();
+
+        System.out.printf("%tc  => %tc%n", mtime, ze.getTime());
+
+        if (TimeUnit.MILLISECONDS.toSeconds(mtime) !=
+            TimeUnit.MILLISECONDS.toSeconds(ze.getTime()))
+            throw new RuntimeException("Timestamp storing failed!");
+
+    }
+}
--- a/jdk/test/java/util/zip/ZipFile/Assortment.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/java/util/zip/ZipFile/Assortment.java	Mon Jun 10 10:38:33 2013 +0100
@@ -22,7 +22,7 @@
  */
 
 /* @test
- * @bug 4770745 6234507
+ * @bug 4770745 6234507 6303183
  * @summary test a variety of zip file entries
  * @author Martin Buchholz
  */
@@ -54,6 +54,44 @@
         check(condition, "Something's wrong");
     }
 
+    static final int get16(byte b[], int off) {
+        return Byte.toUnsignedInt(b[off]) | (Byte.toUnsignedInt(b[off+1]) << 8);
+    }
+
+    // check if all "expected" extra fields equal to their
+    // corresponding fields in "extra". The "extra" might have
+    // timestamp fields added by ZOS.
+    static boolean equalsExtraData(byte[] expected, byte[] extra) {
+        if (expected == null)
+            return true;
+        int off = 0;
+        int len = expected.length;
+        while (off + 4 < len) {
+            int tag = get16(expected, off);
+            int sz = get16(expected, off + 2);
+            int off0 = 0;
+            int len0 = extra.length;
+            boolean matched = false;
+            while (off0 + 4 < len0) {
+                int tag0 = get16(extra, off0);
+                int sz0 = get16(extra, off0 + 2);
+                if (tag == tag0 && sz == sz0) {
+                    matched = true;
+                    for (int i = 0; i < sz; i++) {
+                        if (expected[off + i] != extra[off0 +i])
+                            matched = false;
+                    }
+                    break;
+                }
+                off0 += (4 + sz0);
+            }
+            if (!matched)
+                return false;
+            off += (4 + sz);
+        }
+        return true;
+    }
+
     private static class Entry {
         private String name;
         private int    method;
@@ -109,7 +147,7 @@
             check((((comment == null) || comment.equals(""))
                    && (e.getComment() == null))
                   || comment.equals(e.getComment()));
-            check(Arrays.equals(extra, e.getExtra()));
+            check(equalsExtraData(extra, e.getExtra()));
             check(Arrays.equals(data, getData(f, e)));
             check(e.getSize() == data.length);
             check((method == ZipEntry.DEFLATED) ||
@@ -129,8 +167,7 @@
 
             byte[] extra = (this.extra != null && this.extra.length == 0) ?
                 null : this.extra;
-            check(Arrays.equals(extra, e.getExtra()));
-
+            check(equalsExtraData(extra, e.getExtra()));
             check(name.equals(e.getName()));
             check(method == e.getMethod());
             check(e.getSize() == -1 || e.getSize() == data.length);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/crypto/Cipher/CipherStreamClose.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,167 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 7160837
+ * @summary Make sure Cipher IO streams doesn't call extra doFinal if close()
+ * is called multiple times.  Additionally, verify the input and output streams
+ * match with encryption and decryption with non-stream crypto.
+ */
+
+import java.io.*;
+import java.security.DigestOutputStream;
+import java.security.DigestInputStream;
+import java.security.MessageDigest;
+import java.util.Arrays;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherOutputStream;
+import javax.crypto.CipherInputStream;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import javax.xml.bind.DatatypeConverter;
+
+public class CipherStreamClose {
+    private static final String message = "This is the sample message";
+    static boolean debug = false;
+
+    /*
+     * This method does encryption by cipher.doFinal(), and not with
+     * CipherOutputStream
+     */
+    public static byte[] blockEncrypt(String message, SecretKey key)
+        throws Exception {
+
+        byte[] data;
+        Cipher encCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
+        encCipher.init(Cipher.ENCRYPT_MODE, key);
+        try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
+            try (ObjectOutputStream oos = new ObjectOutputStream(bos)) {
+                oos.writeObject(message);
+            }
+            data = bos.toByteArray();
+        }
+
+        if (debug) {
+            System.out.println(DatatypeConverter.printHexBinary(data));
+        }
+        return encCipher.doFinal(data);
+
+    }
+
+    /*
+     * This method does decryption by cipher.doFinal(), and not with
+     * CipherIntputStream
+     */
+    public static Object blockDecrypt(byte[] data, SecretKey key)
+        throws Exception {
+
+        Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding");
+        c.init(Cipher.DECRYPT_MODE, key);
+        data = c.doFinal(data);
+        try (ByteArrayInputStream bis = new ByteArrayInputStream(data)) {
+            try (ObjectInputStream ois = new ObjectInputStream(bis)) {
+                return ois.readObject();
+            }
+        }
+    }
+
+    public static byte[] streamEncrypt(String message, SecretKey key,
+        MessageDigest digest)
+        throws Exception {
+
+        byte[] data;
+        Cipher encCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
+        encCipher.init(Cipher.ENCRYPT_MODE, key);
+        try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
+            DigestOutputStream dos = new DigestOutputStream(bos, digest);
+            CipherOutputStream cos = new CipherOutputStream(dos, encCipher)) {
+            try (ObjectOutputStream oos = new ObjectOutputStream(cos)) {
+                oos.writeObject(message);
+            }
+            data = bos.toByteArray();
+        }
+
+        if (debug) {
+            System.out.println(DatatypeConverter.printHexBinary(data));
+        }
+        return data;
+    }
+
+    public static Object streamDecrypt(byte[] data, SecretKey key,
+        MessageDigest digest) throws Exception {
+
+        Cipher decCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
+        decCipher.init(Cipher.DECRYPT_MODE, key);
+        digest.reset();
+        try (ByteArrayInputStream bis = new ByteArrayInputStream(data);
+            DigestInputStream dis = new DigestInputStream(bis, digest);
+            CipherInputStream cis = new CipherInputStream(dis, decCipher)) {
+
+            try (ObjectInputStream ois = new ObjectInputStream(cis)) {
+                return ois.readObject();
+            }
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        MessageDigest digest = MessageDigest.getInstance("SHA1");
+        SecretKeySpec key = new SecretKeySpec(
+            DatatypeConverter.parseHexBinary(
+            "12345678123456781234567812345678"), "AES");
+
+        // Run 'message' through streamEncrypt
+        byte[] se = streamEncrypt(message, key, digest);
+        // 'digest' already has the value from the stream, just finish the op
+        byte[] sd = digest.digest();
+        digest.reset();
+        // Run 'message' through blockEncrypt
+        byte[] be = blockEncrypt(message, key);
+        // Take digest of encrypted blockEncrypt result
+        byte[] bd = digest.digest(be);
+        // Verify both returned the same value
+        if (!Arrays.equals(sd, bd)) {
+            System.err.println("Stream: "+DatatypeConverter.printHexBinary(se)+
+                "\t Digest: "+DatatypeConverter.printHexBinary(sd));
+            System.err.println("Block : "+DatatypeConverter.printHexBinary(be)+
+                "\t Digest: "+DatatypeConverter.printHexBinary(bd));
+            throw new Exception("stream & block encryption does not match");
+        }
+
+        digest.reset();
+        // Sanity check: Decrypt separately from stream to verify operations
+        String bm = (String) blockDecrypt(be, key);
+        if (message.compareTo(bm) != 0) {
+            System.err.println("Expected: "+message+"\nBlock:    "+bm);
+            throw new Exception("Block decryption does not match expected");
+        }
+
+        // Have decryption and digest included in the object stream
+        String sm = (String) streamDecrypt(se, key, digest);
+        if (message.compareTo(sm) != 0) {
+            System.err.println("Expected: "+message+"\nStream:   "+sm);
+            throw new Exception("Stream decryption does not match expected.");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/text/View/8014863/bug8014863.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2007, 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.
+ */
+
+/*
+ * @test
+ * @bug 8014863
+ * @summary  Tests the calculation of the line breaks when a text is inserted
+ * @author Dmitry Markov
+ * @library ../../../regtesthelpers
+ * @build Util
+ * @run main bug8014863
+ */
+
+import sun.awt.SunToolkit;
+
+import javax.swing.*;
+import javax.swing.text.html.HTMLEditorKit;
+import java.awt.*;
+import java.awt.event.KeyEvent;
+
+public class bug8014863 {
+
+    private static JEditorPane editorPane;
+    private static Robot robot;
+    private static SunToolkit toolkit;
+
+    public static void main(String[] args) throws Exception {
+        toolkit = (SunToolkit) Toolkit.getDefaultToolkit();
+        robot = new Robot();
+
+        createAndShowGUI();
+
+        toolkit.realSync();
+
+        Util.hitKeys(robot, KeyEvent.VK_HOME);
+        Util.hitKeys(robot, KeyEvent.VK_O);
+
+        toolkit.realSync();
+
+        if (3 != getNumberOfTextLines()) {
+            throw new RuntimeException("The number of texts lines does not meet the expectation");
+        }
+
+        Util.hitKeys(robot, KeyEvent.VK_N);
+
+        toolkit.realSync();
+
+        if (3 != getNumberOfTextLines()) {
+            throw new RuntimeException("The number of texts lines does not meet the expectation");
+        }
+
+        Util.hitKeys(robot, KeyEvent.VK_E);
+        Util.hitKeys(robot, KeyEvent.VK_SPACE);
+        Util.hitKeys(robot, KeyEvent.VK_T);
+        Util.hitKeys(robot, KeyEvent.VK_W);
+
+        toolkit.realSync();
+
+        if (3 != getNumberOfTextLines()) {
+            throw new RuntimeException("The number of texts lines does not meet the expectation");
+        }
+    }
+
+    private static int getNumberOfTextLines() throws Exception {
+        int numberOfLines = 0;
+        int caretPosition = getCaretPosition();
+        int current = 1;
+        int previous;
+
+        setCaretPosition(current);
+        do {
+            previous = current;
+            Util.hitKeys(robot, KeyEvent.VK_DOWN);
+            toolkit.realSync();
+            current = getCaretPosition();
+            numberOfLines++;
+        } while (current != previous);
+
+        setCaretPosition(caretPosition);
+        return numberOfLines;
+    }
+
+    private static int getCaretPosition() throws Exception {
+        final int[] result = new int[1];
+        SwingUtilities.invokeAndWait(new Runnable() {
+            public void run() {
+                result[0] = editorPane.getCaretPosition();
+            }
+        });
+        return result[0];
+    }
+
+    private static void setCaretPosition(final int position) throws Exception {
+        SwingUtilities.invokeAndWait(new Runnable() {
+            public void run() {
+                editorPane.setCaretPosition(position);
+            }
+        });
+    }
+
+    private static void createAndShowGUI() throws Exception {
+        SwingUtilities.invokeAndWait(new Runnable() {
+            public void run() {
+                try {
+                    UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
+                } catch (Exception ex) {
+                    throw new RuntimeException(ex);
+                }
+                JFrame frame = new JFrame();
+                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+
+                editorPane = new JEditorPane();
+                HTMLEditorKit editorKit = new HTMLEditorKit();
+                editorPane.setEditorKit(editorKit);
+                editorPane.setText("<p>qqqq <em>pp</em> qqqq <em>pp</em> " +
+                        "qqqq <em>pp</em> qqqq <em>pp</em> qqqq <em>pp</em> qqqq <em>pp" +
+                        "</em> qqqq <em>pp</em> qqqq <em>pp</em> qqqq <em>pp</em> qqqq</p>");
+                editorPane.setCaretPosition(1);
+
+                frame.add(editorPane);
+                frame.setSize(200, 200);
+                frame.setVisible(true);
+            }
+        });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/text/html/parser/Parser/7011777/bug7011777.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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 7011777
+ * @summary Tests correct parsing of a HTML comment inside 'script' tags
+ * @author Dmitry Markov
+ */
+
+import javax.swing.text.html.HTMLEditorKit;
+import javax.swing.text.html.parser.ParserDelegator;
+import java.io.StringReader;
+
+public class bug7011777 {
+    static String comment = "<!--\n" +
+            "function foo() {\n" +
+            "  var tag1 = \"</script>\";\n" +
+            "  var tag2 = \"<div>\";\n" +
+            "  var tag3 = \"</div>\";\n" +
+            "  var tag4 = \"<script>\";\n" +
+            "}\n" +
+            "// -->";
+    static String html = "<script>" + comment + "</script>";
+    public static void main(String[] args) throws Exception {
+            new ParserDelegator().parse(new StringReader(html), new MyParserCallback(), true);
+    }
+
+    static class MyParserCallback extends HTMLEditorKit.ParserCallback {
+
+        @Override
+        public void handleComment(char[] data, int pos) {
+            String commentWithoutTags = comment.substring("<!--".length(), comment.length() - "-->".length());
+            String str = new String(data);
+            if (!commentWithoutTags.equals(str)) {
+                System.out.println("Sample string:\n" + commentWithoutTags);
+                System.out.println("Returned string:\n" + str);
+                throw new RuntimeException("Test Failed, sample and returned strings are mismatched!");
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/xml/jaxp/XPath/8009579/XPathExceptionInitCause.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,220 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8009579
+ * @summary The initCause() incorrectly initialise the cause in
+ * XPathException class when used with XPathException(String)
+ * constructor.
+ * @run main XPathExceptionInitCause
+ * @author aleksej.efimov@oracle.com
+ */
+
+import javax.xml.xpath.XPathException;
+import java.io.ByteArrayOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectInputStream;
+import java.io.IOException;
+import java.io.InvalidClassException;
+
+
+public class XPathExceptionInitCause {
+
+    /* This is a serial form of XPathException with two causes serialized
+     * by JDK7 code:
+     *
+     *  ByteArrayOutputStream fser = new ByteArrayOutputStream();
+     *  ObjectOutputStream oos = new ObjectOutputStream(fser);
+     *  oos.writeObject(new XPathException(new Exception()).initCause(null));
+     *  oos.close();
+     */
+    static final byte [] TWOCAUSES = {-84,-19,0,5,115,114,0,30,106,97,118,97,120,46,120,
+        109,108,46,120,112,97,116,104,46,88,80,97,116,104,69,120,99,101,112,116,
+        105,111,110,-26,-127,97,60,-120,119,127,28,2,0,1,76,0,5,99,97,117,115,101,
+        116,0,21,76,106,97,118,97,47,108,97,110,103,47,84,104,114,111,119,97,98,
+        108,101,59,120,114,0,19,106,97,118,97,46,108,97,110,103,46,69,120,99,101,
+        112,116,105,111,110,-48,-3,31,62,26,59,28,-60,2,0,0,120,114,0,19,106,97,
+        118,97,46,108,97,110,103,46,84,104,114,111,119,97,98,108,101,-43,-58,53,
+        39,57,119,-72,-53,3,0,4,76,0,5,99,97,117,115,101,113,0,126,0,1,76,0,13,
+        100,101,116,97,105,108,77,101,115,115,97,103,101,116,0,18,76,106,97,118,
+        97,47,108,97,110,103,47,83,116,114,105,110,103,59,91,0,10,115,116,97,99,
+        107,84,114,97,99,101,116,0,30,91,76,106,97,118,97,47,108,97,110,103,47,83,
+        116,97,99,107,84,114,97,99,101,69,108,101,109,101,110,116,59,76,0,20,115,
+        117,112,112,114,101,115,115,101,100,69,120,99,101,112,116,105,111,110,115,
+        116,0,16,76,106,97,118,97,47,117,116,105,108,47,76,105,115,116,59,120,112,
+        112,112,117,114,0,30,91,76,106,97,118,97,46,108,97,110,103,46,83,116,97,99,
+        107,84,114,97,99,101,69,108,101,109,101,110,116,59,2,70,42,60,60,-3,34,57,
+        2,0,0,120,112,0,0,0,1,115,114,0,27,106,97,118,97,46,108,97,110,103,46,83,
+        116,97,99,107,84,114,97,99,101,69,108,101,109,101,110,116,97,9,-59,-102,
+        38,54,-35,-123,2,0,4,73,0,10,108,105,110,101,78,117,109,98,101,114,76,0,
+        14,100,101,99,108,97,114,105,110,103,67,108,97,115,115,113,0,126,0,4,76,
+        0,8,102,105,108,101,78,97,109,101,113,0,126,0,4,76,0,10,109,101,116,104,
+        111,100,78,97,109,101,113,0,126,0,4,120,112,0,0,0,31,116,0,23,88,80,97,116,
+        104,69,120,99,101,112,116,105,111,110,83,101,114,105,97,108,105,122,101,
+        116,0,28,88,80,97,116,104,69,120,99,101,112,116,105,111,110,83,101,114,105,
+        97,108,105,122,101,46,106,97,118,97,116,0,4,109,97,105,110,115,114,0,38,
+        106,97,118,97,46,117,116,105,108,46,67,111,108,108,101,99,116,105,111,110,
+        115,36,85,110,109,111,100,105,102,105,97,98,108,101,76,105,115,116,-4,15,
+        37,49,-75,-20,-114,16,2,0,1,76,0,4,108,105,115,116,113,0,126,0,6,120,114,
+        0,44,106,97,118,97,46,117,116,105,108,46,67,111,108,108,101,99,116,105,111,
+        110,115,36,85,110,109,111,100,105,102,105,97,98,108,101,67,111,108,108,101,
+        99,116,105,111,110,25,66,0,-128,-53,94,-9,30,2,0,1,76,0,1,99,116,0,22,76,
+        106,97,118,97,47,117,116,105,108,47,67,111,108,108,101,99,116,105,111,110,
+        59,120,112,115,114,0,19,106,97,118,97,46,117,116,105,108,46,65,114,114,97,
+        121,76,105,115,116,120,-127,-46,29,-103,-57,97,-99,3,0,1,73,0,4,115,105,
+        122,101,120,112,0,0,0,0,119,4,0,0,0,0,120,113,0,126,0,20,120,115,113,0,126,
+        0,2,113,0,126,0,21,112,117,113,0,126,0,8,0,0,0,1,115,113,0,126,0,10,0,0,0,
+        31,113,0,126,0,12,113,0,126,0,13,113,0,126,0,14,113,0,126,0,18,120
+    };
+
+    /* This is a serial form of ordinary XPathException serialized by JDK7 code:
+     *
+     *  Throwable cause = new Throwable( "message 1" );
+     *  XPathException xpathexcep = new XPathException( "message 2" );
+     *  xpathexcep.initCause( cause );
+     *  ByteArrayOutputStream fser = new ByteArrayOutputStream();
+     *  ObjectOutputStream oos = new ObjectOutputStream(fser);
+     *  oos.writeObject(xpathexcep);
+     *  oos.close();
+     */
+    static final byte [] NORMALJDK7SER = {-84,-19,0,5,115,114,0,30,106,97,118,97,120,
+        46,120,109,108,46,120,112,97,116,104,46,88,80,97,116,104,69,120,99,101,112,
+        116,105,111,110,-26,-127,97,60,-120,119,127,28,2,0,1,76,0,5,99,97,117,115,
+        101,116,0,21,76,106,97,118,97,47,108,97,110,103,47,84,104,114,111,119,97,
+        98,108,101,59,120,114,0,19,106,97,118,97,46,108,97,110,103,46,69,120,99,
+        101,112,116,105,111,110,-48,-3,31,62,26,59,28,-60,2,0,0,120,114,0,19,106,
+        97,118,97,46,108,97,110,103,46,84,104,114,111,119,97,98,108,101,-43,-58,
+        53,39,57,119,-72,-53,3,0,4,76,0,5,99,97,117,115,101,113,0,126,0,1,76,0,13,
+        100,101,116,97,105,108,77,101,115,115,97,103,101,116,0,18,76,106,97,118,
+        97,47,108,97,110,103,47,83,116,114,105,110,103,59,91,0,10,115,116,97,99,
+        107,84,114,97,99,101,116,0,30,91,76,106,97,118,97,47,108,97,110,103,47,83,
+        116,97,99,107,84,114,97,99,101,69,108,101,109,101,110,116,59,76,0,20,115,
+        117,112,112,114,101,115,115,101,100,69,120,99,101,112,116,105,111,110,115,
+        116,0,16,76,106,97,118,97,47,117,116,105,108,47,76,105,115,116,59,120,112,
+        115,113,0,126,0,3,113,0,126,0,8,116,0,9,109,101,115,115,97,103,101,32,49,
+        117,114,0,30,91,76,106,97,118,97,46,108,97,110,103,46,83,116,97,99,107,84,
+        114,97,99,101,69,108,101,109,101,110,116,59,2,70,42,60,60,-3,34,57,2,0,0,
+        120,112,0,0,0,1,115,114,0,27,106,97,118,97,46,108,97,110,103,46,83,116,97,
+        99,107,84,114,97,99,101,69,108,101,109,101,110,116,97,9,-59,-102,38,54,-35,
+        -123,2,0,4,73,0,10,108,105,110,101,78,117,109,98,101,114,76,0,14,100,101,
+        99,108,97,114,105,110,103,67,108,97,115,115,113,0,126,0,4,76,0,8,102,105,
+        108,101,78,97,109,101,113,0,126,0,4,76,0,10,109,101,116,104,111,100,78,97,
+        109,101,113,0,126,0,4,120,112,0,0,0,19,116,0,23,88,80,97,116,104,69,120,
+        99,101,112,116,105,111,110,83,101,114,105,97,108,105,122,101,116,0,28,88,
+        80,97,116,104,69,120,99,101,112,116,105,111,110,83,101,114,105,97,108,105,
+        122,101,46,106,97,118,97,116,0,4,109,97,105,110,115,114,0,38,106,97,118,
+        97,46,117,116,105,108,46,67,111,108,108,101,99,116,105,111,110,115,36,85,
+        110,109,111,100,105,102,105,97,98,108,101,76,105,115,116,-4,15,37,49,-75,
+        -20,-114,16,2,0,1,76,0,4,108,105,115,116,113,0,126,0,6,120,114,0,44,106,
+        97,118,97,46,117,116,105,108,46,67,111,108,108,101,99,116,105,111,110,115,
+        36,85,110,109,111,100,105,102,105,97,98,108,101,67,111,108,108,101,99,116,
+        105,111,110,25,66,0,-128,-53,94,-9,30,2,0,1,76,0,1,99,116,0,22,76,106,97,
+        118,97,47,117,116,105,108,47,67,111,108,108,101,99,116,105,111,110,59,120,
+        112,115,114,0,19,106,97,118,97,46,117,116,105,108,46,65,114,114,97,121,76,
+        105,115,116,120,-127,-46,29,-103,-57,97,-99,3,0,1,73,0,4,115,105,122,101,
+        120,112,0,0,0,0,119,4,0,0,0,0,120,113,0,126,0,22,120,116,0,9,109,101,115,
+        115,97,103,101,32,50,117,113,0,126,0,10,0,0,0,1,115,113,0,126,0,12,0,0,0,
+        20,113,0,126,0,14,113,0,126,0,15,113,0,126,0,16,113,0,126,0,20,120,112
+    };
+
+    //Serialize XPathException
+    static byte [] pickleXPE(XPathException xpe) throws IOException {
+        ByteArrayOutputStream bos =  new ByteArrayOutputStream();
+        ObjectOutputStream xpeos = new ObjectOutputStream(bos);
+        xpeos.writeObject(xpe);
+        xpeos.close();
+        return bos.toByteArray();
+    }
+
+    //Deserialize XPathException with byte array as serial data source
+    static XPathException unpickleXPE(byte [] ser)
+            throws IOException, ClassNotFoundException {
+        XPathException xpe;
+        ByteArrayInputStream bis = new ByteArrayInputStream(ser);
+        ObjectInputStream xpeis = new ObjectInputStream(bis);
+        xpe = (XPathException) xpeis.readObject();
+        xpeis.close();
+        return xpe;
+    }
+
+    public static void main(String[] args) throws Exception {
+        Throwable cause = new Throwable("message 1");
+        XPathException xpathexcep = new XPathException("message 2");
+
+        //Test XPE initCause() method
+        xpathexcep.initCause(cause);
+        System.out.println("getCause() result: '" + xpathexcep.getCause()
+                + "' Cause itself: '" + cause + "'");
+        if (!xpathexcep.getCause().toString().equals(cause.toString())) {
+            throw new Exception("Incorrect cause is set by initCause()");
+        }
+
+        //Test serialization/deserialization of initialized XPE
+        byte [] xpeserial;
+        XPathException xpedeser;
+        xpeserial = pickleXPE(xpathexcep);
+        xpedeser = unpickleXPE(xpeserial);
+        System.out.println("Serialized XPE: message='" + xpathexcep.getMessage()
+                + "' cause='" + xpathexcep.getCause().toString() + "'");
+        System.out.println("Deserialized XPE: message='" + xpedeser.getMessage()
+                + "' cause='" + xpedeser.getCause().toString()+"'");
+        if(xpedeser.getCause() == null ||
+                !xpedeser.getCause().toString().equals(cause.toString()) ||
+                !xpedeser.getMessage().toString().equals("message 2") )
+            throw new Exception("XPathException incorrectly serialized/deserialized");
+
+        //Test serialization/deserialization of uninitialized cause in XPE
+        XPathException xpeuninit = new XPathException("uninitialized cause");
+        xpeserial = pickleXPE(xpeuninit);
+        xpedeser = unpickleXPE(xpeserial);
+        System.out.println("Serialized XPE: message='" + xpeuninit.getMessage()
+                + "' cause='" + xpeuninit.getCause()+"'");
+        System.out.println("Deserialized XPE: message='" + xpedeser.getMessage()
+                + "' cause='" + xpedeser.getCause()+"'");
+        if(xpedeser.getCause() != null ||
+                !xpedeser.getMessage().toString().equals("uninitialized cause") )
+            throw new Exception("XPathException incorrectly serialized/deserialized");
+
+        //Test deserialization of normal XPathException serialized by JDK7
+        XPathException xpejdk7 = unpickleXPE(NORMALJDK7SER);
+        if(xpejdk7 == null || xpejdk7.getCause() == null ||
+                !xpejdk7.getMessage().equals("message 2") ||
+                !xpejdk7.getCause().getMessage().equals("message 1"))
+            throw new Exception("XpathException serialized by JDK7 was "
+                    + "incorrectly deserialized.");
+
+        //Test deserialization of XPathException with two causes from JDK7.
+        //The serialization are done for the following XPathException object:
+        // new XPathException(new Exception()).initCause(null)
+        try {
+            xpejdk7 = unpickleXPE(TWOCAUSES);
+            throw new Exception("Expected InvalidClassException but it wasn't"
+                    + " observed");
+        } catch(InvalidClassException e) {
+            System.out.println("InvalidClassException caught as expected.");
+        }
+
+    }
+}
--- a/jdk/test/sun/awt/datatransfer/SuplementaryCharactersTransferTest.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/sun/awt/datatransfer/SuplementaryCharactersTransferTest.java	Mon Jun 10 10:38:33 2013 +0100
@@ -146,12 +146,6 @@
         }
 
         @Override
-        protected Image platformImageBytesOrStreamToImage(InputStream str,
-                byte[] bytes, long format) throws IOException {
-            throw new UnsupportedOperationException("Not supported yet.");
-        }
-
-        @Override
         protected byte[] imageToPlatformBytes(Image image, long format)
                 throws IOException {
             throw new UnsupportedOperationException("Not supported yet.");
@@ -161,5 +155,10 @@
         public ToolkitThreadBlockedHandler getToolkitThreadBlockedHandler() {
             throw new UnsupportedOperationException("Not supported yet.");
         }
+
+        @Override
+        protected Image platformImageBytesToImage(byte[] bytes, long format) throws IOException {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
     }
 }
\ No newline at end of file
--- a/jdk/test/sun/java2d/X11SurfaceData/SharedMemoryPixmapsTest/SharedMemoryPixmapsTest.sh	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/sun/java2d/X11SurfaceData/SharedMemoryPixmapsTest/SharedMemoryPixmapsTest.sh	Mon Jun 10 10:38:33 2013 +0100
@@ -1,3 +1,4 @@
+#!/bin/sh
 #
 # Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -21,7 +22,6 @@
 # questions.
 #
 
-#!/bin/sh
 # @test
 # @bug 6363434 6588884
 # @summary Verify that shared memory pixmaps are not broken
--- a/jdk/test/sun/management/jdp/JdpTest.sh	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/sun/management/jdp/JdpTest.sh	Mon Jun 10 10:38:33 2013 +0100
@@ -2,17 +2,17 @@
 
 # Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-# 
+#
 # This code is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License version 2 only, as
 # published by the Free Software Foundation.
-# 
+#
 # This code is distributed in the hope that it will be useful, but WITHOUT
 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 # FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 # version 2 for more details (a copy is included in the LICENSE file that
 # accompanied this code).
-# 
+#
 # You should have received a copy of the GNU General Public License version
 # 2 along with this work; if not, write to the Free Software Foundation,
 # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
@@ -22,8 +22,8 @@
 # questions.
 
 # @test
-# @bug 7169888 
-# @compile -XDignore.symbol.file JdpUnitTest.java JdpClient.java JdpDoSomething.java 
+# @bug 7169888
+# @compile -XDignore.symbol.file JdpUnitTest.java JdpClient.java JdpDoSomething.java
 # @run shell JdpTest.sh --jtreg --no-compile
 # @summary No word Failed expected in the test output
 
@@ -44,17 +44,20 @@
 _logname=".classes/output.txt"
 _last_pid=""
 
+_ip="224.0.23.178"
+_port="7095"
+_jmxport="4545"
 
 _do_compile(){
     # If the test run without JTReg, we have to compile it by our self
     # Under JTReg see @compile statement above
-    # sun.* packages is not included to symbol file lib/ct.sym so we have 
+    # sun.* packages is not included to symbol file lib/ct.sym so we have
     # to ignore it
 
     if [ ! -d ${_testclasses} ]
     then
 	  mkdir -p ${_testclasses}
-    fi   
+    fi
 
     rm -f ${_testclasses}/*.class
 
@@ -64,11 +67,11 @@
                                              JdpDoSomething.java  \
                                              JdpClient.java
 
-   
+
     if [ ! -f ${_testclasses}/JdpDoSomething.class -o ! -f ${_testclasses}/JdpClient.class -o ! -f ${_testclasses}/JdpUnitTest.class ]
     then
       echo "ERROR: Can't compile"
-      exit -1
+      exit 255
     fi
 }
 
@@ -84,10 +87,10 @@
   npid=`_get_pid`
   if [ "${npid}" = "" ]
   then
-     echo "ERROR: Test app not started"
+     echo "ERROR: Test app not started. Please check machine resources before filing a bug."
      if [ "${_jtreg}" = "yes" ]
      then
-       exit -1
+       exit 255
      fi
   fi
 }
@@ -100,53 +103,53 @@
    rm ${_lockFileName}
 
 # wait until VM is actually shuts down
-  while true 
+  while true
   do
     npid=`_get_pid`
-    if [ "${npid}" = "" ] 
+    if [ "${npid}" = "" ]
     then
       break
     fi
     sleep 1
-  done 
+  done
 }
-   
+
 _testme(){
   ${TESTJAVA}/bin/java \
   -cp ${_testclasses} \
   $* \
-    -Dcom.sun.management.jdp.port=7095 \
-    -Dcom.sun.management.jdp.address=239.255.255.225 \
-  JdpClient 
+    -Dcom.sun.management.jdp.port=${_port} \
+    -Dcom.sun.management.jdp.address=${_ip} \
+  JdpClient
 
-}   
+}
 
 
 _jcmd(){
     ${TESTJAVA}/bin/jcmd JdpDoSomething $* > /dev/null 2>/dev/null
-} 
+}
 
 
 _echo(){
     echo "$*"
     echo "$*" >> ${_logname}
 }
-   
+
 # ============= TESTS ======================================
-   
+
 test_01(){
-		
-    _echo "**** Test one ****"		
+
+    _echo "**** Test one ****"
 
     _app_start JdpUnitTest \
-    -Dcom.sun.management.jdp.port=7095 \
-    -Dcom.sun.management.jdp.address=239.255.255.225 \
+    -Dcom.sun.management.jdp.port=${_port} \
+    -Dcom.sun.management.jdp.address=${_ip} \
     -Dcom.sun.management.jdp.pause=5
 
     res=`_testme`
 
-    case "${res}" in 
-     OK*)  
+    case "${res}" in
+     OK*)
 	_echo "Passed"
      ;;
      *)
@@ -155,24 +158,24 @@
     esac
 
     _app_stop
-}  
+}
 
 test_02(){
-		
-    _echo "**** Test two ****"		
+
+    _echo "**** Test two ****"
 
     _app_start JdpDoSomething \
-     -Dcom.sun.management.jdp.port=7095 \
-     -Dcom.sun.management.jdp.address=239.255.255.225 \
+     -Dcom.sun.management.jdp.port=${_port} \
+     -Dcom.sun.management.jdp.address=${_ip} \
      -Dcom.sun.management.jdp.pause=5 \
-     -Dcom.sun.management.jmxremote.port=4545 \
+     -Dcom.sun.management.jmxremote.port=${_jmxport} \
      -Dcom.sun.management.jmxremote.authenticate=false \
      -Dcom.sun.management.jmxremote.ssl=false
 
     res=`_testme`
 
-    case "${res}" in 
-     OK*)  
+    case "${res}" in
+     OK*)
 	_echo "Passed"
      ;;
      *)
@@ -181,26 +184,26 @@
     esac
 
     _app_stop
-}  
+}
 
 test_03(){
-		
+
     _echo "**** Test three ****"
 
     _app_start JdpDoSomething
-    
+
     _jcmd  ManagementAgent.start\
-                jdp.port=7095 \
-                jdp.address=239.255.255.225 \
+                jdp.port=${_port} \
+                jdp.address=${_ip} \
                 jdp.pause=5 \
-                jmxremote.port=4545 \
+                jmxremote.port=${_jmxport} \
                 jmxremote.authenticate=false \
                 jmxremote.ssl=false
 
     res=`_testme`
 
-    case "${res}" in 
-     OK*)  
+    case "${res}" in
+     OK*)
 	_echo "Passed"
      ;;
      *)
@@ -209,7 +212,7 @@
     esac
 
     _app_stop
-}  
+}
 
 test_04(){
 
@@ -217,7 +220,7 @@
 
     _app_start JdpDoSomething \
      -Dcom.sun.management.jmxremote.autodiscovery=true \
-     -Dcom.sun.management.jmxremote.port=4545 \
+     -Dcom.sun.management.jmxremote.port=${_jmxport} \
      -Dcom.sun.management.jmxremote.authenticate=false \
      -Dcom.sun.management.jmxremote.ssl=false
 
@@ -243,7 +246,7 @@
 
     _jcmd  ManagementAgent.start\
                 jmxremote.autodiscovery=true \
-                jmxremote.port=4545 \
+                jmxremote.port=${_jmxport} \
                 jmxremote.authenticate=false \
                 jmxremote.ssl=false
 
@@ -279,20 +282,20 @@
 
 
 #------------------------------------------------------------------------------
-# reading parameters 
+# reading parameters
 
-for parm in "$@"  
+for parm in "$@"
 do
    case $parm in
   --verbose)      _verbose=yes  ;;
   --jtreg)        _jtreg=yes    ;;
   --no-compile)   _compile=no   ;;
   --testsuite=*)  _testsuite=`_echo $parm | sed "s,^--.*=\(.*\),\1,"`  ;;
-  *) 
-     echo "Undefined parameter $parm. Try --help for help" 
-     exit 
+  *)
+     echo "Undefined parameter $parm. Try --help for help"
+     exit
    ;;
- esac 
+ esac
 done
 
 if [ "${_compile}" = "yes" ]
@@ -325,11 +328,11 @@
 cat ${_testsrc}/policy.tpl | \
      sed -e "s,@_TESTCLASSES@,${_testclasses},g" -e "s,@TESTJAVA@,${TESTJAVA},g" \
  > ${_policyname}
- 
+
 fi
- 
+
 # Local mode tests
 for i in `echo ${_testsuite} | sed -e "s/,/ /g"`
 do
-  test_${i} 
+  test_${i}
 done
--- a/jdk/test/sun/management/jdp/JdpUnitTest.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/sun/management/jdp/JdpUnitTest.java	Mon Jun 10 10:38:33 2013 +0100
@@ -32,6 +32,12 @@
 
 public class JdpUnitTest {
 
+
+    static byte[] russian_name = {(byte)0xd0,(byte)0xbf,(byte)0xd1,(byte)0x80,(byte)0xd0,(byte)0xbe,(byte)0xd0,(byte)0xb2,
+                                  (byte)0xd0,(byte)0xb5,(byte)0xd1,(byte)0x80,(byte)0xd0,(byte)0xba,(byte)0xd0,(byte)0xb0,
+                                  (byte)0x20,(byte)0xd1,(byte)0x81,(byte)0xd0,(byte)0xb2,(byte)0xd1,(byte)0x8f,(byte)0xd0,
+                                  (byte)0xb7,(byte)0xd0,(byte)0xb8,(byte)0x0a};
+
     /**
      * This test tests that complete packet is build correctly
      */
@@ -42,7 +48,7 @@
         {
             JdpJmxPacket p1 = new JdpJmxPacket(UUID.randomUUID(), "fake://unit-test");
             p1.setMainClass("FakeUnitTest");
-            p1.setInstanceName("Fake");
+            p1.setInstanceName( new String(russian_name,"UTF-8"));
             byte[] b = p1.getPacketData();
 
             JdpJmxPacket p2 = new JdpJmxPacket(b);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/misc/FloatingDecimal/OldFDBigIntForTest.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,491 @@
+/*
+ * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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 );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/misc/FloatingDecimal/OldFloatingDecimalForTest.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,2436 @@
+/*
+ * 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 sun.misc.DoubleConsts;
+import sun.misc.FloatConsts;
+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 > DoubleConsts.MAX_EXPONENT) {         // Infinite result
+                // overflow to properly signed infinity
+                return new OldFloatingDecimalForTest(sign * Double.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 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)(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 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 <= FloatConsts.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/sun/misc/FloatingDecimal/TestFDBigInteger.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,426 @@
+/*
+ * 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
+ * @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");
+        }
+        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");
+        }
+        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/sun/misc/FloatingDecimal/TestFloatingDecimal.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,324 @@
+/*
+ * 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
+ * @author Brian Burkhalter
+ */
+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/sun/net/www/protocol/http/HttpStreams.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,185 @@
+/*
+ * 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.
+ */
+
+/**
+ * @test
+ * @bug 8011719
+ * @summary Basic checks to verify behavior of returned input streams
+ */
+
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpServer;
+import java.io.*;
+import java.net.*;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+
+public class HttpStreams {
+
+    void client(String u) throws Exception {
+        byte[] ba = new byte[5];
+        HttpURLConnection urlc = (HttpURLConnection)(new URL(u)).openConnection();
+        int resp = urlc.getResponseCode();
+        InputStream is;
+        if (resp == 200)
+            is = urlc.getInputStream();
+        else
+            is = urlc.getErrorStream();
+
+        expectNoThrow(() -> { is.read(); }, "read on open stream should not throw :" + u);
+        expectNoThrow(() -> { is.close(); }, "close should never throw: " + u);
+        expectNoThrow(() -> { is.close(); }, "close should never throw: " + u);
+        expectThrow(() -> { is.read(); }, "read on closed stream should throw: " + u);
+        expectThrow(() -> { is.read(ba); }, "read on closed stream should throw: " + u);
+        expectThrow(() -> { is.read(ba, 0, 2); }, "read on closed stream should throw: " + u);
+    }
+
+    void test() throws Exception {
+        HttpServer server = null;
+        try {
+            server = startHttpServer();
+            String baseUrl = "http://localhost:" + server.getAddress().getPort() + "/";
+            client(baseUrl +  "chunked/");
+            client(baseUrl +  "fixed/");
+            client(baseUrl +  "error/");
+            client(baseUrl +  "chunkedError/");
+
+            // Test with a response cache
+            ResponseCache ch = ResponseCache.getDefault();
+            ResponseCache.setDefault(new TrivialCacheHandler());
+            try {
+                client(baseUrl +  "chunked/");
+                client(baseUrl +  "fixed/");
+                client(baseUrl +  "error/");
+                client(baseUrl +  "chunkedError/");
+            } finally {
+                ResponseCache.setDefault(ch);
+            }
+        } finally {
+            if (server != null)
+                server.stop(0);
+        }
+
+        System.out.println("passed: " + pass + ", failed: " + fail);
+        if (fail > 0)
+            throw new RuntimeException("some tests failed check output");
+    }
+
+    public static void main(String[] args) throws Exception {
+        (new HttpStreams()).test();
+    }
+
+    // HTTP Server
+    HttpServer startHttpServer() throws IOException {
+        HttpServer httpServer = HttpServer.create(new InetSocketAddress(0), 0);
+        httpServer.createContext("/chunked/", new ChunkedHandler());
+        httpServer.createContext("/fixed/", new FixedHandler());
+        httpServer.createContext("/error/", new ErrorHandler());
+        httpServer.createContext("/chunkedError/", new ChunkedErrorHandler());
+        httpServer.start();
+        return httpServer;
+    }
+
+    static abstract class AbstractHandler implements HttpHandler {
+        @Override
+        public void handle(HttpExchange t) throws IOException {
+            try (InputStream is = t.getRequestBody()) {
+                while (is.read() != -1);
+            }
+            t.sendResponseHeaders(respCode(), length());
+            try (OutputStream os = t.getResponseBody()) {
+                os.write(message());
+            }
+            t.close();
+        }
+
+        abstract int respCode();
+        abstract int length();
+        abstract byte[] message();
+    }
+
+    static class ChunkedHandler extends AbstractHandler {
+        static final byte[] ba =
+                "Hello there from chunked handler!".getBytes(StandardCharsets.US_ASCII);
+        int respCode() { return 200; }
+        int length() { return 0; }
+        byte[] message() { return ba; }
+    }
+
+    static class FixedHandler extends AbstractHandler {
+        static final byte[] ba =
+                "Hello there from fixed handler!".getBytes(StandardCharsets.US_ASCII);
+        int respCode() { return 200; }
+        int length() { return ba.length; }
+        byte[] message() { return ba; }
+    }
+
+    static class ErrorHandler extends AbstractHandler {
+        static final byte[] ba =
+                "This is an error mesg from the server!".getBytes(StandardCharsets.US_ASCII);
+        int respCode() { return 400; }
+        int length() { return ba.length; }
+        byte[] message() { return ba; }
+    }
+
+    static class ChunkedErrorHandler extends ErrorHandler {
+        int length() { return 0; }
+    }
+
+    static class TrivialCacheHandler extends ResponseCache
+    {
+       public CacheResponse get(URI uri, String rqstMethod, Map rqstHeaders) {
+          return null;
+       }
+
+       public CacheRequest put(URI uri, URLConnection conn) {
+          return new TrivialCacheRequest();
+       }
+    }
+
+    static class TrivialCacheRequest extends CacheRequest
+    {
+       ByteArrayOutputStream baos = new ByteArrayOutputStream();
+       public void abort() {}
+       public OutputStream getBody() throws IOException { return baos; }
+    }
+
+    static interface ThrowableRunnable {
+        void run() throws IOException;
+    }
+
+    void expectThrow(ThrowableRunnable r, String msg) {
+        try { r.run(); fail(msg); } catch (IOException x) { pass(); }
+    }
+
+    void expectNoThrow(ThrowableRunnable r, String msg) {
+        try { r.run(); pass(); } catch (IOException x) { fail(msg, x); }
+    }
+
+    private int pass;
+    private int fail;
+    void pass() { pass++; }
+    void fail(String msg, Exception x) { System.out.println(msg); x.printStackTrace(); fail++; }
+    void fail(String msg) { System.out.println(msg); Thread.dumpStack(); fail++; }
+}
--- a/jdk/test/sun/rmi/rmic/manifestClassPath/run.sh	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/sun/rmi/rmic/manifestClassPath/run.sh	Mon Jun 10 10:38:33 2013 +0100
@@ -1,3 +1,4 @@
+#!/bin/sh
 #
 # Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -21,7 +22,6 @@
 # questions.
 #
 
-#!/bin/sh
 # @test
 # @bug 6473331 6485027 6934615
 # @summary Test handling of the Class-Path attribute in jar file manifests
--- a/jdk/test/sun/rmi/rmic/newrmic/equivalence/batch.sh	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/sun/rmi/rmic/newrmic/equivalence/batch.sh	Mon Jun 10 10:38:33 2013 +0100
@@ -1,3 +1,4 @@
+#!/bin/sh
 #
 # Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -21,7 +22,6 @@
 # questions.
 #
 
-#!/bin/sh
 #
 # Usage: batch.sh classpath classes...
 #
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/krb5/tools/KtabZero.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,78 @@
+/*
+ * 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 sun.security.krb5.internal.ktab.KeyTab;
+import sun.security.krb5.internal.ktab.KeyTabConstants;
+
+import java.io.File;
+import java.lang.reflect.Field;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+/*
+ * @test
+ * @bug 8014196
+ * @summary ktab creates a file with zero kt_vno
+ */
+public class KtabZero {
+
+    static final String NAME = "k.tab";
+
+    public static void main(String[] args) throws Exception {
+
+        // 0. Non-existing keytab
+        Files.deleteIfExists(Paths.get(NAME));
+        check(true);
+
+        // 1. Create with KeyTab
+        Files.deleteIfExists(Paths.get(NAME));
+        KeyTab.getInstance(NAME).save();
+        check(false);
+
+        // 2. Create with the tool
+        Files.deleteIfExists(Paths.get(NAME));
+        try {
+            Class ktab = Class.forName("sun.security.krb5.internal.tools.Ktab");
+            ktab.getDeclaredMethod("main", String[].class).invoke(null,
+                    (Object)(("-k " + NAME + " -a me@HERE pass").split(" ")));
+        } catch (ClassNotFoundException cnfe) {
+            // Only Windows has ktab tool
+            System.out.println("No ktab tool here. Ignored.");
+            return;
+        }
+        check(false);
+    }
+
+    // Checks existence as well as kt-vno
+    static void check(boolean showBeMissing) throws Exception {
+        KeyTab kt = KeyTab.getInstance(NAME);
+        if (kt.isMissing() != showBeMissing) {
+            throw new Exception("isMissing is not " + showBeMissing);
+        }
+        Field f = KeyTab.class.getDeclaredField("kt_vno");
+        f.setAccessible(true);
+        if (f.getInt(kt) != KeyTabConstants.KRB5_KT_VNO) {
+            throw new Exception("kt_vno is " + f.getInt(kt));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/krb5/tools/ktzero.sh	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,74 @@
+#
+# 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.
+#
+
+# @test
+# @bug 8014196
+# @summary ktab creates a file with zero kt_vno
+# @run shell ktzero.sh
+#
+
+if [ "${TESTJAVA}" = "" ] ; then
+  JAVAC_CMD=`which javac`
+  TESTJAVA=`dirname $JAVAC_CMD`/..
+fi
+
+if [ "${TESTSRC}" = "" ] ; then
+  TESTSRC="."
+fi
+
+OS=`uname -s`
+case "$OS" in
+  CYGWIN* )
+    FS="/"
+    ;;
+  Windows_* )
+    FS="\\"
+    ;;
+  * )
+    FS="/"
+    echo "Unsupported system!"
+    exit 0;
+    ;;
+esac
+
+KEYTAB=ktzero.tmp
+
+rm $KEYTAB 2> /dev/null
+KTAB="${TESTJAVA}${FS}bin${FS}ktab -k $KEYTAB"
+
+# Listing non-existing ktab should fail
+$KTAB -l && exit 1
+
+# Can add to non-existing ktab
+$KTAB -a me@LOCAL mine || exit 2
+
+# Now can be listed
+$KTAB -l || exit 3
+
+echo ABCDEFG > $KEYTAB
+
+# Invalid keytab should fail for all commands
+$KTAB -l && exit 4
+$KTAB -a me@LOCAL mine && exit 2
+
+exit 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/pkcs11/tls/TestLeadingZeroesP11.java	Mon Jun 10 10:38:33 2013 +0100
@@ -0,0 +1,410 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8014618
+ * @summary Need to strip leading zeros in TlsPremasterSecret of DHKeyAgreement
+ * @library ..
+ * @author Pasi Eronen
+ */
+
+import java.io.*;
+import java.security.*;
+import java.security.spec.*;
+import java.security.interfaces.*;
+import javax.crypto.*;
+import javax.crypto.spec.*;
+import javax.crypto.interfaces.*;
+
+/**
+ * Test that leading zeroes are stripped in TlsPremasterSecret case,
+ * but are left as-is in other cases.
+ *
+ * We use pre-generated keypairs, since with randomly generated keypairs,
+ * a leading zero happens only (roughly) 1 out of 256 cases.
+ */
+
+public class TestLeadingZeroesP11 extends PKCS11Test {
+
+    public static void main(String[] args) throws Exception {
+        main(new TestLeadingZeroesP11());
+    }
+
+    public void main(Provider p) throws Exception {
+
+        // decode pre-generated keypairs
+        KeyFactory kfac = KeyFactory.getInstance("DH", p);
+        PublicKey alicePubKey =
+            kfac.generatePublic(new X509EncodedKeySpec(alicePubKeyEnc));
+        PublicKey bobPubKey =
+            kfac.generatePublic(new X509EncodedKeySpec(bobPubKeyEnc));
+        PrivateKey alicePrivKey =
+            kfac.generatePrivate(new PKCS8EncodedKeySpec(alicePrivKeyEnc));
+        PrivateKey bobPrivKey =
+            kfac.generatePrivate(new PKCS8EncodedKeySpec(bobPrivKeyEnc));
+
+        // generate normal shared secret
+        KeyAgreement aliceKeyAgree = KeyAgreement.getInstance("DH", p);
+        aliceKeyAgree.init(alicePrivKey);
+        aliceKeyAgree.doPhase(bobPubKey, true);
+        byte[] sharedSecret = aliceKeyAgree.generateSecret();
+        System.out.println("shared secret:\n" + toHexString(sharedSecret));
+
+        // verify that leading zero is present
+        if (sharedSecret.length != 128) {
+            throw new Exception("Unexpected shared secret length");
+        }
+        if (sharedSecret[0] != 0) {
+            throw new Exception("First byte is not zero as expected");
+        }
+
+        // now, test TLS premaster secret
+        aliceKeyAgree.init(alicePrivKey);
+        aliceKeyAgree.doPhase(bobPubKey, true);
+        byte[] tlsPremasterSecret =
+            aliceKeyAgree.generateSecret("TlsPremasterSecret").getEncoded();
+        System.out.println(
+            "tls premaster secret:\n" + toHexString(tlsPremasterSecret));
+
+        // check that leading zero has been stripped
+        if (tlsPremasterSecret.length != 127) {
+            throw new Exception("Unexpected TLS premaster secret length");
+        }
+        if (tlsPremasterSecret[0] == 0) {
+            throw new Exception("First byte is zero");
+        }
+        for (int i = 0; i < tlsPremasterSecret.length; i++) {
+            if (tlsPremasterSecret[i] != sharedSecret[i+1]) {
+                throw new Exception("Shared secrets differ");
+            }
+        }
+
+    }
+
+    /*
+     * Converts a byte to hex digit and writes to the supplied buffer
+     */
+    private void byte2hex(byte b, StringBuffer buf) {
+        char[] hexChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
+                            '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+        int high = ((b & 0xf0) >> 4);
+        int low = (b & 0x0f);
+        buf.append(hexChars[high]);
+        buf.append(hexChars[low]);
+    }
+
+    /*
+     * Converts a byte array to hex string
+     */
+    private String toHexString(byte[] block) {
+        StringBuffer buf = new StringBuffer();
+
+        int len = block.length;
+
+        for (int i = 0; i < len; i++) {
+             byte2hex(block[i], buf);
+             if (i < len-1) {
+                 buf.append(":");
+             }
+        }
+        return buf.toString();
+    }
+
+    private static final byte alicePubKeyEnc[] = {
+        (byte)0x30, (byte)0x82, (byte)0x01, (byte)0x24,
+        (byte)0x30, (byte)0x81, (byte)0x99, (byte)0x06,
+        (byte)0x09, (byte)0x2A, (byte)0x86, (byte)0x48,
+        (byte)0x86, (byte)0xF7, (byte)0x0D, (byte)0x01,
+        (byte)0x03, (byte)0x01, (byte)0x30, (byte)0x81,
+        (byte)0x8B, (byte)0x02, (byte)0x81, (byte)0x81,
+        (byte)0x00, (byte)0xF4, (byte)0x88, (byte)0xFD,
+        (byte)0x58, (byte)0x4E, (byte)0x49, (byte)0xDB,
+        (byte)0xCD, (byte)0x20, (byte)0xB4, (byte)0x9D,
+        (byte)0xE4, (byte)0x91, (byte)0x07, (byte)0x36,
+        (byte)0x6B, (byte)0x33, (byte)0x6C, (byte)0x38,
+        (byte)0x0D, (byte)0x45, (byte)0x1D, (byte)0x0F,
+        (byte)0x7C, (byte)0x88, (byte)0xB3, (byte)0x1C,
+        (byte)0x7C, (byte)0x5B, (byte)0x2D, (byte)0x8E,
+        (byte)0xF6, (byte)0xF3, (byte)0xC9, (byte)0x23,
+        (byte)0xC0, (byte)0x43, (byte)0xF0, (byte)0xA5,
+        (byte)0x5B, (byte)0x18, (byte)0x8D, (byte)0x8E,
+        (byte)0xBB, (byte)0x55, (byte)0x8C, (byte)0xB8,
+        (byte)0x5D, (byte)0x38, (byte)0xD3, (byte)0x34,
+        (byte)0xFD, (byte)0x7C, (byte)0x17, (byte)0x57,
+        (byte)0x43, (byte)0xA3, (byte)0x1D, (byte)0x18,
+        (byte)0x6C, (byte)0xDE, (byte)0x33, (byte)0x21,
+        (byte)0x2C, (byte)0xB5, (byte)0x2A, (byte)0xFF,
+        (byte)0x3C, (byte)0xE1, (byte)0xB1, (byte)0x29,
+        (byte)0x40, (byte)0x18, (byte)0x11, (byte)0x8D,
+        (byte)0x7C, (byte)0x84, (byte)0xA7, (byte)0x0A,
+        (byte)0x72, (byte)0xD6, (byte)0x86, (byte)0xC4,
+        (byte)0x03, (byte)0x19, (byte)0xC8, (byte)0x07,
+        (byte)0x29, (byte)0x7A, (byte)0xCA, (byte)0x95,
+        (byte)0x0C, (byte)0xD9, (byte)0x96, (byte)0x9F,
+        (byte)0xAB, (byte)0xD0, (byte)0x0A, (byte)0x50,
+        (byte)0x9B, (byte)0x02, (byte)0x46, (byte)0xD3,
+        (byte)0x08, (byte)0x3D, (byte)0x66, (byte)0xA4,
+        (byte)0x5D, (byte)0x41, (byte)0x9F, (byte)0x9C,
+        (byte)0x7C, (byte)0xBD, (byte)0x89, (byte)0x4B,
+        (byte)0x22, (byte)0x19, (byte)0x26, (byte)0xBA,
+        (byte)0xAB, (byte)0xA2, (byte)0x5E, (byte)0xC3,
+        (byte)0x55, (byte)0xE9, (byte)0x2F, (byte)0x78,
+        (byte)0xC7, (byte)0x02, (byte)0x01, (byte)0x02,
+        (byte)0x02, (byte)0x02, (byte)0x02, (byte)0x00,
+        (byte)0x03, (byte)0x81, (byte)0x85, (byte)0x00,
+        (byte)0x02, (byte)0x81, (byte)0x81, (byte)0x00,
+        (byte)0xEE, (byte)0xD6, (byte)0xB1, (byte)0xA3,
+        (byte)0xB4, (byte)0x78, (byte)0x2B, (byte)0x35,
+        (byte)0xEF, (byte)0xCD, (byte)0x17, (byte)0x86,
+        (byte)0x63, (byte)0x2B, (byte)0x97, (byte)0x0E,
+        (byte)0x7A, (byte)0xD1, (byte)0xFF, (byte)0x7A,
+        (byte)0xEB, (byte)0x57, (byte)0x61, (byte)0xA1,
+        (byte)0xF7, (byte)0x90, (byte)0x11, (byte)0xA7,
+        (byte)0x79, (byte)0x28, (byte)0x69, (byte)0xBA,
+        (byte)0xA7, (byte)0xB2, (byte)0x37, (byte)0x17,
+        (byte)0xAE, (byte)0x3C, (byte)0x92, (byte)0x89,
+        (byte)0x88, (byte)0xE5, (byte)0x7E, (byte)0x8E,
+        (byte)0xF0, (byte)0x24, (byte)0xD0, (byte)0xE1,
+        (byte)0xC4, (byte)0xB0, (byte)0x26, (byte)0x5A,
+        (byte)0x1E, (byte)0xBD, (byte)0xA0, (byte)0xCF,
+        (byte)0x3E, (byte)0x97, (byte)0x2A, (byte)0x13,
+        (byte)0x92, (byte)0x3B, (byte)0x39, (byte)0xD0,
+        (byte)0x1D, (byte)0xA3, (byte)0x6B, (byte)0x3E,
+        (byte)0xC2, (byte)0xBB, (byte)0x14, (byte)0xB6,
+        (byte)0xE2, (byte)0x4C, (byte)0x0E, (byte)0x5B,
+        (byte)0x4B, (byte)0xA4, (byte)0x9D, (byte)0xA6,
+        (byte)0x21, (byte)0xB0, (byte)0xF9, (byte)0xDE,
+        (byte)0x55, (byte)0xAE, (byte)0x5C, (byte)0x29,
+        (byte)0x0E, (byte)0xC1, (byte)0xFC, (byte)0xBA,
+        (byte)0x51, (byte)0xD3, (byte)0xB6, (byte)0x6D,
+        (byte)0x75, (byte)0x72, (byte)0xDF, (byte)0x43,
+        (byte)0xAB, (byte)0x94, (byte)0x21, (byte)0x6E,
+        (byte)0x0C, (byte)0xD1, (byte)0x93, (byte)0x54,
+        (byte)0x56, (byte)0x7D, (byte)0x4B, (byte)0x90,
+        (byte)0xF1, (byte)0x94, (byte)0x45, (byte)0xD4,
+        (byte)0x2A, (byte)0x71, (byte)0xA1, (byte)0xB8,
+        (byte)0xDD, (byte)0xAA, (byte)0x05, (byte)0xF0,
+        (byte)0x27, (byte)0x37, (byte)0xBD, (byte)0x44
+    };
+
+    private static final byte alicePrivKeyEnc[] = {
+        (byte)0x30, (byte)0x81, (byte)0xE3, (byte)0x02,
+        (byte)0x01, (byte)0x00, (byte)0x30, (byte)0x81,
+        (byte)0x99, (byte)0x06, (byte)0x09, (byte)0x2A,
+        (byte)0x86, (byte)0x48, (byte)0x86, (byte)0xF7,
+        (byte)0x0D, (byte)0x01, (byte)0x03, (byte)0x01,
+        (byte)0x30, (byte)0x81, (byte)0x8B, (byte)0x02,
+        (byte)0x81, (byte)0x81, (byte)0x00, (byte)0xF4,
+        (byte)0x88, (byte)0xFD, (byte)0x58, (byte)0x4E,
+        (byte)0x49, (byte)0xDB, (byte)0xCD, (byte)0x20,
+        (byte)0xB4, (byte)0x9D, (byte)0xE4, (byte)0x91,
+        (byte)0x07, (byte)0x36, (byte)0x6B, (byte)0x33,
+        (byte)0x6C, (byte)0x38, (byte)0x0D, (byte)0x45,
+        (byte)0x1D, (byte)0x0F, (byte)0x7C, (byte)0x88,
+        (byte)0xB3, (byte)0x1C, (byte)0x7C, (byte)0x5B,
+        (byte)0x2D, (byte)0x8E, (byte)0xF6, (byte)0xF3,
+        (byte)0xC9, (byte)0x23, (byte)0xC0, (byte)0x43,
+        (byte)0xF0, (byte)0xA5, (byte)0x5B, (byte)0x18,
+        (byte)0x8D, (byte)0x8E, (byte)0xBB, (byte)0x55,
+        (byte)0x8C, (byte)0xB8, (byte)0x5D, (byte)0x38,
+        (byte)0xD3, (byte)0x34, (byte)0xFD, (byte)0x7C,
+        (byte)0x17, (byte)0x57, (byte)0x43, (byte)0xA3,
+        (byte)0x1D, (byte)0x18, (byte)0x6C, (byte)0xDE,
+        (byte)0x33, (byte)0x21, (byte)0x2C, (byte)0xB5,
+        (byte)0x2A, (byte)0xFF, (byte)0x3C, (byte)0xE1,
+        (byte)0xB1, (byte)0x29, (byte)0x40, (byte)0x18,
+        (byte)0x11, (byte)0x8D, (byte)0x7C, (byte)0x84,
+        (byte)0xA7, (byte)0x0A, (byte)0x72, (byte)0xD6,
+        (byte)0x86, (byte)0xC4, (byte)0x03, (byte)0x19,
+        (byte)0xC8, (byte)0x07, (byte)0x29, (byte)0x7A,
+        (byte)0xCA, (byte)0x95, (byte)0x0C, (byte)0xD9,
+        (byte)0x96, (byte)0x9F, (byte)0xAB, (byte)0xD0,
+        (byte)0x0A, (byte)0x50, (byte)0x9B, (byte)0x02,
+        (byte)0x46, (byte)0xD3, (byte)0x08, (byte)0x3D,
+        (byte)0x66, (byte)0xA4, (byte)0x5D, (byte)0x41,
+        (byte)0x9F, (byte)0x9C, (byte)0x7C, (byte)0xBD,
+        (byte)0x89, (byte)0x4B, (byte)0x22, (byte)0x19,
+        (byte)0x26, (byte)0xBA, (byte)0xAB, (byte)0xA2,
+        (byte)0x5E, (byte)0xC3, (byte)0x55, (byte)0xE9,
+        (byte)0x2F, (byte)0x78, (byte)0xC7, (byte)0x02,
+        (byte)0x01, (byte)0x02, (byte)0x02, (byte)0x02,
+        (byte)0x02, (byte)0x00, (byte)0x04, (byte)0x42,
+        (byte)0x02, (byte)0x40, (byte)0x36, (byte)0x4D,
+        (byte)0xD0, (byte)0x58, (byte)0x64, (byte)0x91,
+        (byte)0x78, (byte)0xA2, (byte)0x4B, (byte)0x79,
+        (byte)0x46, (byte)0xFE, (byte)0xC9, (byte)0xD9,
+        (byte)0xCA, (byte)0x5C, (byte)0xF9, (byte)0xFD,
+        (byte)0x6C, (byte)0x5D, (byte)0x76, (byte)0x3A,
+        (byte)0x41, (byte)0x6D, (byte)0x44, (byte)0x62,
+        (byte)0x75, (byte)0x93, (byte)0x81, (byte)0x93,
+        (byte)0x00, (byte)0x4C, (byte)0xB1, (byte)0xD8,
+        (byte)0x7D, (byte)0x9D, (byte)0xF3, (byte)0x16,
+        (byte)0x2C, (byte)0x6C, (byte)0x9F, (byte)0x7A,
+        (byte)0x84, (byte)0xA3, (byte)0x7A, (byte)0xC1,
+        (byte)0x4F, (byte)0x60, (byte)0xE3, (byte)0xB5,
+        (byte)0x86, (byte)0x28, (byte)0x08, (byte)0x4D,
+        (byte)0x94, (byte)0xB6, (byte)0x04, (byte)0x0D,
+        (byte)0xAC, (byte)0xBD, (byte)0x1F, (byte)0x42,
+        (byte)0x8F, (byte)0x1B
+    };
+
+    private static final byte bobPubKeyEnc[] = {
+        (byte)0x30, (byte)0x82, (byte)0x01, (byte)0x23,
+        (byte)0x30, (byte)0x81, (byte)0x99, (byte)0x06,
+        (byte)0x09, (byte)0x2A, (byte)0x86, (byte)0x48,
+        (byte)0x86, (byte)0xF7, (byte)0x0D, (byte)0x01,
+        (byte)0x03, (byte)0x01, (byte)0x30, (byte)0x81,
+        (byte)0x8B, (byte)0x02, (byte)0x81, (byte)0x81,
+        (byte)0x00, (byte)0xF4, (byte)0x88, (byte)0xFD,
+        (byte)0x58, (byte)0x4E, (byte)0x49, (byte)0xDB,
+        (byte)0xCD, (byte)0x20, (byte)0xB4, (byte)0x9D,
+        (byte)0xE4, (byte)0x91, (byte)0x07, (byte)0x36,
+        (byte)0x6B, (byte)0x33, (byte)0x6C, (byte)0x38,
+        (byte)0x0D, (byte)0x45, (byte)0x1D, (byte)0x0F,
+        (byte)0x7C, (byte)0x88, (byte)0xB3, (byte)0x1C,
+        (byte)0x7C, (byte)0x5B, (byte)0x2D, (byte)0x8E,
+        (byte)0xF6, (byte)0xF3, (byte)0xC9, (byte)0x23,
+        (byte)0xC0, (byte)0x43, (byte)0xF0, (byte)0xA5,
+        (byte)0x5B, (byte)0x18, (byte)0x8D, (byte)0x8E,
+        (byte)0xBB, (byte)0x55, (byte)0x8C, (byte)0xB8,
+        (byte)0x5D, (byte)0x38, (byte)0xD3, (byte)0x34,
+        (byte)0xFD, (byte)0x7C, (byte)0x17, (byte)0x57,
+        (byte)0x43, (byte)0xA3, (byte)0x1D, (byte)0x18,
+        (byte)0x6C, (byte)0xDE, (byte)0x33, (byte)0x21,
+        (byte)0x2C, (byte)0xB5, (byte)0x2A, (byte)0xFF,
+        (byte)0x3C, (byte)0xE1, (byte)0xB1, (byte)0x29,
+        (byte)0x40, (byte)0x18, (byte)0x11, (byte)0x8D,
+        (byte)0x7C, (byte)0x84, (byte)0xA7, (byte)0x0A,
+        (byte)0x72, (byte)0xD6, (byte)0x86, (byte)0xC4,
+        (byte)0x03, (byte)0x19, (byte)0xC8, (byte)0x07,
+        (byte)0x29, (byte)0x7A, (byte)0xCA, (byte)0x95,
+        (byte)0x0C, (byte)0xD9, (byte)0x96, (byte)0x9F,
+        (byte)0xAB, (byte)0xD0, (byte)0x0A, (byte)0x50,
+        (byte)0x9B, (byte)0x02, (byte)0x46, (byte)0xD3,
+        (byte)0x08, (byte)0x3D, (byte)0x66, (byte)0xA4,
+        (byte)0x5D, (byte)0x41, (byte)0x9F, (byte)0x9C,
+        (byte)0x7C, (byte)0xBD, (byte)0x89, (byte)0x4B,
+        (byte)0x22, (byte)0x19, (byte)0x26, (byte)0xBA,
+        (byte)0xAB, (byte)0xA2, (byte)0x5E, (byte)0xC3,
+        (byte)0x55, (byte)0xE9, (byte)0x2F, (byte)0x78,
+        (byte)0xC7, (byte)0x02, (byte)0x01, (byte)0x02,
+        (byte)0x02, (byte)0x02, (byte)0x02, (byte)0x00,
+        (byte)0x03, (byte)0x81, (byte)0x84, (byte)0x00,
+        (byte)0x02, (byte)0x81, (byte)0x80, (byte)0x2C,
+        (byte)0x40, (byte)0xFA, (byte)0xF6, (byte)0xA6,
+        (byte)0xF8, (byte)0xAC, (byte)0xC2, (byte)0x4F,
+        (byte)0xCD, (byte)0xC7, (byte)0x37, (byte)0x93,
+        (byte)0xE5, (byte)0xE4, (byte)0x5E, (byte)0x18,
+        (byte)0x14, (byte)0xE6, (byte)0x50, (byte)0xDA,
+        (byte)0x55, (byte)0x38, (byte)0x5D, (byte)0x24,
+        (byte)0xF5, (byte)0x42, (byte)0x68, (byte)0x5F,
+        (byte)0xF5, (byte)0x15, (byte)0xC8, (byte)0x9B,
+        (byte)0x5D, (byte)0x06, (byte)0x3D, (byte)0xE1,
+        (byte)0x52, (byte)0x2F, (byte)0x98, (byte)0xFF,
+        (byte)0x37, (byte)0xBB, (byte)0x75, (byte)0x48,
+        (byte)0x48, (byte)0xE9, (byte)0x65, (byte)0x84,
+        (byte)0x37, (byte)0xBB, (byte)0xB3, (byte)0xE9,
+        (byte)0x36, (byte)0x01, (byte)0xB4, (byte)0x6A,
+        (byte)0x1C, (byte)0xB2, (byte)0x11, (byte)0x82,
+        (byte)0xCE, (byte)0x3D, (byte)0x65, (byte)0xE5,
+        (byte)0x3C, (byte)0x89, (byte)0xE9, (byte)0x52,
+        (byte)0x19, (byte)0xBD, (byte)0x58, (byte)0xF6,
+        (byte)0xA2, (byte)0x03, (byte)0xA8, (byte)0xB2,
+        (byte)0xA5, (byte)0xDB, (byte)0xEB, (byte)0xF5,
+        (byte)0x94, (byte)0xF9, (byte)0x46, (byte)0xBE,
+        (byte)0x45, (byte)0x4C, (byte)0x65, (byte)0xD2,
+        (byte)0xD1, (byte)0xCF, (byte)0xFF, (byte)0xFF,
+        (byte)0xFA, (byte)0x38, (byte)0xF1, (byte)0x72,
+        (byte)0xAB, (byte)0xB9, (byte)0x14, (byte)0x4E,
+        (byte)0xF5, (byte)0xF0, (byte)0x7A, (byte)0x8E,
+        (byte)0x45, (byte)0xFD, (byte)0x5B, (byte)0xF9,
+        (byte)0xA2, (byte)0x97, (byte)0x1B, (byte)0xAE,
+        (byte)0x2C, (byte)0x7B, (byte)0x6B, (byte)0x7C,
+        (byte)0x98, (byte)0xFE, (byte)0x58, (byte)0xDD,
+        (byte)0xBE, (byte)0xF6, (byte)0x1C, (byte)0x8E,
+        (byte)0xD0, (byte)0xA1, (byte)0x72
+    };
+
+    private static final byte bobPrivKeyEnc[] = {
+        (byte)0x30, (byte)0x81, (byte)0xE4, (byte)0x02,
+        (byte)0x01, (byte)0x00, (byte)0x30, (byte)0x81,
+        (byte)0x99, (byte)0x06, (byte)0x09, (byte)0x2A,
+        (byte)0x86, (byte)0x48, (byte)0x86, (byte)0xF7,
+        (byte)0x0D, (byte)0x01, (byte)0x03, (byte)0x01,
+        (byte)0x30, (byte)0x81, (byte)0x8B, (byte)0x02,
+        (byte)0x81, (byte)0x81, (byte)0x00, (byte)0xF4,
+        (byte)0x88, (byte)0xFD, (byte)0x58, (byte)0x4E,
+        (byte)0x49, (byte)0xDB, (byte)0xCD, (byte)0x20,
+        (byte)0xB4, (byte)0x9D, (byte)0xE4, (byte)0x91,
+        (byte)0x07, (byte)0x36, (byte)0x6B, (byte)0x33,
+        (byte)0x6C, (byte)0x38, (byte)0x0D, (byte)0x45,
+        (byte)0x1D, (byte)0x0F, (byte)0x7C, (byte)0x88,
+        (byte)0xB3, (byte)0x1C, (byte)0x7C, (byte)0x5B,
+        (byte)0x2D, (byte)0x8E, (byte)0xF6, (byte)0xF3,
+        (byte)0xC9, (byte)0x23, (byte)0xC0, (byte)0x43,
+        (byte)0xF0, (byte)0xA5, (byte)0x5B, (byte)0x18,
+        (byte)0x8D, (byte)0x8E, (byte)0xBB, (byte)0x55,
+        (byte)0x8C, (byte)0xB8, (byte)0x5D, (byte)0x38,
+        (byte)0xD3, (byte)0x34, (byte)0xFD, (byte)0x7C,
+        (byte)0x17, (byte)0x57, (byte)0x43, (byte)0xA3,
+        (byte)0x1D, (byte)0x18, (byte)0x6C, (byte)0xDE,
+        (byte)0x33, (byte)0x21, (byte)0x2C, (byte)0xB5,
+        (byte)0x2A, (byte)0xFF, (byte)0x3C, (byte)0xE1,
+        (byte)0xB1, (byte)0x29, (byte)0x40, (byte)0x18,
+        (byte)0x11, (byte)0x8D, (byte)0x7C, (byte)0x84,
+        (byte)0xA7, (byte)0x0A, (byte)0x72, (byte)0xD6,
+        (byte)0x86, (byte)0xC4, (byte)0x03, (byte)0x19,
+        (byte)0xC8, (byte)0x07, (byte)0x29, (byte)0x7A,
+        (byte)0xCA, (byte)0x95, (byte)0x0C, (byte)0xD9,
+        (byte)0x96, (byte)0x9F, (byte)0xAB, (byte)0xD0,
+        (byte)0x0A, (byte)0x50, (byte)0x9B, (byte)0x02,
+        (byte)0x46, (byte)0xD3, (byte)0x08, (byte)0x3D,
+        (byte)0x66, (byte)0xA4, (byte)0x5D, (byte)0x41,
+        (byte)0x9F, (byte)0x9C, (byte)0x7C, (byte)0xBD,
+        (byte)0x89, (byte)0x4B, (byte)0x22, (byte)0x19,
+        (byte)0x26, (byte)0xBA, (byte)0xAB, (byte)0xA2,
+        (byte)0x5E, (byte)0xC3, (byte)0x55, (byte)0xE9,
+        (byte)0x2F, (byte)0x78, (byte)0xC7, (byte)0x02,
+        (byte)0x01, (byte)0x02, (byte)0x02, (byte)0x02,
+        (byte)0x02, (byte)0x00, (byte)0x04, (byte)0x43,
+        (byte)0x02, (byte)0x41, (byte)0x00, (byte)0xE0,
+        (byte)0x31, (byte)0xE7, (byte)0x77, (byte)0xB8,
+        (byte)0xD0, (byte)0x7E, (byte)0x0A, (byte)0x9B,
+        (byte)0x94, (byte)0xD5, (byte)0x3D, (byte)0x33,
+        (byte)0x62, (byte)0x32, (byte)0x51, (byte)0xCE,
+        (byte)0x74, (byte)0x5C, (byte)0xA5, (byte)0x72,
+        (byte)0xD9, (byte)0x36, (byte)0xF3, (byte)0x8A,
+        (byte)0x3F, (byte)0x8B, (byte)0xC6, (byte)0xFE,
+        (byte)0xEF, (byte)0x94, (byte)0x8B, (byte)0x50,
+        (byte)0x41, (byte)0x9B, (byte)0x14, (byte)0xC8,
+        (byte)0xE9, (byte)0x1F, (byte)0x24, (byte)0x1F,
+        (byte)0x65, (byte)0x8E, (byte)0xD3, (byte)0x85,
+        (byte)0xD0, (byte)0x68, (byte)0x6C, (byte)0xF1,
+        (byte)0x79, (byte)0x45, (byte)0xD0, (byte)0x06,
+        (byte)0xA4, (byte)0xB8, (byte)0xE0, (byte)0x64,
+        (byte)0xF5, (byte)0x38, (byte)0x72, (byte)0x97,
+        (byte)0x00, (byte)0x23, (byte)0x5F
+    };
+}
+
--- a/jdk/test/sun/text/resources/LocaleData	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/sun/text/resources/LocaleData	Mon Jun 10 10:38:33 2013 +0100
@@ -7663,3 +7663,7 @@
 
 # bug 7114053
 LocaleNames/sq/sq=shqip
+
+# bug 7074882
+FormatData/mt/MonthNames/7=Awwissu
+FormatData/mt/MonthAbbreviations/7=Aww
--- a/jdk/test/sun/text/resources/LocaleDataTest.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/sun/text/resources/LocaleDataTest.java	Mon Jun 10 10:38:33 2013 +0100
@@ -35,7 +35,7 @@
  *      6645405 6650730 6910489 6573250 6870908 6585666 6716626 6914413 6916787
  *      6919624 6998391 7019267 7020960 7025837 7020583 7036905 7066203 7101495
  *      7003124 7085757 7028073 7171028 7189611 8000983 7195759 8004489 8006509
- *      7114053
+ *      7114053 7074882
  * @summary Verify locale data
  *
  */
--- a/jdk/test/tools/launcher/Arrrghs.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/tools/launcher/Arrrghs.java	Mon Jun 10 10:38:33 2013 +0100
@@ -24,7 +24,7 @@
 /**
  * @test
  * @bug 5030233 6214916 6356475 6571029 6684582 6742159 4459600 6758881 6753938
- *      6894719 6968053 7151434 7146424
+ *      6894719 6968053 7151434 7146424 8007333
  * @summary Argument parsing validation.
  * @compile -XDignore.symbol.file Arrrghs.java
  * @run main/othervm Arrrghs
@@ -310,6 +310,20 @@
         checkArgumentParsing("..\\..\\", "..\\..\\");
         checkArgumentParsing("../../", "../../");
         checkArgumentParsing("a b\\ c", "a", "b\\", "c");
+        // 2 back-slashes
+        checkArgumentParsing("\\\\?", "\\\\?");
+        // 3 back-slashes
+        checkArgumentParsing("\\\\\\?", "\\\\\\?");
+        // 4 back-slashes
+        checkArgumentParsing("\\\\\\\\?", "\\\\\\\\?");
+        // 5 back-slashes
+        checkArgumentParsing("\\\\\\\\\\?", "\\\\\\\\\\?");
+        // 6 back-slashes
+        checkArgumentParsing("\\\\\\\\\\\\?", "\\\\\\\\\\\\?");
+
+        // more treatment of  mixed slashes
+        checkArgumentParsing("f1/ f3\\ f4/", "f1/", "f3\\", "f4/");
+        checkArgumentParsing("f1/ f2\' ' f3/ f4/", "f1/", "f2\'", "'", "f3/", "f4/");
     }
 
     private void initEmptyDir(File emptyDir) throws IOException {
--- a/jdk/test/tools/launcher/MultipleJRE.sh	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/tools/launcher/MultipleJRE.sh	Mon Jun 10 10:38:33 2013 +0100
@@ -1,3 +1,4 @@
+#!/bin/sh
 # @test MultipleJRE.sh
 # @bug 4811102 4953711 4955505 4956301 4991229 4998210 5018605 6387069 6733959
 # @build PrintVersion
--- a/jdk/test/tools/launcher/VersionCheck.java	Fri May 31 10:34:25 2013 +0100
+++ b/jdk/test/tools/launcher/VersionCheck.java	Mon Jun 10 10:38:33 2013 +0100
@@ -49,6 +49,7 @@
         "javaw",
         "javaws",
         "jcontrol",
+        "jmc",
         "jvisualvm",
         "packager",
         "unpack200",
@@ -72,6 +73,7 @@
         "jdeps",
         "jinfo",
         "jmap",
+        "jmc",
         "jps",
         "jrunscript",
         "jjs",