Merge
authorprr
Tue, 21 Mar 2017 08:48:14 -0700
changeset 44355 bca217cee0d0
parent 44354 a99429b721a9 (current diff)
parent 44336 9688370d8b66 (diff)
child 44356 5661993f0555
Merge
--- a/jdk/.hgtags	Thu Mar 16 22:03:08 2017 +0300
+++ b/jdk/.hgtags	Tue Mar 21 08:48:14 2017 -0700
@@ -403,3 +403,4 @@
 c476ca73750698fa5654e101af699ee45db38e2a jdk-9+158
 49b54a4d9e84b7ba956b8c27fced5035465146ae jdk-9+159
 cac788454598b95d8b0153c021a7fae3cd7e6fda jdk-9+160
+09b92d3067a38ee07bc14efa336b14790c93f7e7 jdk-9+161
--- a/jdk/src/java.base/share/classes/java/lang/Class.java	Thu Mar 16 22:03:08 2017 +0300
+++ b/jdk/src/java.base/share/classes/java/lang/Class.java	Tue Mar 21 08:48:14 2017 -0700
@@ -2771,7 +2771,7 @@
          * In all other cases, it requires RuntimePermission("accessDeclaredMembers")
          * permission.
          */
-        final ClassLoader ccl = caller.getClassLoader0();
+        final ClassLoader ccl = ClassLoader.getClassLoader(caller);
         if (which != Member.PUBLIC) {
             final ClassLoader cl = getClassLoader0();
             if (ccl != cl) {
--- a/jdk/src/java.base/share/classes/java/lang/ProcessHandleImpl.java	Thu Mar 16 22:03:08 2017 +0300
+++ b/jdk/src/java.base/share/classes/java/lang/ProcessHandleImpl.java	Tue Mar 21 08:48:14 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,6 +24,7 @@
  */
 package java.lang;
 
+import java.lang.annotation.Native;
 import java.security.PrivilegedAction;
 import java.time.Duration;
 import java.time.Instant;
@@ -57,6 +58,12 @@
     private static long REAPER_DEFAULT_STACKSIZE = 128 * 1024;
 
     /**
+     * Return value from waitForProcessExit0 indicating the process is not a child.
+     */
+    @Native
+    private static final int NOT_A_CHILD = -2;
+
+    /**
      * Cache the ProcessHandle of this process.
      */
     private static final ProcessHandleImpl current;
@@ -131,6 +138,29 @@
                 // spawn a thread to wait for and deliver the exit value
                 processReaperExecutor.execute(() -> {
                     int exitValue = waitForProcessExit0(pid, shouldReap);
+                    if (exitValue == NOT_A_CHILD) {
+                        // pid not alive or not a child of this process
+                        // If it is alive wait for it to terminate
+                        long sleep = 300;     // initial milliseconds to sleep
+                        int incr = 30;        // increment to the sleep time
+
+                        long startTime = isAlive0(pid);
+                        long origStart = startTime;
+                        while (startTime >= 0) {
+                            try {
+                                Thread.sleep(Math.min(sleep, 5000L)); // no more than 5 sec
+                                sleep += incr;
+                            } catch (InterruptedException ie) {
+                                // ignore and retry
+                            }
+                            startTime = isAlive0(pid);  // recheck if is alive
+                            if (origStart > 0 && startTime != origStart) {
+                                // start time changed, pid is not the same process
+                                break;
+                            }
+                        }
+                        exitValue = 0;
+                    }
                     newCompletion.complete(exitValue);
                     // remove from cache afterwards
                     completions.remove(pid, newCompletion);
--- a/jdk/src/java.base/share/classes/java/lang/Runtime.java	Thu Mar 16 22:03:08 2017 +0300
+++ b/jdk/src/java.base/share/classes/java/lang/Runtime.java	Tue Mar 21 08:48:14 2017 -0700
@@ -1337,14 +1337,12 @@
             int oSize = ob.version().size();
             int min = Math.min(size, oSize);
             for (int i = 0; i < min; i++) {
-                Integer val = version.get(i);
-                Integer oVal = ob.version().get(i);
+                int val = version.get(i);
+                int oVal = ob.version().get(i);
                 if (val != oVal)
                     return val - oVal;
             }
-            if (size != oSize)
-                return size - oSize;
-            return 0;
+            return size - oSize;
         }
 
         private int comparePre(Version ob) {
--- a/jdk/src/java.base/share/classes/java/util/Date.java	Thu Mar 16 22:03:08 2017 +0300
+++ b/jdk/src/java.base/share/classes/java/util/Date.java	Tue Mar 21 08:48:14 2017 -0700
@@ -728,7 +728,6 @@
      * @see     java.util.Calendar
      * @deprecated As of JDK version 1.1,
      * replaced by {@code Calendar.get(Calendar.DAY_OF_MONTH)}.
-     * @deprecated
      */
     @Deprecated
     public int getDate() {
--- a/jdk/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c	Thu Mar 16 22:03:08 2017 +0300
+++ b/jdk/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c	Tue Mar 21 08:48:14 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -244,7 +244,8 @@
         int status;
         while (waitpid(pid, &status, 0) < 0) {
             switch (errno) {
-                case ECHILD: return 0;
+                case ECHILD:
+                    return java_lang_ProcessHandleImpl_NOT_A_CHILD; // No child
                 case EINTR: break;
                 default: return -1;
             }
@@ -269,9 +270,10 @@
         memset(&siginfo, 0, sizeof siginfo);
         while (waitid(P_PID, pid, &siginfo, options) < 0) {
             switch (errno) {
-            case ECHILD: return 0;
-            case EINTR: break;
-            default: return -1;
+                case ECHILD:
+                    return java_lang_ProcessHandleImpl_NOT_A_CHILD; // No child
+                case EINTR: break;
+                default: return -1;
             }
         }
 
--- a/jdk/src/java.transaction/share/classes/module-info.java	Thu Mar 16 22:03:08 2017 +0300
+++ b/jdk/src/java.transaction/share/classes/module-info.java	Tue Mar 21 08:48:14 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,6 +31,7 @@
  *
  * @since 9
  */
+@Deprecated(since="9", forRemoval=true)
 module java.transaction {
     requires transitive java.rmi;
     exports javax.transaction;
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java	Thu Mar 16 22:03:08 2017 +0300
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java	Tue Mar 21 08:48:14 2017 -0700
@@ -95,7 +95,7 @@
                     tool.xflag = true;
                 }
             },
-            new Option(false, OptionType.MAIN_OPERATION, "--print-module-descriptor", "-d") {
+            new Option(false, OptionType.MAIN_OPERATION, "--describe-module", "-d") {
                 void process(Main tool, String opt, String arg) throws BadArgs {
                     if (tool.cflag || tool.iflag  || tool.tflag || tool.uflag || tool.xflag)
                         throw new BadArgs("error.multiple.main.operations").showUsage(true);
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java	Thu Mar 16 22:03:08 2017 +0300
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java	Tue Mar 21 08:48:14 2017 -0700
@@ -27,6 +27,7 @@
 
 import java.io.*;
 import java.lang.module.Configuration;
+import java.lang.module.FindException;
 import java.lang.module.InvalidModuleDescriptorException;
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleDescriptor.Exports;
@@ -407,11 +408,11 @@
                 boolean found;
                 if (fname != null) {
                     try (ZipFile zf = new ZipFile(fname)) {
-                        found = printModuleDescriptor(zf);
+                        found = describeModule(zf);
                     }
                 } else {
                     try (FileInputStream fin = new FileInputStream(FileDescriptor.in)) {
-                        found = printModuleDescriptor(fin);
+                        found = describeModule(fin);
                     }
                 }
                 if (!found)
@@ -603,7 +604,7 @@
         int n = args.length - count;
         if (n > 0) {
             if (dflag) {
-                // "--print-module-descriptor/-d" does not require file argument(s)
+                // "--describe-module/-d" does not require file argument(s)
                 usageError(formatMsg("error.bad.dflag", args[count]));
                 return false;
             }
@@ -1728,24 +1729,43 @@
                            .collect(joining(", ", prefix, suffix));
     }
 
-    private boolean printModuleDescriptor(ZipFile zipFile)
-        throws IOException
-    {
+    private boolean describeModule(ZipFile zipFile) throws IOException {
         ZipEntry[] zes = zipFile.stream()
             .filter(e -> isModuleInfoEntry(e.getName()))
             .sorted(Validator.ENTRY_COMPARATOR)
             .toArray(ZipEntry[]::new);
-        if (zes.length == 0)
-            return false;
-        for (ZipEntry ze : zes) {
-            try (InputStream is = zipFile.getInputStream(ze)) {
-                printModuleDescriptor(is, ze.getName());
+
+        if (zes.length == 0) {
+            // No module descriptor found, derive the automatic module name
+            String fn = zipFile.getName();
+            ModuleFinder mf = ModuleFinder.of(Paths.get(fn));
+            try {
+                Set<ModuleReference> mref = mf.findAll();
+                if (mref.isEmpty()) {
+                    output(formatMsg("error.unable.derive.automodule", fn));
+                    return true;
+                }
+                ModuleDescriptor md = mref.iterator().next().descriptor();
+                output(getMsg("out.automodule"));
+                describeModule(md, null, "automatic");
+            } catch (FindException e) {
+                String msg = formatMsg("error.unable.derive.automodule", fn);
+                Throwable t = e.getCause();
+                if (t != null)
+                    msg = msg + "\n" + t.getMessage();
+                output(msg);
+            }
+        } else {
+            for (ZipEntry ze : zes) {
+                try (InputStream is = zipFile.getInputStream(ze)) {
+                    describeModule(is, ze.getName());
+                }
             }
         }
         return true;
     }
 
-    private boolean printModuleDescriptor(FileInputStream fis)
+    private boolean describeModule(FileInputStream fis)
         throws IOException
     {
         try (BufferedInputStream bis = new BufferedInputStream(fis);
@@ -1764,7 +1784,7 @@
             .sorted(Validator.ENTRYNAME_COMPARATOR)
             .toArray(String[]::new);
         for (String name : names) {
-            printModuleDescriptor(new ByteArrayInputStream(moduleInfos.get(name)), name);
+            describeModule(new ByteArrayInputStream(moduleInfos.get(name)), name);
         }
         return true;
     }
@@ -1775,13 +1795,21 @@
                   .collect(joining(" "));
     }
 
-    private void printModuleDescriptor(InputStream entryInputStream, String ename)
+    private void describeModule(InputStream entryInputStream, String ename)
         throws IOException
     {
         ModuleInfo.Attributes attrs = ModuleInfo.read(entryInputStream, null);
         ModuleDescriptor md = attrs.descriptor();
         ModuleHashes hashes = attrs.recordedHashes();
 
+        describeModule(md, hashes, ename);
+    }
+
+    private void describeModule(ModuleDescriptor md,
+                                ModuleHashes hashes,
+                                String ename)
+        throws IOException
+    {
         StringBuilder sb = new StringBuilder();
         sb.append("\nmodule ")
           .append(md.toNameAndVersion())
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties	Thu Mar 16 22:03:08 2017 +0300
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties	Tue Mar 21 08:48:14 2017 -0700
@@ -45,7 +45,7 @@
 	'e' flag and manifest with the 'Main-Class' attribute cannot be specified \n\
 	 together!
 error.bad.dflag=\
-        '-d, --print-module-descriptor' option requires no input file(s) to be specified: {0}
+        '-d, --describe-module' option requires no input file(s) to be specified: {0}
 error.bad.reason=\
         bad reason: {0}, must be one of deprecated, deprecated-for-removal, or incubating
 error.nosuch.fileordir=\
@@ -62,6 +62,8 @@
         Hashing module {0} dependences, unable to find module {1} on module path
 error.module.options.without.info=\
         One of --module-version or --hash-modules without module-info.class
+error.unable.derive.automodule=\
+        Unable to derive module descriptor for: {0}
 error.unexpected.module-info=\
         Unexpected module descriptor {0}
 error.module.descriptor.not.found=\
@@ -129,6 +131,8 @@
         added manifest
 out.added.module-info=\
         added module-info: {0}
+out.automodule=\
+        No module descriptor found. Derived automatic module.
 out.update.manifest=\
         updated manifest
 out.update.module-info=\
@@ -224,8 +228,8 @@
 \  -u, --update               Update an existing jar archive
 main.help.opt.main.extract=\
 \  -x, --extract              Extract named (or all) files from the archive
-main.help.opt.main.print-module-descriptor=\
-\  -d, --print-module-descriptor  Print the module descriptor
+main.help.opt.main.describe-module=\
+\  -d, --describe-module      Print the module descriptor, or automatic module name
 main.help.opt.any=\
 \ Operation modifiers valid in any mode:\n\
 \n\
--- a/jdk/test/TEST.groups	Thu Mar 16 22:03:08 2017 +0300
+++ b/jdk/test/TEST.groups	Tue Mar 21 08:48:14 2017 -0700
@@ -28,8 +28,6 @@
 tier1 = \
     :jdk_lang \
     :jdk_util \
-    -java/util/concurrent/ThreadPoolExecutor/ConfigChanges.java \
-    -java/util/concurrent/forkjoin/FJExceptionTableLeak.java \
     sun/nio/cs/ISO8859x.java \
     java/nio/Buffer \
     com/sun/crypto/provider/Cipher \
@@ -37,8 +35,6 @@
     tools/pack200
 
 tier2 = \
-    java/util/concurrent/ThreadPoolExecutor/ConfigChanges.java \
-    java/util/concurrent/forkjoin/FJExceptionTableLeak.java \
     :jdk_io \
     :jdk_nio \
     -sun/nio/cs/ISO8859x.java \
--- a/jdk/test/java/lang/ProcessHandle/JavaChild.java	Thu Mar 16 22:03:08 2017 +0300
+++ b/jdk/test/java/lang/ProcessHandle/JavaChild.java	Tue Mar 21 08:48:14 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,7 +28,6 @@
 import java.io.InputStreamReader;
 import java.io.BufferedReader;
 import java.io.IOException;
-import java.io.PrintStream;
 import java.io.Reader;
 import java.io.PrintWriter;
 import java.lang.InterruptedException;
@@ -39,9 +38,11 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.Optional;
 import java.util.function.Consumer;
 
 
@@ -437,6 +438,11 @@
                     case "threaddump":
                         Thread.dumpStack();
                         break;
+                    case "waitpid":
+                        long pid = Long.parseLong(args[nextArg++]);
+                        Optional<String> s = ProcessHandle.of(pid).map(ph -> waitAlive(ph));
+                        sendResult(action, s.orElse("pid not valid: " + pid));
+                        break;
                     default:
                         throw new Error("JavaChild action unknown: " + action);
                 }
@@ -447,6 +453,17 @@
         }
     }
 
+    private static String waitAlive(ProcessHandle ph) {
+        String status;
+        try {
+            boolean isAlive = ph.onExit().get().isAlive();
+            status = Boolean.toString(isAlive);
+        } catch (InterruptedException | ExecutionException ex ) {
+            status = "interrupted";
+        }
+        return status;
+    }
+
     static synchronized void sendRaw(String s) {
         System.out.println(s);
         System.out.flush();
@@ -476,6 +493,7 @@
         System.err.println("  spawn <n> command... - spawn n new children and send command");
         System.err.println("  child command... - send command to all live children");
         System.err.println("  child_eof - send eof to all live children");
+        System.err.println("  waitpid <pid> - wait for the pid to exit");
         System.err.println("  exit <exitcode>");
         System.err.println("  out arg...");
         System.err.println("  err arg...");
--- a/jdk/test/java/lang/ProcessHandle/OnExitTest.java	Thu Mar 16 22:03:08 2017 +0300
+++ b/jdk/test/java/lang/ProcessHandle/OnExitTest.java	Tue Mar 21 08:48:14 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,9 +26,11 @@
 import java.time.Instant;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
 
 import jdk.test.lib.Utils;
 
@@ -196,4 +198,95 @@
         }
     }
 
+    /**
+     * Verify that onExit completes for a non-child process only when
+     * the process has exited.
+     * Spawn a child (A) waiting to be commanded to exit.
+     * Spawn a child (B) to wait for that process to exit.
+     * Command (A) to exit.
+     * Check that (B) does not complete until (A) has exited.
+     */
+    @Test
+    public static void peerOnExitTest() {
+        String line = null;
+        ArrayBlockingQueue<String> alines = new ArrayBlockingQueue<>(100);
+        ArrayBlockingQueue<String> blines = new ArrayBlockingQueue<>(100);
+        JavaChild A = null;
+        try {
+            String[] split;
+            A = JavaChild.spawnJavaChild("stdin");
+            A.forEachOutputLine(l -> alines.add(l));
+
+            // Verify A is running
+            A.sendAction("pid");
+            do {
+                split = getSplitLine(alines);
+            } while (!"pid".equals(split[1]));
+
+            JavaChild B = null;
+            try {
+                B = JavaChild.spawnJavaChild("stdin");
+                B.forEachOutputLine(l -> blines.add(l));
+
+                // Verify B is running
+                B.sendAction("pid");
+                do {
+                    split = getSplitLine(blines);
+                } while (!"pid".equals(split[1]));
+
+                // Tell B to wait for A's pid
+                B.sendAction("waitpid", A.getPid());
+
+                // Wait a bit to see if B will prematurely report the termination of A
+                try {
+                    line = blines.poll(5L, TimeUnit.SECONDS);
+                } catch (InterruptedException ie) {
+                    Assert.fail("interrupted", ie);
+                }
+                Assert.assertNull(line, "waitpid didn't wait");
+
+                A.sendAction("exit", 0L);
+
+                // Look for B to report that A has exited
+                do {
+                    split = getSplitLine(blines);
+                } while (!"waitpid".equals(split[1]));
+
+                Assert.assertEquals(split[2], "false",  "Process A should not be alive");
+
+                B.sendAction("exit", 0L);
+            } catch (IOException ioe) {
+                Assert.fail("unable to start JavaChild B", ioe);
+            } finally {
+                B.destroyForcibly();
+            }
+        } catch (IOException ioe2) {
+            Assert.fail("unable to start JavaChild A", ioe2);
+        } finally {
+            A.destroyForcibly();
+        }
+    }
+
+    private static boolean DEBUG = true;
+
+    /**
+     * Get a line from the queue and split into words on whitespace.
+     * Log to stdout if requested.
+     * @param queue a queue of strings
+     * @return the words split from the line.
+     */
+    private static String[] getSplitLine(ArrayBlockingQueue<String> queue) {
+        try {
+            String line = queue.take();
+            String[] split = line.split("\\s");
+            if (DEBUG) {
+                System.out.printf("  Child Output: %s%n", line);
+            }
+            return split;
+        } catch (InterruptedException ie) {
+            Assert.fail("interrupted", ie);
+            return null;
+        }
+    }
+
 }
--- a/jdk/test/java/lang/Runtime/Version/Basic.java	Thu Mar 16 22:03:08 2017 +0300
+++ b/jdk/test/java/lang/Runtime/Version/Basic.java	Tue Mar 21 08:48:14 2017 -0700
@@ -129,6 +129,9 @@
         testEHC("9",          "10",               false, false, -1,   -1);
         testEHC("9",          "8",                false, false,  1,    1);
 
+        testEHC("10.512.1",   "10.512.2",         false, false, -1,   -1);
+        testEHC("512.10.1",   "512.11.1",         false, false, -1,   -1);
+
         // $OPT comparison
         testEHC("9",          "9+-oink",          false, true,  -1,    0);
         testEHC("9+-ribbit",  "9+-moo",           false, true,   1,    0);
--- a/jdk/test/java/nio/channels/FileChannel/Transfer.java	Thu Mar 16 22:03:08 2017 +0300
+++ b/jdk/test/java/nio/channels/FileChannel/Transfer.java	Tue Mar 21 08:48:14 2017 -0700
@@ -22,8 +22,7 @@
  */
 
 /* @test
- * @bug 4434723 4482726 4559072 4638365 4795550 5081340 5103988 6253145
- *   6984545
+ * @bug 4434723 4482726 4559072 4795550 5081340 5103988 6984545
  * @key intermittent
  * @summary Test FileChannel.transferFrom and transferTo (use -Dseed=X to set PRNG seed)
  * @library ..
@@ -34,18 +33,13 @@
  */
 
 import java.io.BufferedReader;
-import java.io.BufferedWriter;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.InputStreamReader;
 import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.PrintStream;
 import java.io.RandomAccessFile;
 import java.io.Reader;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.nio.ByteBuffer;
@@ -55,8 +49,6 @@
 import java.nio.channels.ServerSocketChannel;
 import java.nio.channels.SocketChannel;
 import java.nio.channels.spi.SelectorProvider;
-import java.nio.file.StandardOpenOption;
-import java.nio.file.FileAlreadyExistsException;
 import java.util.Random;
 import java.util.concurrent.TimeUnit;
 
@@ -67,8 +59,6 @@
 public class Transfer {
 
     private static Random generator = RandomFactory.getRandom();
-    private static PrintStream err = System.err;
-    private static PrintStream out = System.out;
 
     @Test
     public void testFileChannel() throws Exception {
@@ -242,116 +232,7 @@
         dest.delete();
     }
 
-    // Test transferTo with large file
-    @Test
-    public void xferTest04() throws Exception { // for bug 4638365
-        // Windows and Linux can't handle the really large file sizes for a
-        // truncate or a positional write required by the test for 4563125
-        String osName = System.getProperty("os.name");
-        if (!(osName.startsWith("SunOS") || osName.contains("OS X")))
-            return;
-        File source = File.createTempFile("blah", null);
-        source.deleteOnExit();
-        long testSize = ((long)Integer.MAX_VALUE) * 2;
-        initTestFile(source, 10);
-        RandomAccessFile raf = new RandomAccessFile(source, "rw");
-        FileChannel fc = raf.getChannel();
-        out.println("  Writing large file...");
-        long t0 = System.nanoTime();
-        fc.write(ByteBuffer.wrap("Use the source!".getBytes()), testSize - 40);
-        long t1 = System.nanoTime();
-        out.printf("  Wrote large file in %d ns (%d ms) %n",
-            t1 - t0, TimeUnit.NANOSECONDS.toMillis(t1 - t0));
-
-        fc.close();
-        raf.close();
-
-        File sink = File.createTempFile("sink", null);
-        sink.deleteOnExit();
-
-        FileInputStream fis = new FileInputStream(source);
-        FileChannel sourceChannel = fis.getChannel();
-
-        raf = new RandomAccessFile(sink, "rw");
-        FileChannel sinkChannel = raf.getChannel();
-
-        long bytesWritten = sourceChannel.transferTo(testSize -40, 10,
-                                                     sinkChannel);
-        if (bytesWritten != 10) {
-            throw new RuntimeException("Transfer test 4 failed " +
-                                       bytesWritten);
-        }
-        sourceChannel.close();
-        sinkChannel.close();
-
-        source.delete();
-        sink.delete();
-    }
-
-    // Test transferFrom with large file
-    @Test
-    public void xferTest05() throws Exception { // for bug 4638365
-        // Create a source file & large sink file for the test
-        File source = File.createTempFile("blech", null);
-        source.deleteOnExit();
-        initTestFile(source, 100);
-
-        // Create the sink file as a sparse file if possible
-        File sink = null;
-        FileChannel fc = null;
-        while (fc == null) {
-            sink = File.createTempFile("sink", null);
-            // re-create as a sparse file
-            sink.delete();
-            try {
-                fc = FileChannel.open(sink.toPath(),
-                                      StandardOpenOption.CREATE_NEW,
-                                      StandardOpenOption.WRITE,
-                                      StandardOpenOption.SPARSE);
-            } catch (FileAlreadyExistsException ignore) {
-                // someone else got it
-            }
-        }
-        sink.deleteOnExit();
-
-        long testSize = ((long)Integer.MAX_VALUE) * 2;
-        try {
-            out.println("  Writing large file...");
-            long t0 = System.nanoTime();
-            fc.write(ByteBuffer.wrap("Use the source!".getBytes()),
-                     testSize - 40);
-            long t1 = System.nanoTime();
-            out.printf("  Wrote large file in %d ns (%d ms) %n",
-            t1 - t0, TimeUnit.NANOSECONDS.toMillis(t1 - t0));
-        } catch (IOException e) {
-            // Can't set up the test, abort it
-            err.println("xferTest05 was aborted.");
-            return;
-        } finally {
-            fc.close();
-        }
-
-        // Get new channels for the source and sink and attempt transfer
-        FileChannel sourceChannel = new FileInputStream(source).getChannel();
-        try {
-            FileChannel sinkChannel = new RandomAccessFile(sink, "rw").getChannel();
-            try {
-                long bytesWritten = sinkChannel.transferFrom(sourceChannel,
-                                                             testSize - 40, 10);
-                if (bytesWritten != 10) {
-                    throw new RuntimeException("Transfer test 5 failed " +
-                                               bytesWritten);
-                }
-            } finally {
-                sinkChannel.close();
-            }
-        } finally {
-            sourceChannel.close();
-        }
-
-        source.delete();
-        sink.delete();
-    }
+    // xferTest04() and xferTest05() moved to Transfer4GBFile.java
 
     static void checkFileData(File file, String expected) throws Exception {
         FileInputStream fis = new FileInputStream(file);
@@ -436,118 +317,7 @@
         source.delete();
     }
 
-
-    // Test transferTo with file positions larger than 2 and 4GB
-    @Test
-    public void xferTest08() throws Exception { // for bug 6253145
-        // Creating a sparse 6GB file on Windows takes too long
-        String osName = System.getProperty("os.name");
-        if (osName.startsWith("Windows"))
-            return;
-
-        final long G = 1024L * 1024L * 1024L;
-
-        // Create 6GB file
-
-        File file = File.createTempFile("source", null);
-        file.deleteOnExit();
-
-        RandomAccessFile raf = new RandomAccessFile(file, "rw");
-        FileChannel fc = raf.getChannel();
-
-        out.println("  Writing large file...");
-        long t0 = System.nanoTime();
-        try {
-            fc.write(ByteBuffer.wrap("0123456789012345".getBytes("UTF-8")), 6*G);
-            long t1 = System.nanoTime();
-            out.printf("  Wrote large file in %d ns (%d ms) %n",
-            t1 - t0, TimeUnit.NANOSECONDS.toMillis(t1 - t0));
-        } catch (IOException x) {
-            err.println("  Unable to create test file:" + x);
-            fc.close();
-            return;
-        }
-
-        // Setup looback connection and echo server
-
-        ServerSocketChannel ssc = ServerSocketChannel.open();
-        ssc.socket().bind(new InetSocketAddress(0));
-
-        InetAddress lh = InetAddress.getLocalHost();
-        InetSocketAddress isa = new InetSocketAddress(lh, ssc.socket().getLocalPort());
-        SocketChannel source = SocketChannel.open(isa);
-        SocketChannel sink = ssc.accept();
-
-        Thread thr = new Thread(new EchoServer(sink));
-        thr.start();
-
-        // Test data is array of positions and counts
-
-        long testdata[][] = {
-            { 2*G-1,    1 },
-            { 2*G-1,    10 },       // across 2GB boundary
-            { 2*G,      1 },
-            { 2*G,      10 },
-            { 2*G+1,    1 },
-            { 4*G-1,    1 },
-            { 4*G-1,    10 },       // across 4GB boundary
-            { 4*G,      1 },
-            { 4*G,      10 },
-            { 4*G+1,    1 },
-            { 5*G-1,    1 },
-            { 5*G-1,    10 },
-            { 5*G,      1 },
-            { 5*G,      10 },
-            { 5*G+1,    1 },
-            { 6*G,      1 },
-        };
-
-        ByteBuffer sendbuf = ByteBuffer.allocateDirect(100);
-        ByteBuffer readbuf = ByteBuffer.allocateDirect(100);
-
-        try {
-            byte value = 0;
-            for (int i=0; i<testdata.length; i++) {
-                long position = testdata[(int)i][0];
-                long count = testdata[(int)i][1];
-
-                // generate bytes
-                for (long j=0; j<count; j++) {
-                    sendbuf.put(++value);
-                }
-                sendbuf.flip();
-
-                // write to file and transfer to echo server
-                fc.write(sendbuf, position);
-                t0 = System.nanoTime();
-                fc.transferTo(position, count, source);
-                out.printf("  transferTo(%d, %2d, source): %d ns%n",
-                    position, count, System.nanoTime() - t0);
-
-                // read from echo server
-                long nread = 0;
-                while (nread < count) {
-                    int n = source.read(readbuf);
-                    if (n < 0)
-                        throw new RuntimeException("Premature EOF!");
-                    nread += n;
-                }
-
-                // check reply from echo server
-                readbuf.flip();
-                sendbuf.flip();
-                if (!readbuf.equals(sendbuf))
-                    throw new RuntimeException("Echoed bytes do not match!");
-                readbuf.clear();
-                sendbuf.clear();
-            }
-        } finally {
-            source.close();
-            ssc.close();
-            fc.close();
-            file.delete();
-        }
-    }
+    // xferTest08() moved to TransferTo6GBFile.java
 
     // Test that transferFrom with FileChannel source that is not readable
     // throws NonReadableChannelException
@@ -570,56 +340,4 @@
             fc2.close();
         }
     }
-
-    /**
-     * Creates file blah of specified size in bytes.
-     */
-    private static void initTestFile(File blah, long size) throws Exception {
-        if (blah.exists())
-            blah.delete();
-        FileOutputStream fos = new FileOutputStream(blah);
-        BufferedWriter awriter
-            = new BufferedWriter(new OutputStreamWriter(fos, "8859_1"));
-
-        for(int i=0; i<size; i++) {
-            awriter.write("e");
-        }
-        awriter.flush();
-        awriter.close();
-    }
-
-    /**
-     * Simple in-process server to echo bytes read by a given socket channel
-     */
-    static class EchoServer implements Runnable {
-        private SocketChannel sc;
-
-        public EchoServer(SocketChannel sc) {
-            this.sc = sc;
-        }
-
-        public void run() {
-            ByteBuffer bb = ByteBuffer.allocateDirect(1024);
-            try {
-                for (;;) {
-                    int n = sc.read(bb);
-                    if (n < 0)
-                        break;
-
-                    bb.flip();
-                    while (bb.remaining() > 0) {
-                        sc.write(bb);
-                    }
-                    bb.clear();
-                }
-            } catch (IOException x) {
-                x.printStackTrace();
-            } finally {
-                try {
-                    sc.close();
-                } catch (IOException ignore) { }
-            }
-        }
-    }
-
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/channels/FileChannel/Transfer4GBFile.java	Tue Mar 21 08:48:14 2017 -0700
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 4638365
+ * @key intermittent
+ * @summary Test FileChannel.transferFrom and transferTo for 4GB files
+ * @run testng/timeout=300 Transfer4GBFile
+ */
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintStream;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.file.StandardOpenOption;
+import java.nio.file.FileAlreadyExistsException;
+import java.util.concurrent.TimeUnit;
+
+import org.testng.annotations.Test;
+
+public class Transfer4GBFile {
+
+    private static PrintStream err = System.err;
+    private static PrintStream out = System.out;
+
+    // Test transferTo with large file
+    @Test
+    public void xferTest04() throws Exception { // for bug 4638365
+        // Windows and Linux can't handle the really large file sizes for a
+        // truncate or a positional write required by the test for 4563125
+        String osName = System.getProperty("os.name");
+        if (!(osName.startsWith("SunOS") || osName.contains("OS X")))
+            return;
+        File source = File.createTempFile("blah", null);
+        source.deleteOnExit();
+        long testSize = ((long)Integer.MAX_VALUE) * 2;
+        initTestFile(source, 10);
+        RandomAccessFile raf = new RandomAccessFile(source, "rw");
+        FileChannel fc = raf.getChannel();
+        out.println("  Writing large file...");
+        long t0 = System.nanoTime();
+        fc.write(ByteBuffer.wrap("Use the source!".getBytes()), testSize - 40);
+        long t1 = System.nanoTime();
+        out.printf("  Wrote large file in %d ns (%d ms) %n",
+            t1 - t0, TimeUnit.NANOSECONDS.toMillis(t1 - t0));
+
+        fc.close();
+        raf.close();
+
+        File sink = File.createTempFile("sink", null);
+        sink.deleteOnExit();
+
+        FileInputStream fis = new FileInputStream(source);
+        FileChannel sourceChannel = fis.getChannel();
+
+        raf = new RandomAccessFile(sink, "rw");
+        FileChannel sinkChannel = raf.getChannel();
+
+        long bytesWritten = sourceChannel.transferTo(testSize -40, 10,
+                                                     sinkChannel);
+        if (bytesWritten != 10) {
+            throw new RuntimeException("Transfer test 4 failed " +
+                                       bytesWritten);
+        }
+        sourceChannel.close();
+        sinkChannel.close();
+
+        source.delete();
+        sink.delete();
+    }
+
+    // Test transferFrom with large file
+    @Test
+    public void xferTest05() throws Exception { // for bug 4638365
+        // Create a source file & large sink file for the test
+        File source = File.createTempFile("blech", null);
+        source.deleteOnExit();
+        initTestFile(source, 100);
+
+        // Create the sink file as a sparse file if possible
+        File sink = null;
+        FileChannel fc = null;
+        while (fc == null) {
+            sink = File.createTempFile("sink", null);
+            // re-create as a sparse file
+            sink.delete();
+            try {
+                fc = FileChannel.open(sink.toPath(),
+                                      StandardOpenOption.CREATE_NEW,
+                                      StandardOpenOption.WRITE,
+                                      StandardOpenOption.SPARSE);
+            } catch (FileAlreadyExistsException ignore) {
+                // someone else got it
+            }
+        }
+        sink.deleteOnExit();
+
+        long testSize = ((long)Integer.MAX_VALUE) * 2;
+        try {
+            out.println("  Writing large file...");
+            long t0 = System.nanoTime();
+            fc.write(ByteBuffer.wrap("Use the source!".getBytes()),
+                     testSize - 40);
+            long t1 = System.nanoTime();
+            out.printf("  Wrote large file in %d ns (%d ms) %n",
+            t1 - t0, TimeUnit.NANOSECONDS.toMillis(t1 - t0));
+        } catch (IOException e) {
+            // Can't set up the test, abort it
+            err.println("xferTest05 was aborted.");
+            return;
+        } finally {
+            fc.close();
+        }
+
+        // Get new channels for the source and sink and attempt transfer
+        FileChannel sourceChannel = new FileInputStream(source).getChannel();
+        try {
+            FileChannel sinkChannel = new RandomAccessFile(sink, "rw").getChannel();
+            try {
+                long bytesWritten = sinkChannel.transferFrom(sourceChannel,
+                                                             testSize - 40, 10);
+                if (bytesWritten != 10) {
+                    throw new RuntimeException("Transfer test 5 failed " +
+                                               bytesWritten);
+                }
+            } finally {
+                sinkChannel.close();
+            }
+        } finally {
+            sourceChannel.close();
+        }
+
+        source.delete();
+        sink.delete();
+    }
+
+    /**
+     * Creates file blah of specified size in bytes.
+     */
+    private static void initTestFile(File blah, long size) throws Exception {
+        if (blah.exists())
+            blah.delete();
+        FileOutputStream fos = new FileOutputStream(blah);
+        BufferedWriter awriter
+            = new BufferedWriter(new OutputStreamWriter(fos, "8859_1"));
+
+        for(int i=0; i<size; i++) {
+            awriter.write("e");
+        }
+        awriter.flush();
+        awriter.close();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/channels/FileChannel/TransferTo6GBFile.java	Tue Mar 21 08:48:14 2017 -0700
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 6253145
+ * @key intermittent
+ * @summary Test FileChannel.transferTo with file positions up to 8GB
+ * @run testng/timeout=300 TransferTo6GBFile
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.RandomAccessFile;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.util.concurrent.TimeUnit;
+
+import org.testng.annotations.Test;
+
+public class TransferTo6GBFile {
+
+    private static PrintStream err = System.err;
+    private static PrintStream out = System.out;
+
+    // Test transferTo with file positions larger than 2 and 4GB
+    @Test
+    public void xferTest08() throws Exception { // for bug 6253145
+        // Creating a sparse 6GB file on Windows takes too long
+        String osName = System.getProperty("os.name");
+        if (osName.startsWith("Windows"))
+            return;
+
+        final long G = 1024L * 1024L * 1024L;
+
+        // Create 6GB file
+
+        File file = File.createTempFile("source", null);
+        file.deleteOnExit();
+
+        RandomAccessFile raf = new RandomAccessFile(file, "rw");
+        FileChannel fc = raf.getChannel();
+
+        out.println("  Writing large file...");
+        long t0 = System.nanoTime();
+        try {
+            fc.write(ByteBuffer.wrap("0123456789012345".getBytes("UTF-8")), 6*G);
+            long t1 = System.nanoTime();
+            out.printf("  Wrote large file in %d ns (%d ms) %n",
+            t1 - t0, TimeUnit.NANOSECONDS.toMillis(t1 - t0));
+        } catch (IOException x) {
+            err.println("  Unable to create test file:" + x);
+            fc.close();
+            return;
+        }
+
+        // Setup looback connection and echo server
+
+        ServerSocketChannel ssc = ServerSocketChannel.open();
+        ssc.socket().bind(new InetSocketAddress(0));
+
+        InetAddress lh = InetAddress.getLocalHost();
+        InetSocketAddress isa = new InetSocketAddress(lh, ssc.socket().getLocalPort());
+        SocketChannel source = SocketChannel.open(isa);
+        SocketChannel sink = ssc.accept();
+
+        Thread thr = new Thread(new EchoServer(sink));
+        thr.start();
+
+        // Test data is array of positions and counts
+
+        long testdata[][] = {
+            { 2*G-1,    1 },
+            { 2*G-1,    10 },       // across 2GB boundary
+            { 2*G,      1 },
+            { 2*G,      10 },
+            { 2*G+1,    1 },
+            { 4*G-1,    1 },
+            { 4*G-1,    10 },       // across 4GB boundary
+            { 4*G,      1 },
+            { 4*G,      10 },
+            { 4*G+1,    1 },
+            { 5*G-1,    1 },
+            { 5*G-1,    10 },
+            { 5*G,      1 },
+            { 5*G,      10 },
+            { 5*G+1,    1 },
+            { 6*G,      1 },
+        };
+
+        ByteBuffer sendbuf = ByteBuffer.allocateDirect(100);
+        ByteBuffer readbuf = ByteBuffer.allocateDirect(100);
+
+        try {
+            byte value = 0;
+            for (int i=0; i<testdata.length; i++) {
+                long position = testdata[(int)i][0];
+                long count = testdata[(int)i][1];
+
+                // generate bytes
+                for (long j=0; j<count; j++) {
+                    sendbuf.put(++value);
+                }
+                sendbuf.flip();
+
+                // write to file and transfer to echo server
+                fc.write(sendbuf, position);
+                t0 = System.nanoTime();
+                fc.transferTo(position, count, source);
+                out.printf("  transferTo(%d, %2d, source): %d ns%n",
+                    position, count, System.nanoTime() - t0);
+
+                // read from echo server
+                long nread = 0;
+                while (nread < count) {
+                    int n = source.read(readbuf);
+                    if (n < 0)
+                        throw new RuntimeException("Premature EOF!");
+                    nread += n;
+                }
+
+                // check reply from echo server
+                readbuf.flip();
+                sendbuf.flip();
+                if (!readbuf.equals(sendbuf))
+                    throw new RuntimeException("Echoed bytes do not match!");
+                readbuf.clear();
+                sendbuf.clear();
+            }
+        } finally {
+            source.close();
+            ssc.close();
+            fc.close();
+            file.delete();
+        }
+    }
+
+    /**
+     * Simple in-process server to echo bytes read by a given socket channel
+     */
+    static class EchoServer implements Runnable {
+        private SocketChannel sc;
+
+        public EchoServer(SocketChannel sc) {
+            this.sc = sc;
+        }
+
+        public void run() {
+            ByteBuffer bb = ByteBuffer.allocateDirect(1024);
+            try {
+                for (;;) {
+                    int n = sc.read(bb);
+                    if (n < 0)
+                        break;
+
+                    bb.flip();
+                    while (bb.remaining() > 0) {
+                        sc.write(bb);
+                    }
+                    bb.clear();
+                }
+            } catch (IOException x) {
+                x.printStackTrace();
+            } finally {
+                try {
+                    sc.close();
+                } catch (IOException ignore) { }
+            }
+        }
+    }
+}
--- a/jdk/test/sun/net/www/http/HttpClient/B8025710.java	Thu Mar 16 22:03:08 2017 +0300
+++ b/jdk/test/sun/net/www/http/HttpClient/B8025710.java	Tue Mar 21 08:48:14 2017 -0700
@@ -37,6 +37,7 @@
  * @test
  * @bug 8025710
  * @summary Proxied https connection reuse by HttpClient can send CONNECT to the server
+ * @run main/othervm B8025710
  */
 public class B8025710 {
 
--- a/jdk/test/tools/jar/modularJar/Basic.java	Thu Mar 16 22:03:08 2017 +0300
+++ b/jdk/test/tools/jar/modularJar/Basic.java	Tue Mar 21 08:48:14 2017 -0700
@@ -39,6 +39,7 @@
 import jdk.testlibrary.FileUtils;
 import jdk.testlibrary.JDKToolFinder;
 import org.testng.annotations.BeforeTest;
+import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
 import static java.lang.String.format;
@@ -46,7 +47,7 @@
 
 /*
  * @test
- * @bug 8167328 8171830 8165640 8174248
+ * @bug 8167328 8171830 8165640 8174248 8176772
  * @library /lib/testlibrary
  * @modules jdk.compiler
  *          jdk.jartool
@@ -754,7 +755,7 @@
             .assertSuccess();
 
 
-        for (String option : new String[]  {"--print-module-descriptor", "-d" }) {
+        for (String option : new String[]  {"--describe-module", "-d" }) {
 
             jar(option,
                 "--file=" + modularJar.toString())
@@ -801,8 +802,8 @@
     }
 
     @Test
-    public void printModuleDescriptorFoo() throws IOException {
-        Path mp = Paths.get("printModuleDescriptorFoo");
+    public void describeModuleFoo() throws IOException {
+        Path mp = Paths.get("describeModuleFoo");
         createTestDir(mp);
         Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName);
         Path modularJar = mp.resolve(FOO.moduleName + ".jar");
@@ -815,7 +816,7 @@
             "-C", modClasses.toString(), ".")
             .assertSuccess();
 
-        for (String option : new String[]  {"--print-module-descriptor", "-d" }) {
+        for (String option : new String[]  {"--describe-module", "-d" }) {
             jar(option,
                 "--file=" + modularJar.toString())
                 .assertSuccess()
@@ -836,8 +837,8 @@
     }
 
     @Test
-    public void printModuleDescriptorFooFromStdin() throws IOException {
-        Path mp = Paths.get("printModuleDescriptorFooFromStdin");
+    public void describeModuleFooFromStdin() throws IOException {
+        Path mp = Paths.get("describeModuleFooFromStdin");
         createTestDir(mp);
         Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName);
         Path modularJar = mp.resolve(FOO.moduleName + ".jar");
@@ -850,7 +851,7 @@
             "-C", modClasses.toString(), ".")
             .assertSuccess();
 
-        for (String option : new String[]  {"--print-module-descriptor", "-d" }) {
+        for (String option : new String[]  {"--describe-module", "-d" }) {
             jarWithStdin(modularJar.toFile(),
                          option)
                          .assertSuccess()
@@ -862,6 +863,50 @@
         }
     }
 
+
+    @DataProvider(name = "autoNames")
+    public Object[][] autoNames() {
+        return new Object[][] {
+            // JAR file name                module-name[@version]
+            { "foo.jar",                    "foo" },
+            { "foo4j.jar",                  "foo4j", },
+            { "foo1.2.3.jar",               "foo" },
+            { "foo-1.2.3.4.jar",            "foo@1.2.3.4" },
+            { "foo-bar.jar",                "foo.bar" },
+            { "foo-1.2-SNAPSHOT.jar",       "foo@1.2-SNAPSHOT" },
+        };
+    }
+
+    @Test(dataProvider = "autoNames")
+    public void describeAutomaticModule(String jarName, String mid)
+        throws IOException
+    {
+        Path mp = Paths.get("describeAutomaticModule");
+        createTestDir(mp);
+        Path regularJar = mp.resolve(jarName);
+        Path t = Paths.get("t");
+        if (Files.notExists(t))
+            Files.createFile(t);
+
+        jar("--create",
+            "--file=" + regularJar.toString(),
+            t.toString())
+            .assertSuccess();
+
+        for (String option : new String[]  {"--describe-module", "-d" }) {
+            jar(option,
+                "--file=" + regularJar.toString())
+                .assertSuccess()
+                .resultChecker(r -> {
+                    assertTrue(r.output.contains("No module descriptor found"));
+                    assertTrue(r.output.contains("Derived automatic module"));
+                    assertTrue(r.output.contains("module " + mid),
+                               "Expected [", "module " + mid,"] in [", r.output, "]");
+                    }
+                );
+        }
+    }
+
     // -- Infrastructure
 
     static Result jarWithStdin(File stdinSource, String... args) {