changeset 14341:fe8df8e55825

Merge
author prr
date Mon, 25 Apr 2016 09:25:26 -0700
parents f60e53156db3 baeb5edb3893
children 0d0cbb576c3c
files src/jdk.jlink/share/classes/jdk/tools/jimage/ExtractedImage.java src/jdk.unsupported/share/classes/sun/misc/ManagedLocalsThread.java
diffstat 36 files changed, 2184 insertions(+), 888 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Mon Apr 25 18:07:45 2016 +0300
+++ b/.hgtags	Mon Apr 25 09:25:26 2016 -0700
@@ -357,3 +357,4 @@
 1565a0efe6f0ca411a6df277df1e069431c60988 jdk-9+112
 68f8be44b6a6b33dfa841ec671c0ba6e4056b372 jdk-9+113
 bb8379287f3736f38c52b2d1418784e2592461d1 jdk-9+114
+35225b837d66582037eeadeb471c13235dfd793d jdk-9+115
--- a/make/lib/CoreLibraries.gmk	Mon Apr 25 18:07:45 2016 +0300
+++ b/make/lib/CoreLibraries.gmk	Mon Apr 25 09:25:26 2016 -0700
@@ -267,7 +267,7 @@
     LDFLAGS_windows := -export:JIMAGE_Open -export:JIMAGE_Close \
         -export:JIMAGE_PackageToModule \
         -export:JIMAGE_FindResource -export:JIMAGE_GetResource \
-        -export:JIMAGE_ResourceIterator, \
+        -export:JIMAGE_ResourceIterator -export:JIMAGE_ResourcePath, \
     LIBS_unix := -ljvm -ldl $(LIBCXX), \
     LIBS_solaris := -lc, \
     LIBS_macosx := -lc++, \
--- a/make/mapfiles/libjimage/mapfile-vers	Mon Apr 25 18:07:45 2016 +0300
+++ b/make/mapfiles/libjimage/mapfile-vers	Mon Apr 25 09:25:26 2016 -0700
@@ -34,6 +34,7 @@
         JIMAGE_FindResource;
         JIMAGE_GetResource;
         JIMAGE_ResourceIterator;
+        JIMAGE_ResourcePath;
     local:
         *;
 };
--- a/src/java.base/aix/native/libnet/aix_close.c	Mon Apr 25 18:07:45 2016 +0300
+++ b/src/java.base/aix/native/libnet/aix_close.c	Mon Apr 25 09:25:26 2016 -0700
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, SAP SE and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -50,6 +51,8 @@
    ...
 */
 
+#include <assert.h>
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <signal.h>
@@ -86,10 +89,35 @@
 static int sigWakeup = (SIGRTMAX - 1);
 
 /*
- * The fd table and the number of file descriptors
+ * fdTable holds one entry per file descriptor, up to a certain
+ * maximum.
+ * Theoretically, the number of possible file descriptors can get
+ * large, though usually it does not. Entries for small value file
+ * descriptors are kept in a simple table, which covers most scenarios.
+ * Entries for large value file descriptors are kept in an overflow
+ * table, which is organized as a sparse two dimensional array whose
+ * slabs are allocated on demand. This covers all corner cases while
+ * keeping memory consumption reasonable.
  */
-static fdEntry_t *fdTable = NULL;
-static int fdCount = 0;
+
+/* Base table for low value file descriptors */
+static fdEntry_t* fdTable = NULL;
+/* Maximum size of base table (in number of entries). */
+static const int fdTableMaxSize = 0x1000; /* 4K */
+/* Actual size of base table (in number of entries) */
+static int fdTableLen = 0;
+/* Max. theoretical number of file descriptors on system. */
+static int fdLimit = 0;
+
+/* Overflow table, should base table not be large enough. Organized as
+ *   an array of n slabs, each holding 64k entries.
+ */
+static fdEntry_t** fdOverflowTable = NULL;
+/* Number of slabs in the overflow table */
+static int fdOverflowTableLen = 0;
+/* Number of entries in one slab */
+static const int fdOverflowTableSlabSize = 0x10000; /* 64k */
+pthread_mutex_t fdOverflowTableLock = PTHREAD_MUTEX_INITIALIZER;
 
 /*
  * Null signal handler
@@ -108,42 +136,42 @@
     struct rlimit nbr_files;
     sigset_t sigset;
     struct sigaction sa;
+    int i = 0;
 
-    /* Check already initialized */
-    if (fdCount > 0 && fdTable != NULL) {
-        return;
-    }
-
-    /*
-     * Allocate table based on the maximum number of
-     * file descriptors.
-     */
+    /* Determine the maximum number of possible file descriptors. */
     if (-1 == getrlimit(RLIMIT_NOFILE, &nbr_files)) {
         fprintf(stderr, "library initialization failed - "
                 "unable to get max # of allocated fds\n");
         abort();
     }
-    fdCount = nbr_files.rlim_max;
-    /*
-     * We have a conceptual problem here, when the number of files is
-     * unlimited. As a kind of workaround, we ensure the table is big
-     * enough for handle even a large number of files. Since SAP itself
-     * recommends a limit of 32000 files, we just use 64000 as 'infinity'.
-     */
-    if (nbr_files.rlim_max == RLIM_INFINITY) {
-        fdCount = 64000;
+    if (nbr_files.rlim_max != RLIM_INFINITY) {
+        fdLimit = nbr_files.rlim_max;
+    } else {
+        /* We just do not know. */
+        fdLimit = INT_MAX;
     }
-    fdTable = (fdEntry_t *)calloc(fdCount, sizeof(fdEntry_t));
+
+    /* Allocate table for low value file descriptors. */
+    fdTableLen = fdLimit < fdTableMaxSize ? fdLimit : fdTableMaxSize;
+    fdTable = (fdEntry_t*) calloc(fdTableLen, sizeof(fdEntry_t));
     if (fdTable == NULL) {
         fprintf(stderr, "library initialization failed - "
                 "unable to allocate file descriptor table - out of memory");
         abort();
+    } else {
+        for (i = 0; i < fdTableLen; i ++) {
+            pthread_mutex_init(&fdTable[i].lock, NULL);
+        }
     }
 
-    {
-        int i;
-        for (i=0; i < fdCount; i++) {
-            pthread_mutex_init(&fdTable[i].lock, NULL);
+    /* Allocate overflow table, if needed */
+    if (fdLimit > fdTableMaxSize) {
+        fdOverflowTableLen = ((fdLimit - fdTableMaxSize) / fdOverflowTableSlabSize) + 1;
+        fdOverflowTable = (fdEntry_t**) calloc(fdOverflowTableLen, sizeof(fdEntry_t*));
+        if (fdOverflowTable == NULL) {
+            fprintf(stderr, "library initialization failed - "
+                    "unable to allocate file descriptor overflow table - out of memory");
+            abort();
         }
     }
 
@@ -161,17 +189,60 @@
 }
 
 /*
- * Return the fd table for this fd or NULL is fd out
- * of range.
+ * Return the fd table for this fd.
  */
 static inline fdEntry_t *getFdEntry(int fd)
 {
-    if (fd < 0 || fd >= fdCount) {
+    fdEntry_t* result = NULL;
+
+    if (fd < 0) {
         return NULL;
     }
-    return &fdTable[fd];
+
+    /* This should not happen. If it does, our assumption about
+     * max. fd value was wrong. */
+    assert(fd < fdLimit);
+
+    if (fd < fdTableMaxSize) {
+        /* fd is in base table. */
+        assert(fd < fdTableLen);
+        result = &fdTable[fd];
+    } else {
+        /* fd is in overflow table. */
+        const int indexInOverflowTable = fd - fdTableMaxSize;
+        const int rootindex = indexInOverflowTable / fdOverflowTableSlabSize;
+        const int slabindex = indexInOverflowTable % fdOverflowTableSlabSize;
+        fdEntry_t* slab = NULL;
+        assert(rootindex < fdOverflowTableLen);
+        assert(slabindex < fdOverflowTableSlabSize);
+        pthread_mutex_lock(&fdOverflowTableLock);
+        /* Allocate new slab in overflow table if needed */
+        if (fdOverflowTable[rootindex] == NULL) {
+            fdEntry_t* const newSlab =
+                (fdEntry_t*)calloc(fdOverflowTableSlabSize, sizeof(fdEntry_t));
+            if (newSlab == NULL) {
+                fprintf(stderr, "Unable to allocate file descriptor overflow"
+                        " table slab - out of memory");
+                pthread_mutex_unlock(&fdOverflowTableLock);
+                abort();
+            } else {
+                int i;
+                for (i = 0; i < fdOverflowTableSlabSize; i ++) {
+                    pthread_mutex_init(&newSlab[i].lock, NULL);
+                }
+                fdOverflowTable[rootindex] = newSlab;
+            }
+        }
+        pthread_mutex_unlock(&fdOverflowTableLock);
+        slab = fdOverflowTable[rootindex];
+        result = &slab[slabindex];
+    }
+
+    return result;
+
 }
 
+
 /*
  * Start a blocking operation :-
  *    Insert thread onto thread list for the fd.
--- a/src/java.base/linux/native/libnet/linux_close.c	Mon Apr 25 18:07:45 2016 +0300
+++ b/src/java.base/linux/native/libnet/linux_close.c	Mon Apr 25 09:25:26 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
  * 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,6 +23,8 @@
  * questions.
  */
 
+#include <assert.h>
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <signal.h>
@@ -59,10 +61,35 @@
 static int sigWakeup = (__SIGRTMAX - 2);
 
 /*
- * The fd table and the number of file descriptors
+ * fdTable holds one entry per file descriptor, up to a certain
+ * maximum.
+ * Theoretically, the number of possible file descriptors can get
+ * large, though usually it does not. Entries for small value file
+ * descriptors are kept in a simple table, which covers most scenarios.
+ * Entries for large value file descriptors are kept in an overflow
+ * table, which is organized as a sparse two dimensional array whose
+ * slabs are allocated on demand. This covers all corner cases while
+ * keeping memory consumption reasonable.
  */
-static fdEntry_t *fdTable;
-static int fdCount;
+
+/* Base table for low value file descriptors */
+static fdEntry_t* fdTable = NULL;
+/* Maximum size of base table (in number of entries). */
+static const int fdTableMaxSize = 0x1000; /* 4K */
+/* Actual size of base table (in number of entries) */
+static int fdTableLen = 0;
+/* Max. theoretical number of file descriptors on system. */
+static int fdLimit = 0;
+
+/* Overflow table, should base table not be large enough. Organized as
+ *   an array of n slabs, each holding 64k entries.
+ */
+static fdEntry_t** fdOverflowTable = NULL;
+/* Number of slabs in the overflow table */
+static int fdOverflowTableLen = 0;
+/* Number of entries in one slab */
+static const int fdOverflowTableSlabSize = 0x10000; /* 64k */
+pthread_mutex_t fdOverflowTableLock = PTHREAD_MUTEX_INITIALIZER;
 
 /*
  * Null signal handler
@@ -78,18 +105,43 @@
     struct rlimit nbr_files;
     sigset_t sigset;
     struct sigaction sa;
+    int i = 0;
 
-    /*
-     * Allocate table based on the maximum number of
-     * file descriptors.
-     */
-    getrlimit(RLIMIT_NOFILE, &nbr_files);
-    fdCount = nbr_files.rlim_max;
-    fdTable = (fdEntry_t *)calloc(fdCount, sizeof(fdEntry_t));
+    /* Determine the maximum number of possible file descriptors. */
+    if (-1 == getrlimit(RLIMIT_NOFILE, &nbr_files)) {
+        fprintf(stderr, "library initialization failed - "
+                "unable to get max # of allocated fds\n");
+        abort();
+    }
+    if (nbr_files.rlim_max != RLIM_INFINITY) {
+        fdLimit = nbr_files.rlim_max;
+    } else {
+        /* We just do not know. */
+        fdLimit = INT_MAX;
+    }
+
+    /* Allocate table for low value file descriptors. */
+    fdTableLen = fdLimit < fdTableMaxSize ? fdLimit : fdTableMaxSize;
+    fdTable = (fdEntry_t*) calloc(fdTableLen, sizeof(fdEntry_t));
     if (fdTable == NULL) {
         fprintf(stderr, "library initialization failed - "
                 "unable to allocate file descriptor table - out of memory");
         abort();
+    } else {
+        for (i = 0; i < fdTableLen; i ++) {
+            pthread_mutex_init(&fdTable[i].lock, NULL);
+        }
+    }
+
+    /* Allocate overflow table, if needed */
+    if (fdLimit > fdTableMaxSize) {
+        fdOverflowTableLen = ((fdLimit - fdTableMaxSize) / fdOverflowTableSlabSize) + 1;
+        fdOverflowTable = (fdEntry_t**) calloc(fdOverflowTableLen, sizeof(fdEntry_t*));
+        if (fdOverflowTable == NULL) {
+            fprintf(stderr, "library initialization failed - "
+                    "unable to allocate file descriptor overflow table - out of memory");
+            abort();
+        }
     }
 
     /*
@@ -106,15 +158,57 @@
 }
 
 /*
- * Return the fd table for this fd or NULL is fd out
- * of range.
+ * Return the fd table for this fd.
  */
 static inline fdEntry_t *getFdEntry(int fd)
 {
-    if (fd < 0 || fd >= fdCount) {
+    fdEntry_t* result = NULL;
+
+    if (fd < 0) {
         return NULL;
     }
-    return &fdTable[fd];
+
+    /* This should not happen. If it does, our assumption about
+     * max. fd value was wrong. */
+    assert(fd < fdLimit);
+
+    if (fd < fdTableMaxSize) {
+        /* fd is in base table. */
+        assert(fd < fdTableLen);
+        result = &fdTable[fd];
+    } else {
+        /* fd is in overflow table. */
+        const int indexInOverflowTable = fd - fdTableMaxSize;
+        const int rootindex = indexInOverflowTable / fdOverflowTableSlabSize;
+        const int slabindex = indexInOverflowTable % fdOverflowTableSlabSize;
+        fdEntry_t* slab = NULL;
+        assert(rootindex < fdOverflowTableLen);
+        assert(slabindex < fdOverflowTableSlabSize);
+        pthread_mutex_lock(&fdOverflowTableLock);
+        /* Allocate new slab in overflow table if needed */
+        if (fdOverflowTable[rootindex] == NULL) {
+            fdEntry_t* const newSlab =
+                (fdEntry_t*)calloc(fdOverflowTableSlabSize, sizeof(fdEntry_t));
+            if (newSlab == NULL) {
+                fprintf(stderr, "Unable to allocate file descriptor overflow"
+                        " table slab - out of memory");
+                pthread_mutex_unlock(&fdOverflowTableLock);
+                abort();
+            } else {
+                int i;
+                for (i = 0; i < fdOverflowTableSlabSize; i ++) {
+                    pthread_mutex_init(&newSlab[i].lock, NULL);
+                }
+                fdOverflowTable[rootindex] = newSlab;
+            }
+        }
+        pthread_mutex_unlock(&fdOverflowTableLock);
+        slab = fdOverflowTable[rootindex];
+        result = &slab[slabindex];
+    }
+
+    return result;
+
 }
 
 /*
--- a/src/java.base/macosx/native/libnet/bsd_close.c	Mon Apr 25 18:07:45 2016 +0300
+++ b/src/java.base/macosx/native/libnet/bsd_close.c	Mon Apr 25 09:25:26 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
  * 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,6 +23,8 @@
  * questions.
  */
 
+#include <assert.h>
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/param.h>
@@ -61,18 +63,35 @@
 static int sigWakeup = SIGIO;
 
 /*
- * The fd table and the number of file descriptors
+ * fdTable holds one entry per file descriptor, up to a certain
+ * maximum.
+ * Theoretically, the number of possible file descriptors can get
+ * large, though usually it does not. Entries for small value file
+ * descriptors are kept in a simple table, which covers most scenarios.
+ * Entries for large value file descriptors are kept in an overflow
+ * table, which is organized as a sparse two dimensional array whose
+ * slabs are allocated on demand. This covers all corner cases while
+ * keeping memory consumption reasonable.
  */
-static fdEntry_t *fdTable;
-static int fdCount;
 
-/*
- * This limit applies if getlimit() returns unlimited.
- * Unfortunately, this means if someone wants a higher limit
- * then they have to set an explicit limit, higher than this,
- * which is probably counter-intuitive.
+/* Base table for low value file descriptors */
+static fdEntry_t* fdTable = NULL;
+/* Maximum size of base table (in number of entries). */
+static const int fdTableMaxSize = 0x1000; /* 4K */
+/* Actual size of base table (in number of entries) */
+static int fdTableLen = 0;
+/* Max. theoretical number of file descriptors on system. */
+static int fdLimit = 0;
+
+/* Overflow table, should base table not be large enough. Organized as
+ *   an array of n slabs, each holding 64k entries.
  */
-#define MAX_FD_COUNT 4096
+static fdEntry_t** fdOverflowTable = NULL;
+/* Number of slabs in the overflow table */
+static int fdOverflowTableLen = 0;
+/* Number of entries in one slab */
+static const int fdOverflowTableSlabSize = 0x10000; /* 64k */
+pthread_mutex_t fdOverflowTableLock = PTHREAD_MUTEX_INITIALIZER;
 
 /*
  * Null signal handler
@@ -88,26 +107,43 @@
     struct rlimit nbr_files;
     sigset_t sigset;
     struct sigaction sa;
-    int i;
+    int i = 0;
 
-    /*
-     * Allocate table based on the maximum number of
-     * file descriptors.
-     */
-    getrlimit(RLIMIT_NOFILE, &nbr_files);
-    if (nbr_files.rlim_max == RLIM_INFINITY) {
-        fdCount = MAX_FD_COUNT;
+    /* Determine the maximum number of possible file descriptors. */
+    if (-1 == getrlimit(RLIMIT_NOFILE, &nbr_files)) {
+        fprintf(stderr, "library initialization failed - "
+                "unable to get max # of allocated fds\n");
+        abort();
+    }
+    if (nbr_files.rlim_max != RLIM_INFINITY) {
+        fdLimit = nbr_files.rlim_max;
     } else {
-        fdCount = nbr_files.rlim_max;
+        /* We just do not know. */
+        fdLimit = INT_MAX;
     }
-    fdTable = (fdEntry_t *)calloc(fdCount, sizeof(fdEntry_t));
+
+    /* Allocate table for low value file descriptors. */
+    fdTableLen = fdLimit < fdTableMaxSize ? fdLimit : fdTableMaxSize;
+    fdTable = (fdEntry_t*) calloc(fdTableLen, sizeof(fdEntry_t));
     if (fdTable == NULL) {
         fprintf(stderr, "library initialization failed - "
                 "unable to allocate file descriptor table - out of memory");
         abort();
+    } else {
+        for (i = 0; i < fdTableLen; i ++) {
+            pthread_mutex_init(&fdTable[i].lock, NULL);
+        }
     }
-    for (i=0; i<fdCount; i++) {
-        pthread_mutex_init(&fdTable[i].lock, NULL);
+
+    /* Allocate overflow table, if needed */
+    if (fdLimit > fdTableMaxSize) {
+        fdOverflowTableLen = ((fdLimit - fdTableMaxSize) / fdOverflowTableSlabSize) + 1;
+        fdOverflowTable = (fdEntry_t**) calloc(fdOverflowTableLen, sizeof(fdEntry_t*));
+        if (fdOverflowTable == NULL) {
+            fprintf(stderr, "library initialization failed - "
+                    "unable to allocate file descriptor overflow table - out of memory");
+            abort();
+        }
     }
 
     /*
@@ -124,17 +160,60 @@
 }
 
 /*
- * Return the fd table for this fd or NULL is fd out
- * of range.
+ * Return the fd table for this fd.
  */
 static inline fdEntry_t *getFdEntry(int fd)
 {
-    if (fd < 0 || fd >= fdCount) {
+    fdEntry_t* result = NULL;
+
+    if (fd < 0) {
         return NULL;
     }
-    return &fdTable[fd];
+
+    /* This should not happen. If it does, our assumption about
+     * max. fd value was wrong. */
+    assert(fd < fdLimit);
+
+    if (fd < fdTableMaxSize) {
+        /* fd is in base table. */
+        assert(fd < fdTableLen);
+        result = &fdTable[fd];
+    } else {
+        /* fd is in overflow table. */
+        const int indexInOverflowTable = fd - fdTableMaxSize;
+        const int rootindex = indexInOverflowTable / fdOverflowTableSlabSize;
+        const int slabindex = indexInOverflowTable % fdOverflowTableSlabSize;
+        fdEntry_t* slab = NULL;
+        assert(rootindex < fdOverflowTableLen);
+        assert(slabindex < fdOverflowTableSlabSize);
+        pthread_mutex_lock(&fdOverflowTableLock);
+        /* Allocate new slab in overflow table if needed */
+        if (fdOverflowTable[rootindex] == NULL) {
+            fdEntry_t* const newSlab =
+                (fdEntry_t*)calloc(fdOverflowTableSlabSize, sizeof(fdEntry_t));
+            if (newSlab == NULL) {
+                fprintf(stderr, "Unable to allocate file descriptor overflow"
+                        " table slab - out of memory");
+                pthread_mutex_unlock(&fdOverflowTableLock);
+                abort();
+            } else {
+                int i;
+                for (i = 0; i < fdOverflowTableSlabSize; i ++) {
+                    pthread_mutex_init(&newSlab[i].lock, NULL);
+                }
+                fdOverflowTable[rootindex] = newSlab;
+            }
+        }
+        pthread_mutex_unlock(&fdOverflowTableLock);
+        slab = fdOverflowTable[rootindex];
+        result = &slab[slabindex];
+    }
+
+    return result;
+
 }
 
+
 /*
  * Start a blocking operation :-
  *    Insert thread onto thread list for the fd.
--- a/src/java.base/share/classes/java/lang/Runtime.java	Mon Apr 25 18:07:45 2016 +0300
+++ b/src/java.base/share/classes/java/lang/Runtime.java	Mon Apr 25 09:25:26 2016 -0700
@@ -718,41 +718,27 @@
     }
 
     /**
-     * Enables/Disables tracing of instructions.
-     * If the {@code boolean} argument is {@code true}, this
-     * method suggests that the Java virtual machine emit debugging
-     * information for each instruction in the virtual machine as it
-     * is executed. The format of this information, and the file or other
-     * output stream to which it is emitted, depends on the host environment.
-     * The virtual machine may ignore this request if it does not support
-     * this feature. The destination of the trace output is system
-     * dependent.
-     * <p>
-     * If the {@code boolean} argument is {@code false}, this
-     * method causes the virtual machine to stop performing the
-     * detailed instruction trace it is performing.
+     * Not implemented, does nothing.
      *
-     * @param   on   {@code true} to enable instruction tracing;
-     *               {@code false} to disable this feature.
+     * @deprecated
+     * This method was intended to control instruction tracing.
+     * It has been superseded by JVM-specific tracing mechanisms.
+     *
+     * @param on ignored
      */
+    @Deprecated(since="9", forRemoval=true)
     public void traceInstructions(boolean on) { }
 
     /**
-     * Enables/Disables tracing of method calls.
-     * If the {@code boolean} argument is {@code true}, this
-     * method suggests that the Java virtual machine emit debugging
-     * information for each method in the virtual machine as it is
-     * called. The format of this information, and the file or other output
-     * stream to which it is emitted, depends on the host environment. The
-     * virtual machine may ignore this request if it does not support
-     * this feature.
-     * <p>
-     * Calling this method with argument false suggests that the
-     * virtual machine cease emitting per-call debugging information.
+     * Not implemented, does nothing.
      *
-     * @param   on   {@code true} to enable instruction tracing;
-     *               {@code false} to disable this feature.
+     * @deprecated
+     * This method was intended to control method call tracing.
+     * It has been superseded by JVM-specific tracing mechanisms.
+     *
+     * @param on ignored
      */
+    @Deprecated(since="9", forRemoval=true)
     public void traceMethodCalls(boolean on) { }
 
     /**
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Mon Apr 25 18:07:45 2016 +0300
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Mon Apr 25 09:25:26 2016 -0700
@@ -4476,12 +4476,24 @@
      * @since 9
      */
     public static MethodHandle countedLoop(MethodHandle start, MethodHandle end, MethodHandle init, MethodHandle body) {
-        MethodHandle returnVar = dropArguments(init == null || init.type().returnType() == void.class ?
-                zero(void.class) : identity(init.type().returnType()), 0, int.class, int.class);
+        Class<?> resultType;
+        MethodHandle actualInit;
+        if (init == null) {
+            resultType = body == null ? void.class : body.type().returnType();
+            actualInit = empty(methodType(resultType));
+        } else {
+            resultType = init.type().returnType();
+            actualInit = init;
+        }
+        MethodHandle defaultResultHandle = resultType == void.class ? zero(void.class) : identity(resultType);
+        MethodHandle actualBody = body == null ? dropArguments(defaultResultHandle, 0, int.class) : body;
+        MethodHandle returnVar = dropArguments(defaultResultHandle, 0, int.class, int.class);
+        MethodHandle actualEnd = end == null ? constant(int.class, 0) : end;
         MethodHandle[] indexVar = {start, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_countedLoopStep)};
-        MethodHandle[] loopLimit = {end, null, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_countedLoopPred), returnVar};
-        MethodHandle[] bodyClause = {init,
-                filterArgument(dropArguments(body, 1, int.class), 0,
+        MethodHandle[] loopLimit = {actualEnd, null,
+                MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_countedLoopPred), returnVar};
+        MethodHandle[] bodyClause = {actualInit,
+                filterArgument(dropArguments(actualBody, 1, int.class), 0,
                         MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_decrementCounter))};
         return loop(indexVar, loopLimit, bodyClause);
     }
@@ -4572,17 +4584,24 @@
      */
     public static MethodHandle iteratedLoop(MethodHandle iterator, MethodHandle init, MethodHandle body) {
         checkIteratedLoop(iterator, body);
-        final boolean voidInit = init == null || init.type().returnType() == void.class;
+        Class<?> resultType = init == null ?
+                body == null ? void.class : body.type().returnType() :
+                init.type().returnType();
+        boolean voidResult = resultType == void.class;
 
-        MethodHandle initit = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_initIterator);
-        MethodHandle initIterator = iterator == null ?
-                initit.asType(initit.type().changeParameterType(0, body.type().parameterType(voidInit ? 1 : 2))) :
-                iterator;
-        Class<?> itype = initIterator.type().returnType();
+        MethodHandle initIterator;
+        if (iterator == null) {
+            MethodHandle initit = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_initIterator);
+            initIterator = initit.asType(initit.type().changeParameterType(0,
+                    body.type().parameterType(voidResult ? 1 : 2)));
+        } else {
+            initIterator = iterator.asType(iterator.type().changeReturnType(Iterator.class));
+        }
+
         Class<?> ttype = body.type().parameterType(0);
 
         MethodHandle returnVar =
-                dropArguments(voidInit ? zero(void.class) : identity(init.type().returnType()), 0, itype);
+                dropArguments(voidResult ? zero(void.class) : identity(resultType), 0, Iterator.class);
         MethodHandle initnx = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_iterateNext);
         MethodHandle nextVal = initnx.asType(initnx.type().changeReturnType(ttype));
 
--- a/src/java.base/share/classes/java/time/format/DateTimeFormatter.java	Mon Apr 25 18:07:45 2016 +0300
+++ b/src/java.base/share/classes/java/time/format/DateTimeFormatter.java	Mon Apr 25 09:25:26 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -284,6 +284,7 @@
  *   D       day-of-year                 number            189
  *   M/L     month-of-year               number/text       7; 07; Jul; July; J
  *   d       day-of-month                number            10
+ *   g       modified-julian-day         number            2451334
  *
  *   Q/q     quarter-of-year             number/text       3; 03; Q3; 3rd quarter
  *   Y       week-based-year             year              1996; 96
@@ -308,10 +309,10 @@
  *
  *   V       time-zone ID                zone-id           America/Los_Angeles; Z; -08:30
  *   z       time-zone name              zone-name         Pacific Standard Time; PST
- *   O       localized zone-offset       offset-O          GMT+8; GMT+08:00; UTC-08:00;
- *   X       zone-offset 'Z' for zero    offset-X          Z; -08; -0830; -08:30; -083015; -08:30:15;
- *   x       zone-offset                 offset-x          +0000; -08; -0830; -08:30; -083015; -08:30:15;
- *   Z       zone-offset                 offset-Z          +0000; -0800; -08:00;
+ *   O       localized zone-offset       offset-O          GMT+8; GMT+08:00; UTC-08:00
+ *   X       zone-offset 'Z' for zero    offset-X          Z; -08; -0830; -08:30; -083015; -08:30:15
+ *   x       zone-offset                 offset-x          +0000; -08; -0830; -08:30; -083015; -08:30:15
+ *   Z       zone-offset                 offset-Z          +0000; -0800; -08:00
  *
  *   p       pad next                    pad modifier      1
  *
--- a/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java	Mon Apr 25 18:07:45 2016 +0300
+++ b/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java	Mon Apr 25 09:25:26 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
  * 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,6 +90,7 @@
 import java.time.format.DateTimeTextProvider.LocaleStore;
 import java.time.temporal.ChronoField;
 import java.time.temporal.IsoFields;
+import java.time.temporal.JulianFields;
 import java.time.temporal.TemporalAccessor;
 import java.time.temporal.TemporalField;
 import java.time.temporal.TemporalQueries;
@@ -666,8 +667,11 @@
      * No rounding occurs due to the maximum width - digits are simply dropped.
      * <p>
      * When parsing in strict mode, the number of parsed digits must be between
-     * the minimum and maximum width. When parsing in lenient mode, the minimum
-     * width is considered to be zero and the maximum is nine.
+     * the minimum and maximum width. In strict mode, if the minimum and maximum widths
+     * are equal and there is no decimal point then the parser will
+     * participate in adjacent value parsing, see
+     * {@link appendValue(java.time.temporal.TemporalField, int)}. When parsing in lenient mode,
+     * the minimum width is considered to be zero and the maximum is nine.
      * <p>
      * If the value cannot be obtained then an exception will be thrown.
      * If the value is negative an exception will be thrown.
@@ -686,7 +690,12 @@
      */
     public DateTimeFormatterBuilder appendFraction(
             TemporalField field, int minWidth, int maxWidth, boolean decimalPoint) {
-        appendInternal(new FractionPrinterParser(field, minWidth, maxWidth, decimalPoint));
+        if (minWidth == maxWidth && decimalPoint == false) {
+            // adjacent parsing
+            appendValue(new FractionPrinterParser(field, minWidth, maxWidth, decimalPoint));
+        } else {
+            appendInternal(new FractionPrinterParser(field, minWidth, maxWidth, decimalPoint));
+        }
         return this;
     }
 
@@ -1383,6 +1392,7 @@
      *   D       day-of-year                 number            189
      *   M/L     month-of-year               number/text       7; 07; Jul; July; J
      *   d       day-of-month                number            10
+     *   g       modified-julian-day         number            2451334
      *
      *   Q/q     quarter-of-year             number/text       3; 03; Q3; 3rd quarter
      *   Y       week-based-year             year              1996; 96
@@ -1408,9 +1418,9 @@
      *   V       time-zone ID                zone-id           America/Los_Angeles; Z; -08:30
      *   z       time-zone name              zone-name         Pacific Standard Time; PST
      *   O       localized zone-offset       offset-O          GMT+8; GMT+08:00; UTC-08:00;
-     *   X       zone-offset 'Z' for zero    offset-X          Z; -08; -0830; -08:30; -083015; -08:30:15;
-     *   x       zone-offset                 offset-x          +0000; -08; -0830; -08:30; -083015; -08:30:15;
-     *   Z       zone-offset                 offset-Z          +0000; -0800; -08:00;
+     *   X       zone-offset 'Z' for zero    offset-X          Z; -08; -0830; -08:30; -083015; -08:30:15
+     *   x       zone-offset                 offset-x          +0000; -08; -0830; -08:30; -083015; -08:30:15
+     *   Z       zone-offset                 offset-Z          +0000; -0800; -08:00
      *
      *   p       pad next                    pad modifier      1
      *
@@ -1437,37 +1447,37 @@
      *    GGGG    4      appendText(ChronoField.ERA, TextStyle.FULL)
      *    GGGGG   5      appendText(ChronoField.ERA, TextStyle.NARROW)
      *
-     *    u       1      appendValue(ChronoField.YEAR, 1, 19, SignStyle.NORMAL);
-     *    uu      2      appendValueReduced(ChronoField.YEAR, 2, 2000);
-     *    uuu     3      appendValue(ChronoField.YEAR, 3, 19, SignStyle.NORMAL);
-     *    u..u    4..n   appendValue(ChronoField.YEAR, n, 19, SignStyle.EXCEEDS_PAD);
-     *    y       1      appendValue(ChronoField.YEAR_OF_ERA, 1, 19, SignStyle.NORMAL);
-     *    yy      2      appendValueReduced(ChronoField.YEAR_OF_ERA, 2, 2000);
-     *    yyy     3      appendValue(ChronoField.YEAR_OF_ERA, 3, 19, SignStyle.NORMAL);
-     *    y..y    4..n   appendValue(ChronoField.YEAR_OF_ERA, n, 19, SignStyle.EXCEEDS_PAD);
+     *    u       1      appendValue(ChronoField.YEAR, 1, 19, SignStyle.NORMAL)
+     *    uu      2      appendValueReduced(ChronoField.YEAR, 2, 2000)
+     *    uuu     3      appendValue(ChronoField.YEAR, 3, 19, SignStyle.NORMAL)
+     *    u..u    4..n   appendValue(ChronoField.YEAR, n, 19, SignStyle.EXCEEDS_PAD)
+     *    y       1      appendValue(ChronoField.YEAR_OF_ERA, 1, 19, SignStyle.NORMAL)
+     *    yy      2      appendValueReduced(ChronoField.YEAR_OF_ERA, 2, 2000)
+     *    yyy     3      appendValue(ChronoField.YEAR_OF_ERA, 3, 19, SignStyle.NORMAL)
+     *    y..y    4..n   appendValue(ChronoField.YEAR_OF_ERA, n, 19, SignStyle.EXCEEDS_PAD)
      *    Y       1      append special localized WeekFields element for numeric week-based-year
-     *    YY      2      append special localized WeekFields element for reduced numeric week-based-year 2 digits;
-     *    YYY     3      append special localized WeekFields element for numeric week-based-year (3, 19, SignStyle.NORMAL);
-     *    Y..Y    4..n   append special localized WeekFields element for numeric week-based-year (n, 19, SignStyle.EXCEEDS_PAD);
+     *    YY      2      append special localized WeekFields element for reduced numeric week-based-year 2 digits
+     *    YYY     3      append special localized WeekFields element for numeric week-based-year (3, 19, SignStyle.NORMAL)
+     *    Y..Y    4..n   append special localized WeekFields element for numeric week-based-year (n, 19, SignStyle.EXCEEDS_PAD)
      *
-     *    Q       1      appendValue(IsoFields.QUARTER_OF_YEAR);
-     *    QQ      2      appendValue(IsoFields.QUARTER_OF_YEAR, 2);
+     *    Q       1      appendValue(IsoFields.QUARTER_OF_YEAR)
+     *    QQ      2      appendValue(IsoFields.QUARTER_OF_YEAR, 2)
      *    QQQ     3      appendText(IsoFields.QUARTER_OF_YEAR, TextStyle.SHORT)
      *    QQQQ    4      appendText(IsoFields.QUARTER_OF_YEAR, TextStyle.FULL)
      *    QQQQQ   5      appendText(IsoFields.QUARTER_OF_YEAR, TextStyle.NARROW)
-     *    q       1      appendValue(IsoFields.QUARTER_OF_YEAR);
-     *    qq      2      appendValue(IsoFields.QUARTER_OF_YEAR, 2);
+     *    q       1      appendValue(IsoFields.QUARTER_OF_YEAR)
+     *    qq      2      appendValue(IsoFields.QUARTER_OF_YEAR, 2)
      *    qqq     3      appendText(IsoFields.QUARTER_OF_YEAR, TextStyle.SHORT_STANDALONE)
      *    qqqq    4      appendText(IsoFields.QUARTER_OF_YEAR, TextStyle.FULL_STANDALONE)
      *    qqqqq   5      appendText(IsoFields.QUARTER_OF_YEAR, TextStyle.NARROW_STANDALONE)
      *
-     *    M       1      appendValue(ChronoField.MONTH_OF_YEAR);
-     *    MM      2      appendValue(ChronoField.MONTH_OF_YEAR, 2);
+     *    M       1      appendValue(ChronoField.MONTH_OF_YEAR)
+     *    MM      2      appendValue(ChronoField.MONTH_OF_YEAR, 2)
      *    MMM     3      appendText(ChronoField.MONTH_OF_YEAR, TextStyle.SHORT)
      *    MMMM    4      appendText(ChronoField.MONTH_OF_YEAR, TextStyle.FULL)
      *    MMMMM   5      appendText(ChronoField.MONTH_OF_YEAR, TextStyle.NARROW)
-     *    L       1      appendValue(ChronoField.MONTH_OF_YEAR);
-     *    LL      2      appendValue(ChronoField.MONTH_OF_YEAR, 2);
+     *    L       1      appendValue(ChronoField.MONTH_OF_YEAR)
+     *    LL      2      appendValue(ChronoField.MONTH_OF_YEAR, 2)
      *    LLL     3      appendText(ChronoField.MONTH_OF_YEAR, TextStyle.SHORT_STANDALONE)
      *    LLLL    4      appendText(ChronoField.MONTH_OF_YEAR, TextStyle.FULL_STANDALONE)
      *    LLLLL   5      appendText(ChronoField.MONTH_OF_YEAR, TextStyle.NARROW_STANDALONE)
@@ -1481,6 +1491,7 @@
      *    DD      2      appendValue(ChronoField.DAY_OF_YEAR, 2)
      *    DDD     3      appendValue(ChronoField.DAY_OF_YEAR, 3)
      *    F       1      appendValue(ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH)
+     *    g..g    1..n   appendValue(JulianFields.MODIFIED_JULIAN_DAY, n, 19, SignStyle.NORMAL)
      *    E       1      appendText(ChronoField.DAY_OF_WEEK, TextStyle.SHORT)
      *    EE      2      appendText(ChronoField.DAY_OF_WEEK, TextStyle.SHORT)
      *    EEE     3      appendText(ChronoField.DAY_OF_WEEK, TextStyle.SHORT)
@@ -1539,8 +1550,8 @@
      * <pre>
      *  Pattern  Count  Equivalent builder methods
      *  -------  -----  --------------------------
-     *    O       1      appendLocalizedOffsetPrefixed(TextStyle.SHORT);
-     *    OOOO    4      appendLocalizedOffsetPrefixed(TextStyle.FULL);
+     *    O       1      appendLocalizedOffset(TextStyle.SHORT)
+     *    OOOO    4      appendLocalizedOffset(TextStyle.FULL)
      *    X       1      appendOffset("+HHmm","Z")
      *    XX      2      appendOffset("+HHMM","Z")
      *    XXX     3      appendOffset("+HH:MM","Z")
@@ -1554,7 +1565,7 @@
      *    Z       1      appendOffset("+HHMM","+0000")
      *    ZZ      2      appendOffset("+HHMM","+0000")
      *    ZZZ     3      appendOffset("+HHMM","+0000")
-     *    ZZZZ    4      appendLocalizedOffset(TextStyle.FULL);
+     *    ZZZZ    4      appendLocalizedOffset(TextStyle.FULL)
      *    ZZZZZ   5      appendOffset("+HH:MM:ss","Z")
      * </pre>
      * <p>
@@ -1836,6 +1847,9 @@
                     throw new IllegalArgumentException("Too many pattern letters: " + cur);
                 }
                 break;
+            case 'g':
+                appendValue(field, count, 19, SignStyle.NORMAL);
+                break;
             default:
                 if (count == 1) {
                     appendValue(field);
@@ -1874,6 +1888,7 @@
         FIELD_MAP.put('A', ChronoField.MILLI_OF_DAY);              // LDML
         FIELD_MAP.put('n', ChronoField.NANO_OF_SECOND);            // 310 (proposed for LDML)
         FIELD_MAP.put('N', ChronoField.NANO_OF_DAY);               // 310 (proposed for LDML)
+        FIELD_MAP.put('g', JulianFields.MODIFIED_JULIAN_DAY);
         // 310 - z - time-zone names, matches LDML and SimpleDateFormat 1 to 4
         // 310 - Z - matches SimpleDateFormat and LDML
         // 310 - V - time-zone id, matches LDML
@@ -1884,7 +1899,6 @@
         // LDML - U - cycle year name, not supported by 310 yet
         // LDML - l - deprecated
         // LDML - j - not relevant
-        // LDML - g - modified-julian-day
         // LDML - v,V - extended time-zone names
     }
 
@@ -2919,11 +2933,8 @@
     /**
      * Prints and parses a numeric date-time field with optional padding.
      */
-    static final class FractionPrinterParser implements DateTimePrinterParser {
-        private final TemporalField field;
-        private final int minWidth;
-        private final int maxWidth;
-        private final boolean decimalPoint;
+    static final class FractionPrinterParser extends NumberPrinterParser {
+       private final boolean decimalPoint;
 
         /**
          * Constructor.
@@ -2934,6 +2945,7 @@
          * @param decimalPoint  whether to output the localized decimal point symbol
          */
         FractionPrinterParser(TemporalField field, int minWidth, int maxWidth, boolean decimalPoint) {
+            this(field, minWidth, maxWidth, decimalPoint, 0);
             Objects.requireNonNull(field, "field");
             if (field.range().isFixed() == false) {
                 throw new IllegalArgumentException("Field must have a fixed set of values: " + field);
@@ -2948,12 +2960,61 @@
                 throw new IllegalArgumentException("Maximum width must exceed or equal the minimum width but " +
                         maxWidth + " < " + minWidth);
             }
-            this.field = field;
-            this.minWidth = minWidth;
-            this.maxWidth = maxWidth;
+        }
+
+        /**
+         * Constructor.
+         *
+         * @param field  the field to output, not null
+         * @param minWidth  the minimum width to output, from 0 to 9
+         * @param maxWidth  the maximum width to output, from 0 to 9
+         * @param decimalPoint  whether to output the localized decimal point symbol
+         * @param subsequentWidth the subsequentWidth for this instance
+         */
+        FractionPrinterParser(TemporalField field, int minWidth, int maxWidth, boolean decimalPoint, int subsequentWidth) {
+            super(field, minWidth, maxWidth, SignStyle.NOT_NEGATIVE, subsequentWidth);
             this.decimalPoint = decimalPoint;
         }
 
+        /**
+         * Returns a new instance with fixed width flag set.
+         *
+         * @return a new updated printer-parser, not null
+         */
+        @Override
+        FractionPrinterParser withFixedWidth() {
+            if (subsequentWidth == -1) {
+                return this;
+            }
+            return new FractionPrinterParser(field, minWidth, maxWidth, decimalPoint, -1);
+        }
+
+        /**
+         * Returns a new instance with an updated subsequent width.
+         *
+         * @param subsequentWidth  the width of subsequent non-negative numbers, 0 or greater
+         * @return a new updated printer-parser, not null
+         */
+        @Override
+        FractionPrinterParser withSubsequentWidth(int subsequentWidth) {
+            return new FractionPrinterParser(field, minWidth, maxWidth, decimalPoint, this.subsequentWidth + subsequentWidth);
+        }
+
+        /**
+         * For FractionPrinterPrinterParser, the width is fixed if context is sttrict,
+         * minWidth equal to maxWidth and decimalpoint is absent.
+         * @param context the context
+         * @return if the field is fixed width
+         * @see DateTimeFormatterBuilder#appendValueFraction(java.time.temporal.TemporalField, int, int, boolean)
+         */
+        @Override
+        boolean isFixedWidth(DateTimeParseContext context) {
+            if (context.isStrict() && minWidth == maxWidth && decimalPoint == false) {
+                return true;
+            }
+            return false;
+        }
+
         @Override
         public boolean format(DateTimePrintContext context, StringBuilder buf) {
             Long value = context.getValue(field);
@@ -2986,8 +3047,8 @@
 
         @Override
         public int parse(DateTimeParseContext context, CharSequence text, int position) {
-            int effectiveMin = (context.isStrict() ? minWidth : 0);
-            int effectiveMax = (context.isStrict() ? maxWidth : 9);
+            int effectiveMin = (context.isStrict() || isFixedWidth(context) ? minWidth : 0);
+            int effectiveMax = (context.isStrict() || isFixedWidth(context) ? maxWidth : 9);
             int length = text.length();
             if (position == length) {
                 // valid if whole field is optional, invalid if minimum width
@@ -3519,9 +3580,7 @@
                 return false;
             }
             String gmtText = "GMT";  // TODO: get localized version of 'GMT'
-            if (gmtText != null) {
-                buf.append(gmtText);
-            }
+            buf.append(gmtText);
             int totalSecs = Math.toIntExact(offsetSecs);
             if (totalSecs != 0) {
                 int absHours = Math.abs((totalSecs / 3600) % 100);  // anything larger than 99 silently dropped
@@ -3565,14 +3624,12 @@
         @Override
         public int parse(DateTimeParseContext context, CharSequence text, int position) {
             int pos = position;
-            int end = pos + text.length();
+            int end = text.length();
             String gmtText = "GMT";  // TODO: get localized version of 'GMT'
-            if (gmtText != null) {
-                if (!context.subSequenceEquals(text, pos, gmtText, 0, gmtText.length())) {
+            if (!context.subSequenceEquals(text, pos, gmtText, 0, gmtText.length())) {
                     return ~position;
                 }
-                pos += gmtText.length();
-            }
+            pos += gmtText.length();
             // parse normal plus/minus offset
             int negative = 0;
             if (pos == end) {
--- a/src/java.base/share/classes/java/time/temporal/JulianFields.java	Mon Apr 25 18:07:45 2016 +0300
+++ b/src/java.base/share/classes/java/time/temporal/JulianFields.java	Mon Apr 25 09:25:26 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -117,7 +117,13 @@
      *
      * <h3>Astronomical and Scientific Notes</h3>
      * The standard astronomical definition uses a fraction to indicate the time-of-day,
-     * thus 3.25 would represent the time 18:00, since days start at midday.
+     * where each day is counted from midday to midday. For example,
+     * a fraction of 0 represents midday, a fraction of 0.25
+     * represents 18:00, a fraction of 0.5 represents midnight and a fraction
+     * of 0.75 represents 06:00.
+     * <p>
+     * By contrast, this implementation has no fractional part, and counts
+     * days from midnight to midnight.
      * This implementation uses an integer and days starting at midnight.
      * The integer value for the Julian Day Number is the astronomical Julian Day value at midday
      * of the date in question.
--- a/src/java.base/share/classes/jdk/internal/jimage/BasicImageReader.java	Mon Apr 25 18:07:45 2016 +0300
+++ b/src/java.base/share/classes/jdk/internal/jimage/BasicImageReader.java	Mon Apr 25 09:25:26 2016 -0700
@@ -183,7 +183,9 @@
     }
 
     public static void releaseByteBuffer(ByteBuffer buffer) {
-        ImageBufferCache.releaseBuffer(buffer);
+        if (!MAP_ALL) {
+            ImageBufferCache.releaseBuffer(buffer);
+        }
     }
 
     public String getName() {
--- a/src/java.base/share/classes/jdk/internal/jimage/ImageReader.java	Mon Apr 25 18:07:45 2016 +0300
+++ b/src/java.base/share/classes/jdk/internal/jimage/ImageReader.java	Mon Apr 25 09:25:26 2016 -0700
@@ -25,6 +25,7 @@
 package jdk.internal.jimage;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.UncheckedIOException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
@@ -36,8 +37,11 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 import java.util.function.Consumer;
 
 /**
@@ -47,80 +51,486 @@
  * but also compiled and delivered as part of the jrtfs.jar to support access
  * to the jimage file provided by the shipped JDK by tools running on JDK 8.
  */
-public class ImageReader extends BasicImageReader {
+public final class ImageReader implements AutoCloseable {
+    private SharedImageReader reader;
 
-    private static final int SIZE_OF_OFFSET = 4;
-
-    // Map of files opened as LITTLE_ENDIAN
-    private static final HashMap<Path, ImageReader> OPEN_LE_FILES
-            = new HashMap<>();
-
-    // Map of files opened as BIG_ENDIAN
-    private static final HashMap<Path, ImageReader> OPEN_BE_FILES
-            = new HashMap<>();
-
-    private int openCount;
-
-    // attributes of the .jimage file. jimage file does not contain
-    // attributes for the individual resources (yet). We use attributes
-    // of the jimage file itself (creation, modification, access times).
-    // Iniitalized lazily, see {@link #imageFileAttributes()}.
-    private BasicFileAttributes imageFileAttributes;
-
-    // directory management implementation
-    private final HashMap<String, Node> nodes;
-    private volatile Directory rootDir;
-
-    private Directory packagesDir;
-    private Directory modulesDir;
-
-    private ImageReader(Path imagePath, ByteOrder byteOrder) throws IOException {
-        super(imagePath, byteOrder);
-        this.nodes = new HashMap<>();
+    private ImageReader(SharedImageReader reader) {
+        this.reader = reader;
     }
 
     public static ImageReader open(Path imagePath, ByteOrder byteOrder) throws IOException {
-        HashMap<Path, ImageReader> openFiles = getOpenFilesMap(byteOrder);
-        ImageReader reader;
-        synchronized (openFiles) {
-            reader = openFiles.get(imagePath);
-            if (reader == null) {
-                reader = new ImageReader(imagePath, byteOrder);
-                ImageReader existingReader = openFiles.putIfAbsent(imagePath, reader);
-                assert (existingReader == null);
-            }
-            reader.openCount++;
-        }
-        return reader;
+        return SharedImageReader.open(imagePath, byteOrder);
     }
 
-    private static HashMap<Path, ImageReader> getOpenFilesMap(ByteOrder byteOrder) {
-        return (byteOrder == ByteOrder.BIG_ENDIAN) ? OPEN_BE_FILES : OPEN_LE_FILES;
-    }
-
-    /**
-     * Opens the given file path as an image file, returning an {@code ImageReader}.
-     */
     public static ImageReader open(Path imagePath) throws IOException {
         return open(imagePath, ByteOrder.nativeOrder());
     }
 
-    private boolean canClose() {
-        HashMap<Path, ImageReader> openFiles = getOpenFilesMap(this.getByteOrder());
-        synchronized (openFiles) {
-            if (--this.openCount == 0) {
-                return openFiles.remove(this.getName(), this);
+    @Override
+    public void close() throws IOException {
+        if (reader == null) {
+            throw new IOException("image file already closed");
+        }
+
+        reader.close(this);
+        reader = null;
+    }
+
+    // directory management interface
+    public Directory getRootDirectory() throws IOException {
+        if (reader == null) {
+            throw new IOException("image file closed");
+        }
+        return reader.getRootDirectory();
+    }
+
+    public Node findNode(String name) throws IOException {
+        if (reader == null) {
+            throw new IOException("image file closed");
+        }
+        return reader.findNode(name);
+    }
+
+    public byte[] getResource(Node node) throws IOException {
+        if (reader == null) {
+            throw new IOException("image file closed");
+        }
+        return reader.getResource(node);
+    }
+
+    public byte[] getResource(Resource rs) throws IOException {
+        if (reader == null) {
+            throw new IOException("image file closed");
+        }
+        return reader.getResource(rs);
+    }
+
+    public ImageHeader getHeader() {
+        Objects.requireNonNull(reader, "image file closed");
+        return reader.getHeader();
+    }
+
+    public static void releaseByteBuffer(ByteBuffer buffer) {
+        BasicImageReader.releaseByteBuffer(buffer);
+    }
+
+    public String getName() {
+        Objects.requireNonNull(reader, "image file closed");
+        return reader.getName() ;
+    }
+
+    public ByteOrder getByteOrder() {
+        Objects.requireNonNull(reader, "image file closed");
+        return reader.getByteOrder();
+    }
+
+    public Path getImagePath() {
+        Objects.requireNonNull(reader, "image file closed");
+        return reader.getImagePath();
+    }
+
+    public ImageStringsReader getStrings() {
+        Objects.requireNonNull(reader, "image file closed");
+        return reader.getStrings();
+    }
+
+    public ImageLocation findLocation(String mn, String rn) {
+        Objects.requireNonNull(reader, "image file closed");
+        return reader.findLocation(mn, rn);
+    }
+
+    public ImageLocation findLocation(String name) {
+        Objects.requireNonNull(reader, "image file closed");
+        return reader.findLocation(name);
+    }
+
+    public String[] getEntryNames() {
+        Objects.requireNonNull(reader, "image file closed");
+        return reader.getEntryNames();
+    }
+
+    public long[] getAttributes(int offset) {
+        Objects.requireNonNull(reader, "image file closed");
+        return reader.getAttributes(offset);
+    }
+
+    public String getString(int offset) {
+        Objects.requireNonNull(reader, "image file closed");
+        return reader.getString(offset);
+    }
+
+    public byte[] getResource(String name) {
+        Objects.requireNonNull(reader, "image file closed");
+        return reader.getResource(name);
+    }
+
+    public byte[] getResource(ImageLocation loc) {
+        Objects.requireNonNull(reader, "image file closed");
+        return reader.getResource(loc);
+    }
+
+    public ByteBuffer getResourceBuffer(ImageLocation loc) {
+        Objects.requireNonNull(reader, "image file closed");
+        return reader.getResourceBuffer(loc);
+    }
+
+    public InputStream getResourceStream(ImageLocation loc) {
+        Objects.requireNonNull(reader, "image file closed");
+        return reader.getResourceStream(loc);
+    }
+
+    private final static class SharedImageReader extends BasicImageReader {
+        static final int SIZE_OF_OFFSET = Integer.BYTES;
+
+        static final Map<Path, SharedImageReader> OPEN_FILES = new HashMap<>();
+
+        // List of openers for this shared image.
+        final Set<ImageReader> openers;
+
+        // attributes of the .jimage file. jimage file does not contain
+        // attributes for the individual resources (yet). We use attributes
+        // of the jimage file itself (creation, modification, access times).
+        // Iniitalized lazily, see {@link #imageFileAttributes()}.
+        BasicFileAttributes imageFileAttributes;
+
+        // directory management implementation
+        final HashMap<String, Node> nodes;
+        volatile Directory rootDir;
+
+        Directory packagesDir;
+        Directory modulesDir;
+
+        private SharedImageReader(Path imagePath, ByteOrder byteOrder) throws IOException {
+            super(imagePath, byteOrder);
+            this.openers = new HashSet<>();
+            this.nodes = new HashMap<>();
+        }
+
+        public static ImageReader open(Path imagePath, ByteOrder byteOrder) throws IOException {
+            synchronized (OPEN_FILES) {
+                SharedImageReader reader = OPEN_FILES.get(imagePath);
+
+                if (reader == null) {
+                    // Will fail with an IOException if wrong byteOrder.
+                    reader =  new SharedImageReader(imagePath, byteOrder);
+                    OPEN_FILES.put(imagePath, reader);
+                } else if (reader.getByteOrder() != byteOrder) {
+                    throw new IOException("\"" + reader.getName() + "\" is not an image file");
+                }
+
+                ImageReader image = new ImageReader(reader);
+                reader.openers.add(image);
+
+                return image;
             }
         }
-        return false;
-    }
 
-    @Override
-    public void close() throws IOException {
-        if (canClose()) {
-            super.close();
-            clearNodes();
-       }
+        public void close(ImageReader image) throws IOException {
+            synchronized (OPEN_FILES) {
+                if (!openers.remove(image)) {
+                    throw new IOException("image file already closed");
+                }
+
+                if (openers.isEmpty()) {
+                    close();
+                    nodes.clear();
+                    rootDir = null;
+
+                    if (!OPEN_FILES.remove(this.getImagePath(), this)) {
+                        throw new IOException("image file not found in open list");
+                    }
+                }
+            }
+        }
+
+        void addOpener(ImageReader reader) {
+            synchronized (OPEN_FILES) {
+                openers.add(reader);
+            }
+        }
+
+        boolean removeOpener(ImageReader reader) {
+            synchronized (OPEN_FILES) {
+                return openers.remove(reader);
+            }
+        }
+
+        // directory management interface
+        Directory getRootDirectory() {
+            return buildRootDirectory();
+        }
+
+        /**
+         * Lazily build a node from a name.
+        */
+        synchronized Node buildNode(String name) {
+            Node n;
+            boolean isPackages = name.startsWith("/packages");
+            boolean isModules = !isPackages && name.startsWith("/modules");
+
+            if (!(isModules || isPackages)) {
+                return null;
+            }
+
+            ImageLocation loc = findLocation(name);
+
+            if (loc != null) { // A sub tree node
+                if (isPackages) {
+                    n = handlePackages(name, loc);
+                } else { // modules sub tree
+                    n = handleModulesSubTree(name, loc);
+                }
+            } else { // Asking for a resource? /modules/java.base/java/lang/Object.class
+                if (isModules) {
+                    n = handleResource(name);
+                } else {
+                    // Possibly ask for /packages/java.lang/java.base
+                    // although /packages/java.base not created
+                    n = handleModuleLink(name);
+                }
+            }
+            return n;
+        }
+
+        synchronized Directory buildRootDirectory() {
+            Directory root = rootDir; // volatile read
+            if (root != null) {
+                return root;
+            }
+
+            root = newDirectory(null, "/");
+            root.setIsRootDir();
+
+            // /packages dir
+            packagesDir = newDirectory(root, "/packages");
+            packagesDir.setIsPackagesDir();
+
+            // /modules dir
+            modulesDir = newDirectory(root, "/modules");
+            modulesDir.setIsModulesDir();
+
+            root.setCompleted(true);
+            return rootDir = root;
+        }
+
+        /**
+         * To visit sub tree resources.
+         */
+        interface LocationVisitor {
+            void visit(ImageLocation loc);
+        }
+
+        void visitLocation(ImageLocation loc, LocationVisitor visitor) {
+            byte[] offsets = getResource(loc);
+            ByteBuffer buffer = ByteBuffer.wrap(offsets);
+            buffer.order(getByteOrder());
+            IntBuffer intBuffer = buffer.asIntBuffer();
+            for (int i = 0; i < offsets.length / SIZE_OF_OFFSET; i++) {
+                int offset = intBuffer.get(i);
+                ImageLocation pkgLoc = getLocation(offset);
+                visitor.visit(pkgLoc);
+            }
+        }
+
+        void visitPackageLocation(ImageLocation loc) {
+            // Retrieve package name
+            String pkgName = getBaseExt(loc);
+            // Content is array of offsets in Strings table
+            byte[] stringsOffsets = getResource(loc);
+            ByteBuffer buffer = ByteBuffer.wrap(stringsOffsets);
+            buffer.order(getByteOrder());
+            IntBuffer intBuffer = buffer.asIntBuffer();
+            // For each module, create a link node.
+            for (int i = 0; i < stringsOffsets.length / SIZE_OF_OFFSET; i++) {
+                // skip empty state, useless.
+                intBuffer.get(i);
+                i++;
+                int offset = intBuffer.get(i);
+                String moduleName = getString(offset);
+                Node targetNode = findNode("/modules/" + moduleName);
+                if (targetNode != null) {
+                    String pkgDirName = packagesDir.getName() + "/" + pkgName;
+                    Directory pkgDir = (Directory) nodes.get(pkgDirName);
+                    newLinkNode(pkgDir, pkgDir.getName() + "/" + moduleName, targetNode);
+                }
+            }
+        }
+
+        Node handlePackages(String name, ImageLocation loc) {
+            long size = loc.getUncompressedSize();
+            Node n = null;
+            // Only possiblities are /packages, /packages/package/module
+            if (name.equals("/packages")) {
+                visitLocation(loc, (childloc) -> {
+                    findNode(childloc.getFullName());
+                });
+                packagesDir.setCompleted(true);
+                n = packagesDir;
+            } else {
+                if (size != 0) { // children are offsets to module in StringsTable
+                    String pkgName = getBaseExt(loc);
+                    Directory pkgDir = newDirectory(packagesDir, packagesDir.getName() + "/" + pkgName);
+                    visitPackageLocation(loc);
+                    pkgDir.setCompleted(true);
+                    n = pkgDir;
+                } else { // Link to module
+                    String pkgName = loc.getParent();
+                    String modName = getBaseExt(loc);
+                    Node targetNode = findNode("/modules/" + modName);
+                    if (targetNode != null) {
+                        String pkgDirName = packagesDir.getName() + "/" + pkgName;
+                        Directory pkgDir = (Directory) nodes.get(pkgDirName);
+                        Node linkNode = newLinkNode(pkgDir, pkgDir.getName() + "/" + modName, targetNode);
+                        n = linkNode;
+                    }
+                }
+            }
+            return n;
+        }
+
+        // Asking for /packages/package/module although
+        // /packages/<pkg>/ not yet created, need to create it
+        // prior to return the link to module node.
+        Node handleModuleLink(String name) {
+            // eg: unresolved /packages/package/module
+            // Build /packages/package node
+            Node ret = null;
+            String radical = "/packages/";
+            String path = name;
+            if (path.startsWith(radical)) {
+                int start = radical.length();
+                int pkgEnd = path.indexOf('/', start);
+                if (pkgEnd != -1) {
+                    String pkg = path.substring(start, pkgEnd);
+                    String pkgPath = radical + pkg;
+                    Node n = findNode(pkgPath);
+                    // If not found means that this is a symbolic link such as:
+                    // /packages/java.util/java.base/java/util/Vector.class
+                    // and will be done by a retry of the filesystem
+                    for (Node child : n.getChildren()) {
+                        if (child.name.equals(name)) {
+                            ret = child;
+                            break;
+                        }
+                    }
+                }
+            }
+            return ret;
+        }
+
+        Node handleModulesSubTree(String name, ImageLocation loc) {
+            Node n;
+            assert (name.equals(loc.getFullName()));
+            Directory dir = makeDirectories(name);
+            visitLocation(loc, (childloc) -> {
+                String path = childloc.getFullName();
+                if (path.startsWith("/modules")) { // a package
+                    makeDirectories(path);
+                } else { // a resource
+                    makeDirectories(childloc.buildName(true, true, false));
+                    newResource(dir, childloc);
+                }
+            });
+            dir.setCompleted(true);
+            n = dir;
+            return n;
+        }
+
+        Node handleResource(String name) {
+            Node n = null;
+            String locationPath = name.substring("/modules".length());
+            ImageLocation resourceLoc = findLocation(locationPath);
+            if (resourceLoc != null) {
+                Directory dir = makeDirectories(resourceLoc.buildName(true, true, false));
+                Resource res = newResource(dir, resourceLoc);
+                n = res;
+            }
+            return n;
+        }
+
+        String getBaseExt(ImageLocation loc) {
+            String base = loc.getBase();
+            String ext = loc.getExtension();
+            if (ext != null && !ext.isEmpty()) {
+                base = base + "." + ext;
+            }
+            return base;
+        }
+
+        synchronized Node findNode(String name) {
+            buildRootDirectory();
+            Node n = nodes.get(name);
+            if (n == null || !n.isCompleted()) {
+                n = buildNode(name);
+            }
+            return n;
+        }
+
+        /**
+         * Returns the file attributes of the image file.
+         */
+        BasicFileAttributes imageFileAttributes() {
+            BasicFileAttributes attrs = imageFileAttributes;
+            if (attrs == null) {
+                try {
+                    Path file = getImagePath();
+                    attrs = Files.readAttributes(file, BasicFileAttributes.class);
+                } catch (IOException ioe) {
+                    throw new UncheckedIOException(ioe);
+                }
+                imageFileAttributes = attrs;
+            }
+            return attrs;
+        }
+
+        Directory newDirectory(Directory parent, String name) {
+            Directory dir = Directory.create(parent, name, imageFileAttributes());
+            nodes.put(dir.getName(), dir);
+            return dir;
+        }
+
+        Resource newResource(Directory parent, ImageLocation loc) {
+            Resource res = Resource.create(parent, loc, imageFileAttributes());
+            nodes.put(res.getName(), res);
+            return res;
+        }
+
+        LinkNode newLinkNode(Directory dir, String name, Node link) {
+            LinkNode linkNode = LinkNode.create(dir, name, link);
+            nodes.put(linkNode.getName(), linkNode);
+            return linkNode;
+        }
+
+        Directory makeDirectories(String parent) {
+            Directory last = rootDir;
+            for (int offset = parent.indexOf('/', 1);
+                    offset != -1;
+                    offset = parent.indexOf('/', offset + 1)) {
+                String dir = parent.substring(0, offset);
+                last = makeDirectory(dir, last);
+            }
+            return makeDirectory(parent, last);
+
+        }
+
+        Directory makeDirectory(String dir, Directory last) {
+            Directory nextDir = (Directory) nodes.get(dir);
+            if (nextDir == null) {
+                nextDir = newDirectory(last, dir);
+            }
+            return nextDir;
+        }
+
+        byte[] getResource(Node node) throws IOException {
+            if (node.isResource()) {
+                return super.getResource(node.getLocation());
+            }
+            throw new IOException("Not a resource: " + node);
+        }
+
+        byte[] getResource(Resource rs) throws IOException {
+            return super.getResource(rs.getLocation());
+        }
     }
 
     // jimage file does not store directory structure. We build nodes
@@ -389,7 +799,7 @@
 
         @Override
         public Node resolveLink(boolean recursive) {
-            return recursive && (link instanceof LinkNode)? ((LinkNode)link).resolveLink(true) : link;
+            return (recursive && link instanceof LinkNode) ? ((LinkNode)link).resolveLink(true) : link;
         }
 
         @Override
@@ -397,297 +807,4 @@
             return true;
         }
     }
-
-    // directory management interface
-    public Directory getRootDirectory() {
-        return buildRootDirectory();
-    }
-
-    /**
-     * To visit sub tree resources.
-     */
-    interface LocationVisitor {
-
-        void visit(ImageLocation loc);
-    }
-
-    /**
-     * Lazily build a node from a name.
-    */
-    private Node buildNode(String name) {
-        Node n;
-        boolean isPackages = name.startsWith("/packages");
-        boolean isModules = !isPackages && name.startsWith("/modules");
-
-        if (!(isModules || isPackages)) {
-            return null;
-        }
-
-        ImageLocation loc = findLocation(name);
-
-        if (loc != null) { // A sub tree node
-            if (isPackages) {
-                n = handlePackages(name, loc);
-            } else { // modules sub tree
-                n = handleModulesSubTree(name, loc);
-            }
-        } else { // Asking for a resource? /modules/java.base/java/lang/Object.class
-            if (isModules) {
-                n = handleResource(name);
-            } else {
-                // Possibly ask for /packages/java.lang/java.base
-                // although /packages/java.base not created
-                n = handleModuleLink(name);
-            }
-        }
-        return n;
-    }
-
-    private void visitLocation(ImageLocation loc, LocationVisitor visitor) {
-        byte[] offsets = getResource(loc);
-        ByteBuffer buffer = ByteBuffer.wrap(offsets);
-        buffer.order(getByteOrder());
-        IntBuffer intBuffer = buffer.asIntBuffer();
-        for (int i = 0; i < offsets.length / SIZE_OF_OFFSET; i++) {
-            int offset = intBuffer.get(i);
-            ImageLocation pkgLoc = getLocation(offset);
-            visitor.visit(pkgLoc);
-        }
-    }
-
-    private void visitPackageLocation(ImageLocation loc) {
-        // Retrieve package name
-        String pkgName = getBaseExt(loc);
-        // Content is array of offsets in Strings table
-        byte[] stringsOffsets = getResource(loc);
-        ByteBuffer buffer = ByteBuffer.wrap(stringsOffsets);
-        buffer.order(getByteOrder());
-        IntBuffer intBuffer = buffer.asIntBuffer();
-        // For each module, create a link node.
-        for (int i = 0; i < stringsOffsets.length / SIZE_OF_OFFSET; i++) {
-            // skip empty state, useless.
-            intBuffer.get(i);
-            i++;
-            int offset = intBuffer.get(i);
-            String moduleName = getString(offset);
-            Node targetNode = findNode("/modules/" + moduleName);
-            if (targetNode != null) {
-                String pkgDirName = packagesDir.getName() + "/" + pkgName;
-                Directory pkgDir = (Directory) nodes.get(pkgDirName);
-                newLinkNode(pkgDir, pkgDir.getName() + "/" + moduleName, targetNode);
-            }
-        }
-    }
-
-    private Node handlePackages(String name, ImageLocation loc) {
-        long size = loc.getUncompressedSize();
-        Node n = null;
-        // Only possiblities are /packages, /packages/package/module
-        if (name.equals("/packages")) {
-            visitLocation(loc, (childloc) -> {
-                findNode(childloc.getFullName());
-            });
-            packagesDir.setCompleted(true);
-            n = packagesDir;
-        } else {
-            if (size != 0) { // children are offsets to module in StringsTable
-                String pkgName = getBaseExt(loc);
-                Directory pkgDir = newDirectory(packagesDir, packagesDir.getName() + "/" + pkgName);
-                visitPackageLocation(loc);
-                pkgDir.setCompleted(true);
-                n = pkgDir;
-            } else { // Link to module
-                String pkgName = loc.getParent();
-                String modName = getBaseExt(loc);
-                Node targetNode = findNode("/modules/" + modName);
-                if (targetNode != null) {
-                    String pkgDirName = packagesDir.getName() + "/" + pkgName;
-                    Directory pkgDir = (Directory) nodes.get(pkgDirName);
-                    Node linkNode = newLinkNode(pkgDir, pkgDir.getName() + "/" + modName, targetNode);
-                    n = linkNode;
-                }
-            }
-        }
-        return n;
-    }
-
-    // Asking for /packages/package/module although
-    // /packages/<pkg>/ not yet created, need to create it
-    // prior to return the link to module node.
-    private Node handleModuleLink(String name) {
-        // eg: unresolved /packages/package/module
-        // Build /packages/package node
-        Node ret = null;
-        String radical = "/packages/";
-        String path = name;
-        if (path.startsWith(radical)) {
-            int start = radical.length();
-            int pkgEnd = path.indexOf('/', start);
-            if (pkgEnd != -1) {
-                String pkg = path.substring(start, pkgEnd);
-                String pkgPath = radical + pkg;
-                Node n = findNode(pkgPath);
-                // If not found means that this is a symbolic link such as:
-                // /packages/java.util/java.base/java/util/Vector.class
-                // and will be done by a retry of the filesystem
-                for (Node child : n.getChildren()) {
-                    if (child.name.equals(name)) {
-                        ret = child;
-                        break;
-                    }
-                }
-            }
-        }
-        return ret;
-    }
-
-    private Node handleModulesSubTree(String name, ImageLocation loc) {
-        Node n;
-        assert (name.equals(loc.getFullName()));
-        Directory dir = makeDirectories(name);
-        visitLocation(loc, (childloc) -> {
-            String path = childloc.getFullName();
-            if (path.startsWith("/modules")) { // a package
-                makeDirectories(path);
-            } else { // a resource
-                makeDirectories(childloc.buildName(true, true, false));
-                newResource(dir, childloc);
-            }
-        });
-        dir.setCompleted(true);
-        n = dir;
-        return n;
-    }
-
-    private Node handleResource(String name) {
-        Node n = null;
-        String locationPath = name.substring("/modules".length());
-        ImageLocation resourceLoc = findLocation(locationPath);
-        if (resourceLoc != null) {
-            Directory dir = makeDirectories(resourceLoc.buildName(true, true, false));
-            Resource res = newResource(dir, resourceLoc);
-            n = res;
-        }
-        return n;
-    }
-
-    private String getBaseExt(ImageLocation loc) {
-        String base = loc.getBase();
-        String ext = loc.getExtension();
-        if (ext != null && !ext.isEmpty()) {
-            base = base + "." + ext;
-        }
-        return base;
-    }
-
-    public synchronized Node findNode(String name) {
-        buildRootDirectory();
-        Node n = nodes.get(name);
-        if (n == null || !n.isCompleted()) {
-            n = buildNode(name);
-        }
-        return n;
-    }
-
-    private synchronized void clearNodes() {
-        nodes.clear();
-        rootDir = null;
-    }
-
-    /**
-     * Returns the file attributes of the image file.
-     */
-    private BasicFileAttributes imageFileAttributes() {
-        BasicFileAttributes attrs = imageFileAttributes;
-        if (attrs == null) {
-            try {
-                Path file = getImagePath();
-                attrs = Files.readAttributes(file, BasicFileAttributes.class);
-            } catch (IOException ioe) {
-                throw new UncheckedIOException(ioe);
-            }
-            imageFileAttributes = attrs;
-        }
-        return attrs;
-    }
-
-    private Directory buildRootDirectory() {
-        Directory root = rootDir; // volatile read
-        if (root != null) {
-            return root;
-        }
-
-        synchronized (this) {
-            root = rootDir;
-            if (root != null) {
-                return root;
-            }
-
-            // FIXME no time information per resource in jimage file (yet?)
-            // we use file attributes of jimage itself.
-            // root directory
-            root = newDirectory(null, "/");
-            root.setIsRootDir();
-
-            // /packages dir
-            packagesDir = newDirectory(root, "/packages");
-            packagesDir.setIsPackagesDir();
-
-            // /modules dir
-            modulesDir = newDirectory(root, "/modules");
-            modulesDir.setIsModulesDir();
-
-            root.setCompleted(true);
-            return rootDir = root;
-        }
-    }
-
-    private Directory newDirectory(Directory parent, String name) {
-        Directory dir = Directory.create(parent, name, imageFileAttributes());
-        nodes.put(dir.getName(), dir);
-        return dir;
-    }
-
-    private Resource newResource(Directory parent, ImageLocation loc) {
-        Resource res = Resource.create(parent, loc, imageFileAttributes());
-        nodes.put(res.getName(), res);
-        return res;
-    }
-
-    private LinkNode newLinkNode(Directory dir, String name, Node link) {
-        LinkNode linkNode = LinkNode.create(dir, name, link);
-        nodes.put(linkNode.getName(), linkNode);
-        return linkNode;
-    }
-
-    private Directory makeDirectories(String parent) {
-        Directory last = rootDir;
-        for (int offset = parent.indexOf('/', 1);
-                offset != -1;
-                offset = parent.indexOf('/', offset + 1)) {
-            String dir = parent.substring(0, offset);
-            last = makeDirectory(dir, last);
-        }
-        return makeDirectory(parent, last);
-
-    }
-
-    private Directory makeDirectory(String dir, Directory last) {
-        Directory nextDir = (Directory) nodes.get(dir);
-        if (nextDir == null) {
-            nextDir = newDirectory(last, dir);
-        }
-        return nextDir;
-    }
-
-    public byte[] getResource(Node node) throws IOException {
-        if (node.isResource()) {
-            return super.getResource(node.getLocation());
-        }
-        throw new IOException("Not a resource: " + node);
-    }
-
-    public byte[] getResource(Resource rs) throws IOException {
-        return super.getResource(rs.getLocation());
-    }
 }
--- a/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystem.java	Mon Apr 25 18:07:45 2016 +0300
+++ b/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystem.java	Mon Apr 25 09:25:26 2016 -0700
@@ -299,13 +299,9 @@
     }
 
     // clean up this file system - called from finalize and close
-    void cleanup() throws IOException {
-        if (!isOpen) {
-            return;
-        }
-        synchronized (this) {
+    synchronized void cleanup() throws IOException {
+        if (isOpen) {
             isOpen = false;
-            // close image reader and null out
             image.close();
             image = null;
         }
@@ -461,8 +457,8 @@
     private Node lookup(String path) {
         try {
             return image.findNode(path);
-        } catch (RuntimeException re) {
-            throw new InvalidPathException(path, re.toString());
+        } catch (RuntimeException | IOException ex) {
+            throw new InvalidPathException(path, ex.toString());
         }
     }
 
--- a/src/java.base/share/classes/jdk/internal/jrtfs/SystemImage.java	Mon Apr 25 18:07:45 2016 +0300
+++ b/src/java.base/share/classes/jdk/internal/jrtfs/SystemImage.java	Mon Apr 25 09:25:26 2016 -0700
@@ -49,7 +49,7 @@
  */
 abstract class SystemImage {
 
-    abstract Node findNode(String path);
+    abstract Node findNode(String path) throws IOException;
     abstract byte[] getResource(Node node) throws IOException;
     abstract void close() throws IOException;
 
@@ -60,7 +60,7 @@
             image.getRootDirectory();
             return new SystemImage() {
                 @Override
-                Node findNode(String path) {
+                Node findNode(String path) throws IOException {
                     return image.findNode(path);
                 }
                 @Override
--- a/src/java.base/share/classes/jdk/internal/loader/BootLoader.java	Mon Apr 25 18:07:45 2016 +0300
+++ b/src/java.base/share/classes/jdk/internal/loader/BootLoader.java	Mon Apr 25 09:25:26 2016 -0700
@@ -30,6 +30,7 @@
 import java.lang.reflect.Layer;
 import java.lang.reflect.Module;
 import java.net.MalformedURLException;
+import java.net.URI;
 import java.net.URL;
 import java.nio.file.Files;
 import java.nio.file.Path;
@@ -184,9 +185,9 @@
 
         /**
          * Define the {@code Package} with the given name. The specified
-         * location is a jrt URL to a named module in the run-time image, a
-         * file path to a module in an exploded run-time image, or the file
-         * path to an enty on the boot class path (java agent Boot-Class-Path
+         * location is a jrt URL to a named module in the run-time image,
+         * a file URL to a module in an exploded run-time image, or a file
+         * path to an entry on the boot class path (java agent Boot-Class-Path
          * or -Xbootclasspath/a.
          *
          * <p> If the given location is a JAR file containing a manifest,
@@ -194,7 +195,9 @@
          * the manifest, if present.
          *
          * @param name     package name
-         * @param location location where the package is (jrt URL or file path)
+         * @param location location where the package is (jrt URL or file URL
+         *                 for a named module in the run-time or exploded image;
+         *                 a file path for a package from -Xbootclasspath/a)
          */
         static Package definePackage(String name, String location) {
             Module module = findModule(location);
@@ -222,9 +225,9 @@
             if (location.startsWith("jrt:/")) {
                 // named module in runtime image ("jrt:/".length() == 5)
                 mn = location.substring(5, location.length());
-            } else {
+            } else if (location.startsWith("file:/")) {
                 // named module in exploded image
-                Path path = Paths.get(location);
+                Path path = Paths.get(URI.create(location));
                 Path modulesDir = Paths.get(JAVA_HOME, "modules");
                 if (path.startsWith(modulesDir)) {
                     mn = path.getFileName().toString();
--- a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java	Mon Apr 25 18:07:45 2016 +0300
+++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java	Mon Apr 25 09:25:26 2016 -0700
@@ -209,6 +209,12 @@
     Collection<SNIMatcher>      sniMatchers =
                                     Collections.<SNIMatcher>emptyList();
 
+    // Is the serverNames set to empty with SSLParameters.setServerNames()?
+    private boolean             noSniExtension = false;
+
+    // Is the sniMatchers set to empty with SSLParameters.setSNIMatchers()?
+    private boolean             noSniMatcher = false;
+
     // Configured application protocol values
     String[] applicationProtocols = new String[0];
 
@@ -642,6 +648,11 @@
         }
 
         super.connect(endpoint, timeout);
+
+        if (host == null || host.length() == 0) {
+            useImplicitHost(false);
+        }
+
         doneConnect();
     }
 
@@ -2098,41 +2109,62 @@
         outputRecord.setVersion(protocolVersion);
     }
 
+    //
+    // ONLY used by ClientHandshaker for the server hostname during handshaking
+    //
     synchronized String getHost() {
         // Note that the host may be null or empty for localhost.
         if (host == null || host.length() == 0) {
-            if (!trustNameService) {
-                // If the local name service is not trustworthy, reverse host
-                // name resolution should not be performed for endpoint
-                // identification.  Use the application original specified
-                // hostname or IP address instead.
-                host = getOriginalHostname(getInetAddress());
-            } else {
-                host = getInetAddress().getHostName();
-            }
+            useImplicitHost(true);
         }
 
         return host;
     }
 
     /*
-     * Get the original application specified hostname.
+     * Try to set and use the implicit specified hostname
      */
-    private static String getOriginalHostname(InetAddress inetAddress) {
-        /*
-         * Get the original hostname via jdk.internal.misc.SharedSecrets.
-         */
-        JavaNetInetAddressAccess jna = SharedSecrets.getJavaNetInetAddressAccess();
-        String originalHostname = jna.getOriginalHostName(inetAddress);
+    private synchronized void useImplicitHost(boolean noSniUpdate) {
 
-        /*
-         * If no application specified hostname, use the IP address.
-         */
-        if (originalHostname == null || originalHostname.length() == 0) {
-            originalHostname = inetAddress.getHostAddress();
+        // Note: If the local name service is not trustworthy, reverse
+        // host name resolution should not be performed for endpoint
+        // identification.  Use the application original specified
+        // hostname or IP address instead.
+
+        // Get the original hostname via jdk.internal.misc.SharedSecrets
+        InetAddress inetAddress = getInetAddress();
+        if (inetAddress == null) {      // not connected
+            return;
         }
 
-        return originalHostname;
+        JavaNetInetAddressAccess jna =
+                SharedSecrets.getJavaNetInetAddressAccess();
+        String originalHostname = jna.getOriginalHostName(inetAddress);
+        if ((originalHostname != null) &&
+                (originalHostname.length() != 0)) {
+
+            host = originalHostname;
+            if (!noSniUpdate && serverNames.isEmpty() && !noSniExtension) {
+                serverNames =
+                        Utilities.addToSNIServerNameList(serverNames, host);
+
+                if (!roleIsServer &&
+                        (handshaker != null) && !handshaker.started()) {
+                    handshaker.setSNIServerNames(serverNames);
+                }
+            }
+
+            return;
+        }
+
+        // No explicitly specified hostname, no server name indication.
+        if (!trustNameService) {
+            // The local name service is not trustworthy, use IP address.
+            host = inetAddress.getHostAddress();
+        } else {
+            // Use the underlying reverse host name resolution service.
+            host = getInetAddress().getHostName();
+        }
     }
 
     // ONLY used by HttpsClient to setup the URI specified hostname
@@ -2144,6 +2176,10 @@
         this.host = host;
         this.serverNames =
             Utilities.addToSNIServerNameList(this.serverNames, this.host);
+
+        if (!roleIsServer && (handshaker != null) && !handshaker.started()) {
+            handshaker.setSNIServerNames(serverNames);
+        }
     }
 
     /**
@@ -2533,8 +2569,21 @@
         // the super implementation does not handle the following parameters
         params.setEndpointIdentificationAlgorithm(identificationProtocol);
         params.setAlgorithmConstraints(algorithmConstraints);
-        params.setSNIMatchers(sniMatchers);
-        params.setServerNames(serverNames);
+
+        if (sniMatchers.isEmpty() && !noSniMatcher) {
+            // 'null' indicates none has been set
+            params.setSNIMatchers(null);
+        } else {
+            params.setSNIMatchers(sniMatchers);
+        }
+
+        if (serverNames.isEmpty() && !noSniExtension) {
+            // 'null' indicates none has been set
+            params.setServerNames(null);
+        } else {
+            params.setServerNames(serverNames);
+        }
+
         params.setUseCipherSuitesOrder(preferLocalCipherSuites);
         params.setMaximumPacketSize(maximumPacketSize);
         params.setApplicationProtocols(applicationProtocols);
@@ -2568,11 +2617,13 @@
 
         List<SNIServerName> sniNames = params.getServerNames();
         if (sniNames != null) {
+            noSniExtension = sniNames.isEmpty();
             serverNames = sniNames;
         }
 
         Collection<SNIMatcher> matchers = params.getSNIMatchers();
         if (matchers != null) {
+            noSniMatcher = matchers.isEmpty();
             sniMatchers = matchers;
         }
 
--- a/src/java.base/share/native/libjimage/jimage.cpp	Mon Apr 25 18:07:45 2016 +0300
+++ b/src/java.base/share/native/libjimage/jimage.cpp	Mon Apr 25 09:25:26 2016 -0700
@@ -207,7 +207,30 @@
         if (!(*visitor)(image, module, "9", parent, base, extension, arg)) {
             break;
         }
-
     }
 }
 
+/*
+ * JIMAGE_ResourcePath- Given an open image file, a location reference, a buffer
+ * and a maximum buffer size, copy the path of the resource into the buffer.
+ * Returns false if not a valid location reference.
+ *
+ * Ex.
+ *   JImageLocationRef location = ...
+ *   char path[JIMAGE_MAX_PATH];
+ *    (*JImageResourcePath)(image, location, path, JIMAGE_MAX_PATH);
+ */
+extern "C" bool JIMAGE_ResourcePath(JImageFile* image, JImageLocationRef locationRef,
+                                    char* path, size_t max) {
+    ImageFileReader* imageFile = (ImageFileReader*) image;
+
+    u4 offset = (u4) locationRef;
+    if (offset >= imageFile->locations_size()) {
+        return false;
+    }
+
+    ImageLocation location(imageFile->get_location_offset_data(offset));
+    imageFile->location_path(location, path, max);
+
+    return true;
+}
--- a/src/java.base/share/native/libjimage/jimage.hpp	Mon Apr 25 18:07:45 2016 +0300
+++ b/src/java.base/share/native/libjimage/jimage.hpp	Mon Apr 25 09:25:26 2016 -0700
@@ -37,11 +37,13 @@
 typedef jlong JImageLocationRef;
 
 // Max path length limit independent of platform.  Windows max path is 1024,
-// other platforms use 4096.  The JCK fails several tests when 1024 is used.
+// other platforms use 4096.
 #define JIMAGE_MAX_PATH 4096
 
 // JImage Error Codes
 
+// Resource was not found
+#define JIMAGE_NOT_FOUND (0)
 // The image file is not prefixed with 0xCAFEDADA
 #define JIMAGE_BAD_MAGIC (-1)
 // The image file does not have a compatible (translatable) version
@@ -184,3 +186,20 @@
 
 typedef void (*JImageResourceIterator_t)(JImageFile* jimage,
         JImageResourceVisitor_t visitor, void* arg);
+
+/*
+ * JIMAGE_ResourcePath- Given an open image file, a location reference, a buffer
+ * and a maximum buffer size, copy the path of the resource into the buffer.
+ * Returns false if not a valid location reference.
+ *
+ * Ex.
+ *   JImageLocationRef location = ...
+ *   char path[JIMAGE_MAX_PATH];
+ *    (*JImageResourcePath)(image, location, path, JIMAGE_MAX_PATH);
+ */
+extern "C" bool JIMAGE_ResourcePath(JImageFile* image, JImageLocationRef locationRef,
+                                    char* path, size_t max);
+
+typedef bool (*JImage_ResourcePath_t)(JImageFile* jimage, JImageLocationRef location,
+        char* buffer, jlong size);
+
--- a/src/jdk.jdi/share/classes/com/sun/jdi/VirtualMachineManager.java	Mon Apr 25 18:07:45 2016 +0300
+++ b/src/jdk.jdi/share/classes/com/sun/jdi/VirtualMachineManager.java	Mon Apr 25 09:25:26 2016 -0700
@@ -257,11 +257,11 @@
  * delegate to the {@link com.sun.jdi.connect.spi.TransportService#description()
  * description()} method of the underlying transport service. Both
  * the AttachingConnector and the ListeningConnector will have two
- * Connector {@link com.sun.jdi.connect.Connector$Argument Arguments}.
- * A {@link com.sun.jdi.connect.Connector$StringArgument StringArgument}
+ * Connector {@link com.sun.jdi.connect.Connector.Argument Arguments}.
+ * A {@link com.sun.jdi.connect.Connector.StringArgument StringArgument}
  * named {@code address} is the connector argument to specify the
  * address to attach too, or to listen on. A
- * {@link com.sun.jdi.connect.Connector$IntegerArgument IntegerArgument}
+ * {@link com.sun.jdi.connect.Connector.IntegerArgument IntegerArgument}
  * named {@code timeout} is the connector argument to specify the
  * timeout when attaching, or accepting. The timeout connector may be
  * ignored depending on if the transport service supports an attach
--- a/src/jdk.jlink/share/classes/jdk/tools/jimage/ExtractedImage.java	Mon Apr 25 18:07:45 2016 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.tools.jimage;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.function.Consumer;
-import jdk.tools.jlink.internal.ImageFileCreator;
-import jdk.tools.jlink.internal.Archive;
-import jdk.tools.jlink.internal.ImagePluginStack;
-import jdk.tools.jlink.internal.DirArchive;
-/**
- *
- * Support for extracted image.
- */
-public final class ExtractedImage {
-
-    private Set<Archive> archives = new HashSet<>();
-    private final ImagePluginStack plugins;
-
-    ExtractedImage(Path dirPath, ImagePluginStack plugins, PrintWriter log,
-            boolean verbose) throws IOException {
-        if (!Files.isDirectory(dirPath)) {
-            throw new IOException("Not a directory");
-        }
-        Consumer<String> cons = (String t) -> {
-            if (verbose) {
-                log.println(t);
-            }
-        };
-        this.plugins = plugins;
-        Files.walk(dirPath, 1).forEach((p) -> {
-            if (!dirPath.equals(p)) {
-                if (Files.isDirectory(p)) {
-                    Archive a = new DirArchive(p, cons);
-                    archives.add(a);
-                }
-            }
-        });
-        archives = Collections.unmodifiableSet(archives);
-    }
-
-    void recreateJImage(Path path) throws IOException {
-        ImageFileCreator.recreateJimage(path, archives, plugins);
-    }
-
-    private static String getPathName(Path path) {
-        return path.toString().replace(File.separatorChar, '/');
-    }
-}
--- a/src/jdk.jlink/share/classes/jdk/tools/jimage/JImageTask.java	Mon Apr 25 18:07:45 2016 +0300
+++ b/src/jdk.jlink/share/classes/jdk/tools/jimage/JImageTask.java	Mon Apr 25 09:25:26 2016 -0700
@@ -32,7 +32,6 @@
 import java.nio.ByteOrder;
 import java.nio.channels.FileChannel;
 import java.nio.file.Files;
-import java.nio.file.Path;
 import static java.nio.file.StandardOpenOption.READ;
 import static java.nio.file.StandardOpenOption.WRITE;
 import java.util.LinkedList;
@@ -44,8 +43,6 @@
 import static jdk.internal.jimage.ImageHeader.MINOR_VERSION;
 import jdk.internal.jimage.ImageLocation;
 import jdk.tools.jlink.internal.ImageResourcesTree;
-import jdk.tools.jlink.internal.ImagePluginConfiguration;
-import jdk.tools.jlink.internal.ImagePluginStack;
 import jdk.tools.jlink.internal.TaskHelper;
 import jdk.tools.jlink.internal.TaskHelper.BadArgs;
 import static jdk.tools.jlink.internal.TaskHelper.JIMAGE_BUNDLE;
@@ -97,7 +94,6 @@
         EXTRACT,
         INFO,
         LIST,
-        RECREATE,
         SET,
         VERIFY
     };
@@ -152,21 +148,28 @@
             setLog(new PrintWriter(System.out));
         }
 
+        if (args.length == 0) {
+            log.println(taskHelper.getMessage("main.usage.summary", PROGNAME));
+            return EXIT_ABNORMAL;
+        }
+
         try {
             List<String> unhandled = optionsHelper.handleOptions(this, args);
             if(!unhandled.isEmpty()) {
-                options.task = Enum.valueOf(Task.class, unhandled.get(0).toUpperCase());
+                try {
+                    options.task = Enum.valueOf(Task.class, unhandled.get(0).toUpperCase());
+                } catch (IllegalArgumentException ex) {
+                    throw taskHelper.newBadArgs("err.not.a.task", unhandled.get(0));
+                }
                 for(int i = 1; i < unhandled.size(); i++) {
                     options.jimages.add(new File(unhandled.get(i)));
                 }
+            } else {
+                throw taskHelper.newBadArgs("err.not.a.task", "<unspecified>");
             }
             if (options.help) {
                 optionsHelper.showHelp(PROGNAME);
             }
-            if(optionsHelper.listPlugins()) {
-                optionsHelper.listPlugins(true);
-                return EXIT_OK;
-            }
             if (options.version || options.fullVersion) {
                 taskHelper.showVersion(options.fullVersion);
             }
@@ -186,49 +189,19 @@
         }
     }
 
-    private void recreate() throws Exception, BadArgs {
-        File directory = new File(options.directory);
-        if (!directory.isDirectory()) {
-            throw taskHelper.newBadArgs("err.not.a.dir", directory.getAbsolutePath());
-        }
-        Path dirPath = directory.toPath();
-        if (options.jimages.isEmpty()) {
-            throw taskHelper.newBadArgs("err.jimage.not.specified");
-        } else if (options.jimages.size() != 1) {
-            throw taskHelper.newBadArgs("err.only.one.jimage");
-        }
-
-        Path jimage = options.jimages.get(0).toPath();
-
-        if (jimage.toFile().createNewFile()) {
-            ImagePluginStack pc = ImagePluginConfiguration.parseConfiguration(taskHelper.
-                    getPluginsConfig(null, false));
-            ExtractedImage img = new ExtractedImage(dirPath, pc, log, options.verbose);
-            img.recreateJImage(jimage);
-        } else {
-            throw taskHelper.newBadArgs("err.jimage.already.exists", jimage.getFileName());
-        }
-    }
-
-    private void title(File file, BasicImageReader reader) {
-        log.println("jimage: " + file.getName());
-    }
-
     private void listTitle(File file, BasicImageReader reader) {
-        title(file, reader);
-
-        if (options.verbose) {
-            log.print(pad("Offset", OFFSET_WIDTH + 1));
-            log.print(pad("Size", SIZE_WIDTH + 1));
-            log.print(pad("Compressed", COMPRESSEDSIZE_WIDTH + 1));
-            log.println(" Entry");
-        }
+        log.println("jimage: " + file);
     }
 
     private interface JImageAction {
         public void apply(File file, BasicImageReader reader) throws IOException, BadArgs;
     }
 
+    private interface ModuleAction {
+         public void apply(BasicImageReader reader,
+                 String oldModule, String newModule) throws IOException, BadArgs;
+    }
+
     private interface ResourceAction {
         public void apply(BasicImageReader reader, String name,
                 ImageLocation location) throws IOException, BadArgs;
@@ -254,23 +227,32 @@
         }
     }
 
-    private static final int NUMBER_WIDTH = 12;
-    private static final int OFFSET_WIDTH = NUMBER_WIDTH;
-    private static final int SIZE_WIDTH = NUMBER_WIDTH;
-    private static final int COMPRESSEDSIZE_WIDTH = NUMBER_WIDTH;
+    private static final int OFFSET_WIDTH = 12;
+    private static final int SIZE_WIDTH = 10;
+    private static final int COMPRESSEDSIZE_WIDTH = 10;
 
-    private void print(String entry, ImageLocation location) {
+    private String trimModule(String name) {
+        int offset = name.indexOf('/', 1);
+
+        if (offset != -1 && offset + 1 < name.length()) {
+            return name.substring(offset + 1);
+        }
+
+        return name;
+    }
+
+    private void print(String name, ImageLocation location) {
         log.print(pad(location.getContentOffset(), OFFSET_WIDTH) + " ");
         log.print(pad(location.getUncompressedSize(), SIZE_WIDTH) + " ");
         log.print(pad(location.getCompressedSize(), COMPRESSEDSIZE_WIDTH) + " ");
-        log.println(entry);
+        log.println(trimModule(name));
     }
 
-    private void print(BasicImageReader reader, String entry) {
+    private void print(BasicImageReader reader, String name) {
         if (options.verbose) {
-            print(entry, reader.findLocation(entry));
+            print(name, reader.findLocation(name));
         } else {
-            log.println(entry);
+            log.println("    " + trimModule(name));
         }
     }
 
@@ -289,6 +271,18 @@
         log.println(" Index Size:     " + header.getIndexSize());
     }
 
+    private void listModule(BasicImageReader reader, String oldModule, String newModule) {
+        log.println();
+        log.println("Module: " + newModule);
+
+        if (options.verbose) {
+            log.print(pad("Offset", OFFSET_WIDTH) + " ");
+            log.print(pad("Size", SIZE_WIDTH) + " ");
+            log.print(pad("Compressed", COMPRESSEDSIZE_WIDTH) + " ");
+            log.println("Entry");
+        }
+    }
+
     private void list(BasicImageReader reader, String name, ImageLocation location) {
         print(reader, name);
     }
@@ -338,7 +332,12 @@
     }
 
     private void iterate(JImageAction jimageAction,
+            ModuleAction moduleAction,
             ResourceAction resourceAction) throws IOException, BadArgs {
+        if (options.jimages.isEmpty()) {
+            throw taskHelper.newBadArgs("err.no.jimage");
+        }
+
         for (File file : options.jimages) {
             if (!file.exists() || !file.isFile()) {
                 throw taskHelper.newBadArgs("err.not.a.jimage", file.getName());
@@ -351,9 +350,23 @@
 
                 if (resourceAction != null) {
                     String[] entryNames = reader.getEntryNames();
+                    String oldModule = "";
 
                     for (String name : entryNames) {
                         if (!ImageResourcesTree.isTreeInfoResource(name)) {
+                            if (moduleAction != null) {
+                                int offset = name.indexOf('/', 1);
+
+                                String newModule = offset != -1 ?
+                                        name.substring(1, offset) :
+                                        "<unknown>";
+
+                                if (!oldModule.equals(newModule)) {
+                                    moduleAction.apply(reader, oldModule, newModule);
+                                    oldModule = newModule;
+                                }
+                            }
+
                             ImageLocation location = reader.findLocation(name);
                             resourceAction.apply(reader, name, location);
                         }
@@ -366,22 +379,19 @@
     private boolean run() throws Exception, BadArgs {
         switch (options.task) {
             case EXTRACT:
-                iterate(null, this::extract);
+                iterate(null, null, this::extract);
                 break;
             case INFO:
-                iterate(this::info, null);
+                iterate(this::info, null, null);
                 break;
             case LIST:
-                iterate(this::listTitle, this::list);
-                break;
-            case RECREATE:
-                recreate();
+                iterate(this::listTitle, this::listModule, this::list);
                 break;
             case SET:
-                iterate(this::set, null);
+                iterate(this::set, null, null);
                 break;
             case VERIFY:
-                iterate(this::title, this::verify);
+                iterate(this::listTitle, null, this::verify);
                 break;
             default:
                 throw taskHelper.newBadArgs("err.invalid.task", options.task.name()).showUsage(true);
--- a/src/jdk.jlink/share/classes/jdk/tools/jimage/resources/jimage.properties	Mon Apr 25 18:07:45 2016 +0300
+++ b/src/jdk.jlink/share/classes/jdk/tools/jimage/resources/jimage.properties	Mon Apr 25 09:25:26 2016 -0700
@@ -1,30 +1,25 @@
 main.usage.summary=\
-Usage: {0} <extract|info|list|recreate|set|verify> <options> jimage...\n\
+Usage: {0} <extract|info|list|set|verify> <options> jimage...\n\
 use --help for a list of possible options
 
 main.usage=\
-Usage: {0} <extract|info|list|recreate|set|verify> <options> jimage...\n\
+Usage: {0} <extract|info|list|set|verify> <options> jimage...\n\
 \n\
 \  extract  - Extract all jimage entries into separate files into the directory\n\
 \             specified by --dir=<directory> (default='.')\n\
 \  info     - Prints information specified in the jimage header.\n\
 \  list     - Prints the names of all the entries in the jimage.  When used with\n\
 \             --verbose will also print entry attributes ex. size and offset.\n\
-\  recreate - Reconstructs a jimage from an extracted directory (--dir)\n\
 \  set      - sets the value of specific jimage header entries\n\
 \  verify   - Reports errors on any .class entries that don't verify as classes.\n\
 \n\
 Possible options include:
 
-main.extended.help=\
-jimage recreate is extensible by the main of plugins. Following plugins have been discovered \
-thanks to ServiceLoader and can be used when re-creating a jimage.
-
 error.prefix=Error:
 warn.prefix=Warning:
 
 main.opt.dir=\
-\  --dir                                Target directory for extract/recreate
+\  --dir                                Target directory for extract
 
 main.opt.flags=\
 \  --flags=value                        Set the jimage flags to value
@@ -38,14 +33,8 @@
 main.opt.version=\
 \  --version                            Version information
 
-main.opt.configuration=\
-\  --configuration <path>               Path to properties file containing defaults\
-\ options for recreate
-
 main.command.files=\
 \  @<filename>                          Read options from file
-
-err.cannot.create.dir=cannot create directory: {0}
 err.cannot.read.file=cannot read file: {0}
 err.cannot.update.file=cannot update file: {0}
 err.file.not.found=cannot find file: {0}
@@ -53,12 +42,11 @@
 err.flags.not.int=--flags value not integer: {0}
 err.internal.error=internal error: {0} {1} {2}
 err.invalid.arg.for.option=invalid argument for option: {0}
-err.invalid.task=task must be extract|recreate|info|list|verify: {0}
-err.jimage.already.exists=jimage already exists: {0}
-err.jimage.not.specified=no jimage specified
+err.invalid.task=task must be extract|info|list|verify: {0}
 err.missing.arg=no value given for {0}
 err.not.a.dir=not a directory: {0}
 err.not.a.jimage=not a jimage file: {0}
-err.only.one.jimage=only one jimage should be specified
+err.no.jimage=no jimage provided
+err.not.a.task=not a valid task: {0}
 err.option.unsupported={0} not supported: {1}
 err.unknown.option=unknown option: {0}
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/Pool.java	Mon Apr 25 18:07:45 2016 +0300
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/Pool.java	Mon Apr 25 09:25:26 2016 -0700
@@ -226,7 +226,7 @@
      * <li>For jimage content: /{module name}/{package1}/.../{packageN}/{file
      * name}</li>
      * <li>For other files (shared lib, launchers, config, ...):/{module name}/
-     * {@literal bin|conf|native}/{dir1}>/.../{dirN}/{file name}</li>
+     * {@literal bin|conf|native}/{dir1}/.../{dirN}/{file name}</li>
      * </ul>
      */
     public static class ModuleData {
--- a/src/jdk.unsupported/share/classes/sun/misc/ManagedLocalsThread.java	Mon Apr 25 18:07:45 2016 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.misc;
-
-/**
- * A thread that has it's thread locals, and inheritable thread
- * locals erased on construction.
- */
-public class ManagedLocalsThread extends Thread {
-    private static final jdk.internal.misc.Unsafe UNSAFE;
-    private static final long THREAD_LOCALS;
-    private static final long INHERITABLE_THREAD_LOCALS;
-
-    public ManagedLocalsThread() {
-        eraseThreadLocals();
-    }
-
-    public ManagedLocalsThread(Runnable target) {
-        super(target);
-        eraseThreadLocals();
-    }
-
-    public ManagedLocalsThread(String name) {
-        super(name);
-        eraseThreadLocals();
-    }
-
-    public ManagedLocalsThread(ThreadGroup group, Runnable target) {
-        super(group, target);
-        eraseThreadLocals();
-    }
-
-    public ManagedLocalsThread(Runnable target, String name) {
-        super(target, name);
-        eraseThreadLocals();
-    }
-
-    public ManagedLocalsThread(ThreadGroup group, String name) {
-        super(group, name);
-        eraseThreadLocals();
-    }
-
-    public ManagedLocalsThread(ThreadGroup group, Runnable target, String name) {
-        super(group, target, name);
-        eraseThreadLocals();
-    }
-
-    /**
-     * Drops all thread locals (and inherited thread locals).
-     */
-    public final void eraseThreadLocals() {
-        UNSAFE.putObject(this, THREAD_LOCALS, null);
-        UNSAFE.putObject(this, INHERITABLE_THREAD_LOCALS, null);
-    }
-
-    static {
-        UNSAFE = jdk.internal.misc.Unsafe.getUnsafe();
-        Class<?> t = Thread.class;
-        try {
-            THREAD_LOCALS = UNSAFE.objectFieldOffset
-                (t.getDeclaredField("threadLocals"));
-            INHERITABLE_THREAD_LOCALS = UNSAFE.objectFieldOffset
-                (t.getDeclaredField("inheritableThreadLocals"));
-        } catch (Exception e) {
-            throw new Error(e);
-        }
-    }
-}
-
--- a/test/TEST.groups	Mon Apr 25 18:07:45 2016 +0300
+++ b/test/TEST.groups	Mon Apr 25 09:25:26 2016 -0700
@@ -32,7 +32,6 @@
     -java/util/WeakHashMap/GCDuringIteration.java \
     -java/util/concurrent/ThreadPoolExecutor/ConfigChanges.java \
     -java/util/concurrent/forkjoin/FJExceptionTableLeak.java \
-    -java/util/TimeZone/Bug6772689.java \
     sun/nio/cs/ISO8859x.java \
     java/nio/Buffer \
     com/sun/crypto/provider/Cipher \
@@ -43,7 +42,6 @@
     java/util/WeakHashMap/GCDuringIteration.java \
     java/util/concurrent/ThreadPoolExecutor/ConfigChanges.java \
     java/util/concurrent/forkjoin/FJExceptionTableLeak.java \
-    java/util/TimeZone/Bug6772689.java \
     :jdk_io \
     :jdk_nio \
     -sun/nio/cs/ISO8859x.java \
--- a/test/java/lang/invoke/LoopCombinatorTest.java	Mon Apr 25 18:07:45 2016 +0300
+++ b/test/java/lang/invoke/LoopCombinatorTest.java	Mon Apr 25 09:25:26 2016 -0700
@@ -28,7 +28,10 @@
  * @bug 8150635
  * @bug 8150956
  * @bug 8150957
+ * @bug 8152667
  * @bug 8153637
+ * @bug 8154751
+ * @bug 8154754
  * @run testng/othervm -ea -esa test.java.lang.invoke.LoopCombinatorTest
  */
 
@@ -325,6 +328,74 @@
     }
 
     @Test
+    public static void testCountedLoopNullBody() throws Throwable {
+        MethodHandle h5 = MethodHandles.constant(int.class, 5);
+        MethodHandle h13 = MethodHandles.constant(int.class, 13);
+        MethodHandle loop = MethodHandles.countedLoop(h5, h13, null);
+        assertEquals(methodType(int.class), loop.type());
+        assertEquals(13, loop.invoke());
+    }
+
+    @Test
+    public static void testCountedLoopNullIterations() throws Throwable {
+        MethodHandle loop = MethodHandles.countedLoop(null, null, null);
+        assertEquals(methodType(void.class), loop.type());
+        loop.invoke();
+    }
+
+    @Test
+    public static void testCountedLoopNullInitAndBody() throws Throwable {
+        MethodHandle loop = MethodHandles.countedLoop(MethodHandles.constant(int.class, 5), null, null);
+        assertEquals(methodType(void.class), loop.type());
+        loop.invoke();
+    }
+
+    @DataProvider
+    static Object[][] countedLoopBodyParameters() {
+        return new Object[][] {
+                {methodType(String.class), methodType(String.class, int.class)},
+                {methodType(String.class, List.class), methodType(String.class, int.class)},
+                {methodType(String.class, List.class), methodType(String.class, int.class, String.class)}
+        };
+    }
+
+    @Test(dataProvider = "countedLoopBodyParameters")
+    public static void testCountedLoopBodyParameters(MethodType initType, MethodType bodyType) throws Throwable {
+        MethodHandle loop = MethodHandles.countedLoop(MethodHandles.constant(int.class, 5),
+                MethodHandles.empty(initType), MethodHandles.empty(bodyType));
+        assertEquals(initType, loop.type());
+    }
+
+    @DataProvider
+    static Object[][] countedLoopTypes() {
+        return new Object[][]{{void.class}, {int.class}, {Object.class}, {String.class}, {List.class}};
+    }
+
+    @Test(dataProvider = "countedLoopTypes")
+    public static void testCountedLoopBodyParametersNullInit(Class<?> t) throws Throwable {
+        MethodHandle loop = MethodHandles.countedLoop(MethodHandles.constant(int.class, 5), null,
+                MethodHandles.empty(methodType(t, int.class)));
+        assertEquals(methodType(t), loop.type());
+        loop.invoke();
+    }
+
+    @Test
+    public static void testCountedLoopStateDefinedByBody() throws Throwable {
+        MethodHandle loop = MethodHandles.countedLoop(MethodHandles.constant(int.class, 5), null, Counted.MH_stateBody);
+        assertEquals(Counted.MT_bodyDeterminesState, loop.type());
+        assertEquals("sssssnull01234", loop.invoke());
+    }
+
+    @Test
+    public static void testCountedLoopArgsDefinedByIterations() throws Throwable {
+        MethodHandle loop = MethodHandles.countedLoop(
+                MethodHandles.dropArguments(MethodHandles.constant(int.class, 3), 0, String.class),
+                null, Counted.MH_append);
+        assertEquals(Counted.MT_iterationsDefineArgs, loop.type());
+        assertEquals("hello012", loop.invoke("hello"));
+    }
+
+    @Test
     public static void testCountedRangeLoop() throws Throwable {
         // String s = "Lambdaman!"; for (int i = -5; i < 8; ++i) { s = "na " + s; } return s; => a well known theme
         MethodHandle fitm5 = MethodHandles.dropArguments(Counted.MH_m5, 0, String.class);
@@ -347,6 +418,23 @@
     }
 
     @Test
+    public static void testCountedLoopEmpty() throws Throwable {
+        // for (int i = 0; i < 5; ++i) { /* empty */ }
+        MethodHandle loop = MethodHandles.countedLoop(MethodHandles.constant(int.class, 5), null, null);
+        assertEquals(methodType(void.class), loop.type());
+        loop.invoke();
+    }
+
+    @Test
+    public static void testCountedRangeLoopEmpty() throws Throwable {
+        // for (int i = -5; i < 5; ++i) { /* empty */ }
+        MethodHandle loop = MethodHandles.countedLoop(MethodHandles.constant(int.class, -5),
+                MethodHandles.constant(int.class, 5), null, null);
+        assertEquals(methodType(void.class), loop.type());
+        loop.invoke();
+    }
+
+    @Test
     public static void testIterateSum() throws Throwable {
         // Integer[] a = new Integer[]{1,2,3,4,5,6}; int sum = 0; for (int e : a) { sum += e; } return sum; => 21
         MethodHandle loop = MethodHandles.iteratedLoop(Iterate.MH_sumIterator, Iterate.MH_sumInit, Iterate.MH_sumStep);
@@ -400,10 +488,15 @@
         assertTrue(caught);
     }
 
-    @Test
-    public static void testIterateVoidIterator() {
+    @DataProvider
+    static Object[][] wrongIteratorTypes() {
+        return new Object[][]{{void.class}, {Object.class}, {Iterable.class}};
+    }
+
+    @Test(dataProvider = "wrongIteratorTypes")
+    public static void testIterateVoidIterator(Class<?> it) {
         boolean caught = false;
-        MethodType v = methodType(void.class);
+        MethodType v = methodType(it);
         try {
             MethodHandles.iteratedLoop(MethodHandles.empty(v), null, MethodHandles.empty(v));
         } catch(IllegalArgumentException iae) {
@@ -420,6 +513,77 @@
         loop.invoke(Arrays.asList("hello", "world"));
     }
 
+    @DataProvider
+    static Object[][] iterateParameters() {
+        MethodType i = methodType(int.class);
+        MethodType sil_i = methodType(int.class, String.class, int.class, List.class);
+        MethodType sl_v = methodType(void.class, String.class, List.class);
+        MethodType l_it = methodType(Iterator.class, List.class);
+        MethodType li_it = methodType(Iterator.class, List.class, int.class);
+        MethodType l_i = methodType(int.class, List.class);
+        MethodType _it = methodType(Iterator.class);
+        MethodType si_i = methodType(int.class, String.class, int.class);
+        MethodType s_i = methodType(int.class, String.class);
+        return new Object[][]{
+                {null, null, sl_v},
+                {null, i, sil_i},
+                {null, l_i, sil_i},
+                {l_it, null, sl_v},
+                {l_it, i, sil_i},
+                {li_it, l_i, sil_i},
+                {l_it, null, sil_i},
+                {li_it, null, sl_v},
+                {_it, l_i, si_i},
+                {_it, l_i, s_i}
+        };
+    }
+
+    @Test(dataProvider = "iterateParameters")
+    public static void testIterateParameters(MethodType it, MethodType in, MethodType bo) throws Throwable {
+        MethodHandle iterator = it == null ? null : MethodHandles.empty(it);
+        MethodHandle init = in == null ? null : MethodHandles.empty(in);
+        MethodHandle loop = MethodHandles.iteratedLoop(iterator, init, MethodHandles.empty(bo));
+        MethodType lt = loop.type();
+        if (it == null && in == null) {
+            assertEquals(bo.dropParameterTypes(0, 1), lt);
+        } else if (it == null) {
+            if (in.parameterCount() == 0) {
+                assertEquals(bo.dropParameterTypes(0, in.returnType() == void.class ? 1 : 2), lt);
+            } else {
+                assertEquals(methodType(bo.returnType(), in.parameterArray()), lt);
+            }
+        } else if (in == null) {
+            assertEquals(methodType(bo.returnType(), it.parameterArray()), lt);
+        } else if (it.parameterCount() > in.parameterCount()) {
+            assertEquals(methodType(bo.returnType(), it.parameterArray()), lt);
+        } else if (it.parameterCount() < in.parameterCount()) {
+            assertEquals(methodType(bo.returnType(), in.parameterArray()), lt);
+        } else {
+            // both it, in present; with equal parameter list lengths
+            assertEquals(it.parameterList(), lt.parameterList());
+            assertEquals(in.parameterList(), lt.parameterList());
+            assertEquals(bo.returnType(), lt.returnType());
+        }
+    }
+
+    @Test
+    public static void testIteratorSubclass() throws Throwable {
+        MethodHandle loop = MethodHandles.iteratedLoop(MethodHandles.empty(methodType(BogusIterator.class, List.class)),
+                null, MethodHandles.empty(methodType(void.class, String.class)));
+        assertEquals(methodType(void.class, List.class), loop.type());
+    }
+
+    static class BogusIterator implements Iterator {
+        @Override
+        public boolean hasNext() {
+            return false;
+        }
+        @Override
+        public Object next() {
+            return null;
+        }
+    }
+
     static class Empty {
 
         static void f() { }
@@ -744,6 +908,17 @@
             return x + counter;
         }
 
+        static String stateBody(int counter, String s) {
+            return "s" + s + counter;
+        }
+
+        static String append(int counter, String localState, String loopArg) {
+            if (null == localState) {
+                return loopArg + counter;
+            }
+            return localState + counter;
+        }
+
         static final Class<Counted> COUNTED = Counted.class;
 
         static final MethodType MT_start = methodType(String.class, String.class);
@@ -751,6 +926,8 @@
         static final MethodType MT_stepUpdateArray = methodType(void.class, int.class, int[].class);
         static final MethodType MT_printHello = methodType(void.class, int.class);
         static final MethodType MT_addCounter = methodType(int.class, int.class, int.class);
+        static final MethodType MT_stateBody = methodType(String.class, int.class, String.class);
+        static final MethodType MT_append = methodType(String.class, int.class, String.class, String.class);
 
         static final MethodHandle MH_13;
         static final MethodHandle MH_m5;
@@ -760,11 +937,15 @@
         static final MethodHandle MH_stepUpdateArray;
         static final MethodHandle MH_printHello;
         static final MethodHandle MH_addCounter;
+        static final MethodHandle MH_stateBody;
+        static final MethodHandle MH_append;
 
         static final MethodType MT_counted = methodType(String.class, String.class);
         static final MethodType MT_arrayCounted = methodType(void.class, int[].class);
         static final MethodType MT_countedPrinting = methodType(void.class);
         static final MethodType MT_counterInit = methodType(int.class);
+        static final MethodType MT_bodyDeterminesState = methodType(String.class);
+        static final MethodType MT_iterationsDefineArgs = methodType(String.class, String.class);
 
         static {
             try {
@@ -776,6 +957,8 @@
                 MH_stepUpdateArray = LOOKUP.findStatic(COUNTED, "stepUpdateArray", MT_stepUpdateArray);
                 MH_printHello = LOOKUP.findStatic(COUNTED, "printHello", MT_printHello);
                 MH_addCounter = LOOKUP.findStatic(COUNTED, "addCounter", MT_addCounter);
+                MH_stateBody = LOOKUP.findStatic(COUNTED, "stateBody", MT_stateBody);
+                MH_append = LOOKUP.findStatic(COUNTED, "append", MT_append);
             } catch (Exception e) {
                 throw new ExceptionInInitializerError(e);
             }
--- a/test/java/time/tck/java/time/format/TCKDateTimeFormatterBuilder.java	Mon Apr 25 18:07:45 2016 +0300
+++ b/test/java/time/tck/java/time/format/TCKDateTimeFormatterBuilder.java	Mon Apr 25 09:25:26 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -71,6 +71,7 @@
 
 import java.text.ParsePosition;
 import java.time.LocalDate;
+import java.time.LocalDateTime;
 import java.time.YearMonth;
 import java.time.ZoneOffset;
 import java.time.format.DateTimeFormatter;
@@ -661,6 +662,8 @@
             {"W"},
             {"W"},
 
+            {"g"},
+            {"ggggg"},
         };
     }
 
@@ -762,6 +765,37 @@
     }
 
     //-----------------------------------------------------------------------
+    @DataProvider(name="modJulianFieldPattern")
+    Object[][] data_modJuilanFieldPattern() {
+        return new Object[][] {
+            {"g", "1"},
+            {"g", "123456"},
+            {"gggggg", "123456"},
+        };
+    }
+
+    @Test(dataProvider="modJulianFieldPattern")
+    public void test_modJulianFieldPattern(String pattern, String input) throws Exception {
+        DateTimeFormatter.ofPattern(pattern).parse(input);
+    }
+
+    @DataProvider(name="modJulianFieldValues")
+    Object[][] data_modJuilanFieldValues() {
+        return new Object[][] {
+            {1970, 1, 1, "40587"},
+            {1858, 11, 17, "0"},
+            {1858, 11, 16, "-1"},
+        };
+    }
+
+    @Test(dataProvider="modJulianFieldValues")
+    public void test_modJulianFieldValues(int y, int m, int d, String expected) throws Exception {
+        DateTimeFormatter df = new DateTimeFormatterBuilder().appendPattern("g").toFormatter();
+         assertEquals(LocalDate.of(y, m, d).format(df), expected);
+    }
+
+
+    //-----------------------------------------------------------------------
     @Test
     public void test_adjacent_strict_firstFixedWidth() throws Exception {
         // succeeds because both number elements are fixed width
@@ -897,7 +931,7 @@
 
     @Test
     public void test_adjacent_lenient_fractionFollows_0digit() throws Exception {
-        // succeeds because hour/min are fixed width
+        // succeeds because hour, min and fraction of seconds are fixed width
         DateTimeFormatter f = builder.parseLenient().appendValue(HOUR_OF_DAY, 2).appendValue(MINUTE_OF_HOUR, 2).appendFraction(NANO_OF_SECOND, 3, 3, false).toFormatter(Locale.UK);
         ParsePosition pp = new ParsePosition(0);
         TemporalAccessor parsed = f.parseUnresolved("1230", pp);
@@ -907,6 +941,21 @@
         assertEquals(parsed.getLong(MINUTE_OF_HOUR), 30L);
     }
 
+    @DataProvider(name="adjacentFractionParseData")
+    Object[][] data_adjacent_fraction_parse() {
+        return new Object[][] {
+            {"20130812214600025", "yyyyMMddHHmmssSSS", LocalDateTime.of(2013, 8, 12, 21, 46, 00, 25000000)},
+            {"201308122146000256", "yyyyMMddHHmmssSSSS", LocalDateTime.of(2013, 8, 12, 21, 46, 00, 25600000)},
+        };
+    }
+
+    @Test(dataProvider = "adjacentFractionParseData")
+    public void test_adjacent_fraction(String input, String pattern, LocalDateTime expected) {
+        DateTimeFormatter dtf = DateTimeFormatter.ofPattern(pattern);
+        LocalDateTime actual = LocalDateTime.parse(input, dtf);
+        assertEquals(actual, expected);
+    }
+
     @DataProvider(name="lenientOffsetParseData")
     Object[][] data_lenient_offset_parse() {
         return new Object[][] {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/time/tck/java/time/format/TCKLocalizedOffsetIdPrinterParser.java	Mon Apr 25 09:25:26 2016 -0700
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package tck.java.time.format;
+
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Locale;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test localized behavior of formatter.
+ */
+@Test
+public class TCKLocalizedOffsetIdPrinterParser {
+    @Test
+    public void test_localized_offset_parse() {
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.S O")
+                                                       .withLocale(Locale.ENGLISH);
+        String date = formatter.format(ZonedDateTime.now(ZoneOffset.UTC));
+        formatter.parse(date) ;
+     }
+}
--- a/test/java/util/TimeZone/Bug6772689.java	Mon Apr 25 18:07:45 2016 +0300
+++ b/test/java/util/TimeZone/Bug6772689.java	Mon Apr 25 09:25:26 2016 -0700
@@ -24,7 +24,6 @@
 /*
  * @test
  * @bug 6772689
- * @key intermittent
  * @summary Test for standard-to-daylight transitions at midnight:
  * date stays on the given day.
  */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/ServerName/BestEffortOnLazyConnected.java	Mon Apr 25 09:25:26 2016 -0700
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/**
+ * @test
+ * @bug 8144566
+ * @summary Custom HostnameVerifier disables SNI extension
+ * @run main/othervm BestEffortOnLazyConnected
+ */
+
+import java.io.*;
+import java.nio.*;
+import java.nio.channels.*;
+import java.util.*;
+import java.net.*;
+import javax.net.ssl.*;
+
+public class BestEffortOnLazyConnected {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    private static final boolean separateServerThread = true;
+
+    /*
+     * Where do we find the keystores?
+     */
+    private static final String pathToStores = "../etc";
+    private static final String keyStoreFile = "keystore";
+    private static final String trustStoreFile = "truststore";
+    private static final String passwd = "passphrase";
+
+    /*
+     * Is the server ready to serve?
+     */
+    private static volatile boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    private static final boolean debug = false;
+
+    /*
+     * the fully qualified domain name of localhost
+     */
+    private static String hostname = null;
+
+    /*
+     * If the client or server is doing some kind of object creation
+     * that the other side depends on, and that thread prematurely
+     * exits, you may experience a hang.  The test harness will
+     * terminate all hung threads after its timeout has expired,
+     * currently 3 minutes by default, but you might try to be
+     * smart about it....
+     */
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    private void doServerSide() throws Exception {
+        SSLServerSocketFactory sslssf =
+            (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
+        try (SSLServerSocket sslServerSocket =
+                (SSLServerSocket) sslssf.createServerSocket(serverPort)) {
+
+            serverPort = sslServerSocket.getLocalPort();
+
+            /*
+             * Signal Client, we're ready for his connect.
+             */
+            serverReady = true;
+
+            try (SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept()) {
+                InputStream sslIS = sslSocket.getInputStream();
+                OutputStream sslOS = sslSocket.getOutputStream();
+
+                sslIS.read();
+                sslOS.write(85);
+                sslOS.flush();
+
+                ExtendedSSLSession session =
+                        (ExtendedSSLSession)sslSocket.getSession();
+                if (session.getRequestedServerNames().isEmpty()) {
+                    throw new Exception("No expected Server Name Indication");
+                }
+            }
+        }
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    private void doClientSide() throws Exception {
+
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        SSLSocketFactory sslsf =
+            (SSLSocketFactory) SSLSocketFactory.getDefault();
+
+        try (SSLSocket sslSocket = (SSLSocket)sslsf.createSocket()) {
+
+            sslSocket.connect(new InetSocketAddress(hostname, serverPort), 0);
+
+            InputStream sslIS = sslSocket.getInputStream();
+            OutputStream sslOS = sslSocket.getOutputStream();
+
+            sslOS.write(280);
+            sslOS.flush();
+            sslIS.read();
+        }
+    }
+
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    // use any free port by default
+    private volatile int serverPort = 0;
+
+    private volatile Exception serverException = null;
+    private volatile Exception clientException = null;
+
+    public static void main(String[] args) throws Exception {
+        String keyFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + keyStoreFile;
+        String trustFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+        if (debug) {
+            System.setProperty("javax.net.debug", "all");
+        }
+
+        try {
+            hostname = InetAddress.getLocalHost().getCanonicalHostName();
+        } catch (UnknownHostException uhe) {
+            System.out.println(
+                "Ignore the test as the local hostname cannot be determined");
+
+            return;
+        }
+
+        System.out.println(
+                "The fully qualified domain name of the local host is " +
+                hostname);
+        // Ignore the test if the hostname does not sound like a domain name.
+        if ((hostname == null) || hostname.isEmpty() ||
+                hostname.startsWith("localhost") ||
+                Character.isDigit(hostname.charAt(hostname.length() - 1))) {
+
+            System.out.println("Ignore the test as the local hostname " +
+                    "cannot be determined as fully qualified domain name");
+
+            return;
+        }
+
+        /*
+         * Start the tests.
+         */
+        new BestEffortOnLazyConnected();
+    }
+
+    private Thread clientThread = null;
+    private Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    BestEffortOnLazyConnected() throws Exception {
+        try {
+            if (separateServerThread) {
+                startServer(true);
+                startClient(false);
+            } else {
+                startClient(true);
+                startServer(false);
+            }
+        } catch (Exception e) {
+            // swallow for now.  Show later
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            serverThread.join();
+        } else {
+            clientThread.join();
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         * Which side threw the error?
+         */
+        Exception local;
+        Exception remote;
+        String whichRemote;
+
+        if (separateServerThread) {
+            remote = serverException;
+            local = clientException;
+            whichRemote = "server";
+        } else {
+            remote = clientException;
+            local = serverException;
+            whichRemote = "client";
+        }
+
+        /*
+         * If both failed, return the curthread's exception, but also
+         * print the remote side Exception
+         */
+        if ((local != null) && (remote != null)) {
+            System.out.println(whichRemote + " also threw:");
+            remote.printStackTrace();
+            System.out.println();
+            throw local;
+        }
+
+        if (remote != null) {
+            throw remote;
+        }
+
+        if (local != null) {
+            throw local;
+        }
+    }
+
+    private void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            try {
+                doServerSide();
+            } catch (Exception e) {
+                serverException = e;
+            } finally {
+                serverReady = true;
+            }
+        }
+    }
+
+    private void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            try {
+                doClientSide();
+            } catch (Exception e) {
+                clientException = e;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/net/www/protocol/https/HttpsURLConnection/ImpactOnSNI.java	Mon Apr 25 09:25:26 2016 -0700
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 8144566
+ * @summary Custom HostnameVerifier disables SNI extension
+ * @run main/othervm ImpactOnSNI
+ */
+
+import java.io.*;
+import java.net.*;
+import javax.net.ssl.*;
+
+public class ImpactOnSNI {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    private static final boolean separateServerThread = true;
+
+    /*
+     * Where do we find the keystores?
+     */
+    private static final String pathToStores =
+                                        "../../../../../../javax/net/ssl/etc";
+    private static final String keyStoreFile = "keystore";
+    private static final String trustStoreFile = "truststore";
+    private static final String passwd = "passphrase";
+
+    /*
+     * Is the server ready to serve?
+     */
+    private static volatile boolean serverReady = false;
+
+    /*
+     * Is the connection ready to close?
+     */
+    private static volatile boolean closeReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    private static final boolean debug = false;
+
+    /*
+     * Message posted
+     */
+    private static final String postMsg = "HTTP post on a https server";
+
+    /*
+     * the fully qualified domain name of localhost
+     */
+    private static String hostname = null;
+
+    /*
+     * If the client or server is doing some kind of object creation
+     * that the other side depends on, and that thread prematurely
+     * exits, you may experience a hang.  The test harness will
+     * terminate all hung threads after its timeout has expired,
+     * currently 3 minutes by default, but you might try to be
+     * smart about it....
+     */
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    private void doServerSide() throws Exception {
+        SSLServerSocketFactory sslssf =
+            (SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
+        try (SSLServerSocket sslServerSocket =
+                (SSLServerSocket)sslssf.createServerSocket(serverPort)) {
+
+            serverPort = sslServerSocket.getLocalPort();
+
+            /*
+             * Signal Client, we're ready for his connect.
+             */
+            serverReady = true;
+
+            /*
+             * Accept connections
+             */
+            try (SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept()) {
+                InputStream sslIS = sslSocket.getInputStream();
+                OutputStream sslOS = sslSocket.getOutputStream();
+                BufferedReader br =
+                        new BufferedReader(new InputStreamReader(sslIS));
+                PrintStream ps = new PrintStream(sslOS);
+
+                // process HTTP POST request from client
+                System.out.println("status line: " + br.readLine());
+                String msg = null;
+                while ((msg = br.readLine()) != null && msg.length() > 0);
+
+                msg = br.readLine();
+                if (msg.equals(postMsg)) {
+                    ps.println("HTTP/1.1 200 OK\n\n");
+                } else {
+                    ps.println("HTTP/1.1 500 Not OK\n\n");
+                }
+                ps.flush();
+
+                ExtendedSSLSession session =
+                        (ExtendedSSLSession)sslSocket.getSession();
+                if (session.getRequestedServerNames().isEmpty()) {
+                    throw new Exception("No expected Server Name Indication");
+                }
+
+                // close the socket
+                while (!closeReady) {
+                    Thread.sleep(50);
+                }
+            }
+        }
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    private void doClientSide() throws Exception {
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        // Send HTTP POST request to server
+        URL url = new URL("https://" + hostname + ":" + serverPort);
+
+        HttpsURLConnection.setDefaultHostnameVerifier(new NameVerifier());
+        HttpsURLConnection http = (HttpsURLConnection)url.openConnection();
+        http.setDoOutput(true);
+
+        http.setRequestMethod("POST");
+        PrintStream ps = new PrintStream(http.getOutputStream());
+        try {
+            ps.println(postMsg);
+            ps.flush();
+            if (http.getResponseCode() != 200) {
+                throw new RuntimeException("test Failed");
+            }
+        } finally {
+            ps.close();
+            http.disconnect();
+            closeReady = true;
+        }
+    }
+
+    private static class NameVerifier implements HostnameVerifier {
+        public boolean verify(String hostname, SSLSession session) {
+            return true;
+        }
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    // use any free port by default
+    private volatile int serverPort = 0;
+
+    private volatile Exception serverException = null;
+    private volatile Exception clientException = null;
+
+    public static void main(String[] args) throws Exception {
+        String keyFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + keyStoreFile;
+        String trustFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+        if (debug) {
+            System.setProperty("javax.net.debug", "all");
+        }
+
+        try {
+            hostname = InetAddress.getLocalHost().getCanonicalHostName();
+        } catch (UnknownHostException uhe) {
+            System.out.println(
+                "Ignore the test as the local hostname cannot be determined");
+
+            return;
+        }
+
+        System.out.println(
+                "The fully qualified domain name of the local host is " +
+                hostname);
+        // Ignore the test if the hostname does not sound like a domain name.
+        if ((hostname == null) || hostname.isEmpty() ||
+                hostname.startsWith("localhost") ||
+                Character.isDigit(hostname.charAt(hostname.length() - 1))) {
+
+            System.out.println("Ignore the test as the local hostname " +
+                    "cannot be determined as fully qualified domain name");
+
+            return;
+        }
+
+        /*
+         * Start the tests.
+         */
+        new ImpactOnSNI();
+    }
+
+    private Thread clientThread = null;
+    private Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    ImpactOnSNI() throws Exception {
+        Exception startException = null;
+        try {
+            if (separateServerThread) {
+                startServer(true);
+                startClient(false);
+            } else {
+                startClient(true);
+                startServer(false);
+            }
+        } catch (Exception e) {
+            startException = e;
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            if (serverThread != null) {
+                serverThread.join();
+            }
+        } else {
+            if (clientThread != null) {
+                clientThread.join();
+            }
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         * Which side threw the error?
+         */
+        Exception local;
+        Exception remote;
+
+        if (separateServerThread) {
+            remote = serverException;
+            local = clientException;
+        } else {
+            remote = clientException;
+            local = serverException;
+        }
+
+        Exception exception = null;
+
+        /*
+         * Check various exception conditions.
+         */
+        if ((local != null) && (remote != null)) {
+            // If both failed, return the curthread's exception.
+            local.initCause(remote);
+            exception = local;
+        } else if (local != null) {
+            exception = local;
+        } else if (remote != null) {
+            exception = remote;
+        } else if (startException != null) {
+            exception = startException;
+        }
+
+        /*
+         * If there was an exception *AND* a startException,
+         * output it.
+         */
+        if (exception != null) {
+            if (exception != startException && startException != null) {
+                exception.addSuppressed(startException);
+            }
+            throw exception;
+        }
+
+        // Fall-through: no exception to throw!
+    }
+
+    private void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                @Override
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            try {
+                doServerSide();
+            } catch (Exception e) {
+                serverException = e;
+            } finally {
+                serverReady = true;
+            }
+        }
+    }
+
+    private void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                @Override
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            try {
+                doClientSide();
+            } catch (Exception e) {
+                clientException = e;
+            }
+        }
+    }
+}
--- a/test/tools/jimage/JImageTest.java	Mon Apr 25 18:07:45 2016 +0300
+++ b/test/tools/jimage/JImageTest.java	Mon Apr 25 09:25:26 2016 -0700
@@ -110,54 +110,5 @@
                 .dir(helper.createNewExtractedDir("modules"))
                 .image(image.resolve("lib").resolve("modules"))
                 .extract().assertSuccess();
-
-        Path recreatedImage = JImageGenerator.getJImageTask()
-                .dir(extractedDir)
-                .image(helper.createNewRecreatedDir(extractedDir.getFileName().toString()))
-                .recreate().assertSuccess();
-        JImageValidator.validate(recreatedImage, bootClasses, Collections.emptyList());
-
-        // Check replacing the boot image by recreated one
-        Path destFile = image.resolve("lib").resolve("modules");
-        Files.copy(recreatedImage, destFile, REPLACE_EXISTING);
-        JImageValidator validator = new JImageValidator(module, Collections.emptyList(),
-                image.toFile(), Collections.emptyList(), Collections.emptyList());
-        validator.validate();
-
-        Path recreatedImage2 = JImageGenerator.getJImageTask()
-                .dir(extractedDir)
-                .option("--compress").option("2")
-                .image(helper.createNewRecreatedDir(extractedDir.getFileName().toString()))
-                .recreate().assertSuccess();
-        JImageValidator.validate(recreatedImage2, bootClasses, Collections.emptyList());
-
-        Path recreatedImage3 = JImageGenerator.getJImageTask()
-                .dir(extractedDir)
-                .option("--strip-debug")
-                .image(helper.createNewRecreatedDir(extractedDir.getFileName().toString()))
-                .recreate().assertSuccess();
-        JImageValidator.validate(recreatedImage3, bootClasses, Collections.emptyList());
-
-        Path recreatedImage4 = JImageGenerator.getJImageTask()
-                .dir(extractedDir)
-                .option("--exclude-resources")
-                .option("*.jcov, */META-INF/*")
-                .image(helper.createNewRecreatedDir(extractedDir.getFileName().toString()))
-                .recreate().assertSuccess();
-        List<String> unexpectedPaths = new ArrayList<>();
-        unexpectedPaths.add(".jcov");
-        unexpectedPaths.add("/META-INF/");
-        JImageValidator.validate(recreatedImage4, bootClasses, unexpectedPaths);
-
-        Path recreatedImage5 = JImageGenerator.getJImageTask()
-                .dir(extractedDir)
-                .option("--compress")
-                .option("2")
-                .option("--strip-debug")
-                .option("--exclude-resources")
-                .option("*.jcov, */META-INF/*")
-                .image(helper.createNewRecreatedDir(extractedDir.getFileName().toString()))
-                .recreate().assertSuccess();
-        JImageValidator.validate(recreatedImage5, bootClasses, unexpectedPaths);
     }
 }
--- a/test/tools/jimage/JImageToolTest.java	Mon Apr 25 18:07:45 2016 +0300
+++ b/test/tools/jimage/JImageToolTest.java	Mon Apr 25 09:25:26 2016 -0700
@@ -63,11 +63,7 @@
             String jimage = jimagePath.toAbsolutePath().toString();
             String bootimage = modulesimagePath.toAbsolutePath().toString();
             String extractDir = Paths.get(".", "extract").toAbsolutePath().toString();
-            String recreateImage = Paths.get(".", "recreate").toAbsolutePath().toString();
-            String relativeRecreateImage = Paths.get(".", "recreate2").toString();
             jimage("extract", "--dir", extractDir, bootimage);
-            jimage("recreate", "--dir", extractDir, recreateImage);
-            jimage("recreate", "--dir", extractDir, relativeRecreateImage);
             System.out.println("Test successful");
          } else {
             System.out.println("Test skipped, not an images build");
--- a/test/tools/launcher/modules/limitmods/LimitModsTest.java	Mon Apr 25 18:07:45 2016 +0300
+++ b/test/tools/launcher/modules/limitmods/LimitModsTest.java	Mon Apr 25 09:25:26 2016 -0700
@@ -103,10 +103,9 @@
     public void testWithAddMods() throws Exception {
         int exitValue;
 
-        // java -limitmods java.base -addmods java.logging,jdk.unsupported -listmods
+        // java -limitmods java.base -addmods java.logging -listmods
         exitValue = executeTestJava("-limitmods", "java.base",
-                                    "-addmods",
-                                    "java.logging,jdk.unsupported",  // TODO: add bug No.
+                                    "-addmods", "java.logging",
                                     "-listmods")
             .outputTo(System.out)
             .errorTo(System.out)
--- a/test/tools/lib/tests/JImageGenerator.java	Mon Apr 25 18:07:45 2016 +0300
+++ b/test/tools/lib/tests/JImageGenerator.java	Mon Apr 25 09:25:26 2016 -0700
@@ -553,10 +553,6 @@
         public Result extract() {
             return cmd("extract", dir);
         }
-
-        public Result recreate() {
-            return cmd("recreate", image);
-        }
     }
 
     public static class JLinkTask {