Merge
authorduke
Wed, 05 Jul 2017 22:19:40 +0200
changeset 41454 daa1590082a3
parent 41453 5429549751ad (diff)
parent 41436 1efa1eea875e (current diff)
child 41455 0875007901f7
Merge
hotspot/make/Dist.gmk
hotspot/src/share/vm/oops/arrayOop.cpp
hotspot/src/share/vm/utilities/chunkedList.cpp
hotspot/src/share/vm/utilities/linkedlist.cpp
hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodAtSlotTest.java
hotspot/test/native/runtime/test_instanceKlass.cpp
hotspot/test/runtime/SharedArchiveFile/SASymbolTableTestAttachee.java
jdk/make/Import.gmk
jdk/src/java.desktop/share/classes/sun/java2d/pipe/hw/AccelDeviceEventListener.java
jdk/src/java.desktop/share/classes/sun/java2d/pipe/hw/AccelDeviceEventNotifier.java
jdk/test/java/awt/image/multiresolution/MultiResolutionTrayIconTest/MultiResolutionTrayIconTest.html
make/StripBinaries.gmk
--- a/langtools/.hgtags	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/.hgtags	Wed Jul 05 22:19:40 2017 +0200
@@ -381,3 +381,4 @@
 c8f02f0ecbd7cd6700f47416e4b7e9d5ec20ad77 jdk-9+136
 dd56c243c199a540c9f1fbff4855f0934b32a9d0 jdk-9+137
 90dd93e668a521642382561c47abe96ee2e065b7 jdk-9+138
+17a82cb0e4b480e97021691d39917f15e3f7b653 jdk-9+139
--- a/langtools/ASSEMBLY_EXCEPTION	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/ASSEMBLY_EXCEPTION	Wed Jul 05 22:19:40 2017 +0200
@@ -1,27 +1,27 @@
 
 OPENJDK ASSEMBLY EXCEPTION
 
-The OpenJDK source code made available by Sun at openjdk.java.net and
-openjdk.dev.java.net ("OpenJDK Code") is distributed under the terms of the
-GNU General Public License <http://www.gnu.org/copyleft/gpl.html> version 2
+The OpenJDK source code made available by Oracle America, Inc. (Oracle) at
+openjdk.java.net ("OpenJDK Code") is distributed under the terms of the GNU
+General Public License <http://www.gnu.org/copyleft/gpl.html> version 2
 only ("GPL2"), with the following clarification and special exception.
 
     Linking this OpenJDK Code statically or dynamically with other code
     is making a combined work based on this library.  Thus, the terms
     and conditions of GPL2 cover the whole combination.
 
-    As a special exception, Sun gives you permission to link this
-    OpenJDK Code with certain code licensed by Sun as indicated at
+    As a special exception, Oracle gives you permission to link this
+    OpenJDK Code with certain code licensed by Oracle as indicated at
     http://openjdk.java.net/legal/exception-modules-2007-05-08.html
     ("Designated Exception Modules") to produce an executable,
     regardless of the license terms of the Designated Exception Modules,
     and to copy and distribute the resulting executable under GPL2,
     provided that the Designated Exception Modules continue to be
-    governed by the licenses under which they were offered by Sun.
+    governed by the licenses under which they were offered by Oracle.
 
-As such, it allows licensees and sublicensees of Sun's GPL2 OpenJDK Code to
-build an executable that includes those portions of necessary code that Sun
-could not provide under GPL2 (or that Sun has provided under GPL2 with the
-Classpath exception).  If you modify or add to the OpenJDK code, that new
-GPL2 code may still be combined with Designated Exception Modules if the
-new code is made subject to this exception by its copyright holder.
+As such, it allows licensees and sublicensees of Oracle's GPL2 OpenJDK Code
+to build an executable that includes those portions of necessary code that
+Oracle could not provide under GPL2 (or that Oracle has provided under GPL2
+with the Classpath exception).  If you modify or add to the OpenJDK code,
+that new GPL2 code may still be combined with Designated Exception Modules
+if the new code is made subject to this exception by its copyright holder.
--- a/langtools/make/CompileInterim.gmk	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/make/CompileInterim.gmk	Wed Jul 05 22:19:40 2017 +0200
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 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
@@ -47,7 +47,7 @@
           $$(wildcard $(SUPPORT_OUTPUTDIR)/gensrc/$(strip $1)), \
       EXCLUDES := sun com/sun/tools/jdeps com/sun/tools/javap \
           com/sun/tools/jdeprscan, \
-      EXCLUDE_FILES := module-info.java, \
+      EXCLUDE_FILES := module-info.java JavacToolProvider.java JavadocToolProvider.java, \
       COPY := .gif .png .xml .css .js javax.tools.JavaCompilerTool, \
       BIN := $(BUILDTOOLS_OUTPUTDIR)/override_modules/$(strip $1), \
       ADD_JAVAC_FLAGS := -Xbootclasspath/p:$$(call PathList, \
--- a/langtools/make/tools/crules/MutableFieldsAnalyzer.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/make/tools/crules/MutableFieldsAnalyzer.java	Wed Jul 05 22:19:40 2017 +0200
@@ -111,6 +111,8 @@
                 "loadMethod");
         ignoreFields("com.sun.tools.javac.util.JDK9Wrappers$VMHelper",
                 "vmClass", "getRuntimeArgumentsMethod");
+        ignoreFields("com.sun.tools.javac.util.JDK9Wrappers$JmodFile",
+                "jmodFileClass", "checkMagicMethod");
     }
 
 }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/source/util/DocTreeFactory.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/source/util/DocTreeFactory.java	Wed Jul 05 22:19:40 2017 +0200
@@ -112,12 +112,11 @@
 
     /**
      * Create a new {@code DocCommentTree} object, to represent a complete doc comment.
-     * @param firstSentence the first sentence of the doc comment
-     * @param body the body of the doc comment following the first sentence
+     * @param fullBody the entire body of the doc comment
      * @param tags the block tags in the doc comment
      * @return a {@code DocCommentTree} object
      */
-    DocCommentTree newDocCommentTree(List<? extends DocTree> firstSentence, List<? extends DocTree> body, List<? extends DocTree> tags);
+    DocCommentTree newDocCommentTree(List<? extends DocTree> fullBody, List<? extends DocTree> tags);
 
     /**
      * Create a new {@code DocRootTree} object, to represent an {@code {@docroot} } tag.
--- a/langtools/src/jdk.compiler/share/classes/com/sun/source/util/TreePathScanner.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/source/util/TreePathScanner.java	Wed Jul 05 22:19:40 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 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
@@ -35,6 +35,10 @@
  * Inside your method, call super.visitXYZ to visit descendant
  * nodes.
  *
+ * @apiNote
+ * In order to initialize the "current path", the scan must be
+ * started by calling one of the {@code scan} methods.
+ *
  * @author Jonathan Gibbons
  * @since 1.6
  */
@@ -58,6 +62,13 @@
     /**
      * Scans a single node.
      * The current path is updated for the duration of the scan.
+     *
+     * @apiNote This method should normally only be called by the
+     * scanner's {@code visit} methods, as part of an ongoing scan
+     * initiated by {@link #scan(TreePath,Object) scan(TreePath, P)}.
+     * The one exception is that it may also be called to initiate
+     * a full scan of a {@link CompilationUnitTree}.
+     *
      * @return the result value from the visit method
      */
     @Override
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Wed Jul 05 22:19:40 2017 +0200
@@ -4415,6 +4415,7 @@
                 chk.checkDeprecatedAnnotation(env.tree.pos(), c);
                 chk.checkClassOverrideEqualsAndHashIfNeeded(env.tree.pos(), c);
                 chk.checkFunctionalInterface((JCClassDecl) env.tree, c);
+                chk.checkLeaksNotAccessible(env, (JCClassDecl) env.tree);
             } finally {
                 env.info.returnResult = prevReturnRes;
                 log.useSource(prev);
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Wed Jul 05 22:19:40 2017 +0200
@@ -31,10 +31,13 @@
 
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Attribute.Compound;
+import com.sun.tools.javac.code.Directive.ExportsDirective;
+import com.sun.tools.javac.code.Directive.RequiresDirective;
 import com.sun.tools.javac.comp.Annotate.AnnotationTypeMetadata;
 import com.sun.tools.javac.jvm.*;
 import com.sun.tools.javac.resources.CompilerProperties.Errors;
 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
+import com.sun.tools.javac.resources.CompilerProperties.Warnings;
 import com.sun.tools.javac.tree.*;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
@@ -3661,4 +3664,178 @@
         }
     }
 
+    public void checkLeaksNotAccessible(Env<AttrContext> env, JCClassDecl check) {
+        JCCompilationUnit toplevel = env.toplevel;
+
+        if (   toplevel.modle == syms.unnamedModule
+            || toplevel.modle == syms.noModule
+            || (check.sym.flags() & COMPOUND) != 0) {
+            return ;
+        }
+
+        ExportsDirective currentExport = findExport(toplevel.packge);
+
+        if (   currentExport == null //not exported
+            || currentExport.modules != null) //don't check classes in qualified export
+            return ;
+
+        new TreeScanner() {
+            Lint lint = env.info.lint;
+            boolean inSuperType;
+
+            @Override
+            public void visitBlock(JCBlock tree) {
+            }
+            @Override
+            public void visitMethodDef(JCMethodDecl tree) {
+                if (!isAPISymbol(tree.sym))
+                    return;
+                Lint prevLint = lint;
+                try {
+                    lint = lint.augment(tree.sym);
+                    if (lint.isEnabled(LintCategory.EXPORTS)) {
+                        super.visitMethodDef(tree);
+                    }
+                } finally {
+                    lint = prevLint;
+                }
+            }
+            @Override
+            public void visitVarDef(JCVariableDecl tree) {
+                if (!isAPISymbol(tree.sym) && tree.sym.owner.kind != MTH)
+                    return;
+                Lint prevLint = lint;
+                try {
+                    lint = lint.augment(tree.sym);
+                    if (lint.isEnabled(LintCategory.EXPORTS)) {
+                        scan(tree.mods);
+                        scan(tree.vartype);
+                    }
+                } finally {
+                    lint = prevLint;
+                }
+            }
+            @Override
+            public void visitClassDef(JCClassDecl tree) {
+                if (tree != check)
+                    return ;
+
+                if (!isAPISymbol(tree.sym))
+                    return ;
+
+                Lint prevLint = lint;
+                try {
+                    lint = lint.augment(tree.sym);
+                    if (lint.isEnabled(LintCategory.EXPORTS)) {
+                        scan(tree.mods);
+                        scan(tree.typarams);
+                        try {
+                            inSuperType = true;
+                            scan(tree.extending);
+                            scan(tree.implementing);
+                        } finally {
+                            inSuperType = false;
+                        }
+                        scan(tree.defs);
+                    }
+                } finally {
+                    lint = prevLint;
+                }
+            }
+            @Override
+            public void visitTypeApply(JCTypeApply tree) {
+                scan(tree.clazz);
+                boolean oldInSuperType = inSuperType;
+                try {
+                    inSuperType = false;
+                    scan(tree.arguments);
+                } finally {
+                    inSuperType = oldInSuperType;
+                }
+            }
+            @Override
+            public void visitIdent(JCIdent tree) {
+                Symbol sym = TreeInfo.symbol(tree);
+                if (sym.kind == TYP && !sym.type.hasTag(TYPEVAR)) {
+                    checkVisible(tree.pos(), sym, toplevel.packge, inSuperType);
+                }
+            }
+
+            @Override
+            public void visitSelect(JCFieldAccess tree) {
+                Symbol sym = TreeInfo.symbol(tree);
+                Symbol sitesym = TreeInfo.symbol(tree.selected);
+                if (sym.kind == TYP && sitesym.kind == PCK) {
+                    checkVisible(tree.pos(), sym, toplevel.packge, inSuperType);
+                } else {
+                    super.visitSelect(tree);
+                }
+            }
+
+            @Override
+            public void visitAnnotation(JCAnnotation tree) {
+                if (tree.attribute.type.tsym.getAnnotation(java.lang.annotation.Documented.class) != null)
+                    super.visitAnnotation(tree);
+            }
+
+        }.scan(check);
+    }
+        //where:
+        private ExportsDirective findExport(PackageSymbol pack) {
+            for (ExportsDirective d : pack.modle.exports) {
+                if (d.packge == pack)
+                    return d;
+            }
+
+            return null;
+        }
+        private boolean isAPISymbol(Symbol sym) {
+            while (sym.kind != PCK) {
+                if ((sym.flags() & Flags.PUBLIC) == 0 && (sym.flags() & Flags.PROTECTED) == 0) {
+                    return false;
+                }
+                sym = sym.owner;
+            }
+            return true;
+        }
+        private void checkVisible(DiagnosticPosition pos, Symbol what, PackageSymbol inPackage, boolean inSuperType) {
+            if (!isAPISymbol(what) && !inSuperType) { //package private/private element
+                log.warning(LintCategory.EXPORTS, pos, Warnings.LeaksNotAccessible(kindName(what), what, what.packge().modle));
+                return ;
+            }
+
+            PackageSymbol whatPackage = what.packge();
+            ExportsDirective whatExport = findExport(whatPackage);
+            ExportsDirective inExport = findExport(inPackage);
+
+            if (whatExport == null) { //package not exported:
+                log.warning(LintCategory.EXPORTS, pos, Warnings.LeaksNotAccessibleUnexported(kindName(what), what, what.packge().modle));
+                return ;
+            }
+
+            if (whatExport.modules != null) {
+                if (inExport.modules == null || !whatExport.modules.containsAll(inExport.modules)) {
+                    log.warning(LintCategory.EXPORTS, pos, Warnings.LeaksNotAccessibleUnexportedQualified(kindName(what), what, what.packge().modle));
+                }
+            }
+
+            if (whatPackage.modle != inPackage.modle && whatPackage.modle != syms.java_base) {
+                //check that relativeTo.modle requires public what.modle, somehow:
+                List<ModuleSymbol> todo = List.of(inPackage.modle);
+
+                while (todo.nonEmpty()) {
+                    ModuleSymbol current = todo.head;
+                    todo = todo.tail;
+                    if (current == whatPackage.modle)
+                        return ; //OK
+                    for (RequiresDirective req : current.requires) {
+                        if (req.isPublic()) {
+                            todo = todo.prepend(req.module);
+                        }
+                    }
+                }
+
+                log.warning(LintCategory.EXPORTS, pos, Warnings.LeaksNotAccessibleNotRequiredPublic(kindName(what), what, what.packge().modle));
+            }
+        }
 }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java	Wed Jul 05 22:19:40 2017 +0200
@@ -78,6 +78,7 @@
 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
 import com.sun.tools.javac.util.DefinedBy;
 import com.sun.tools.javac.util.DefinedBy.Api;
+import com.sun.tools.javac.util.JDK9Wrappers;
 import com.sun.tools.javac.util.ListBuffer;
 import com.sun.tools.javac.util.Log;
 import com.sun.tools.javac.jvm.ModuleNameReader;
@@ -1103,6 +1104,11 @@
 
                 if (p.getFileName().toString().endsWith(".jmod")) {
                     try {
+                        // check if the JMOD file is valid
+                        JDK9Wrappers.JmodFile.checkMagic(p);
+
+                        // No JMOD file system.  Use JarFileSystem to
+                        // workaround for now
                         FileSystem fs = fileSystems.get(p);
                         if (fs == null) {
                             URI uri = URI.create("jar:" + p.toUri());
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/CommandLine.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/CommandLine.java	Wed Jul 05 22:19:40 2017 +0200
@@ -27,7 +27,6 @@
 
 import java.io.IOException;
 import java.io.Reader;
-import java.io.StreamTokenizer;
 import java.nio.file.Files;
 import java.nio.file.Paths;
 
@@ -51,10 +50,11 @@
      * '@file' argument replaced with the resulting tokens. Recursive command
      * files are not supported. The '@' character itself can be quoted with
      * the sequence '@@'.
+     * @param args the arguments that may contain @files
+     * @return the arguments, with @files expanded
+     * @throws IOException if there is a problem reading any of the @files
      */
-    public static String[] parse(String[] args)
-        throws IOException
-    {
+    public static String[] parse(String[] args) throws IOException {
         ListBuffer<String> newArgs = new ListBuffer<>();
         for (String arg : args) {
             if (arg.length() > 1 && arg.charAt(0) == '@') {
@@ -71,19 +71,120 @@
         return newArgs.toList().toArray(new String[newArgs.length()]);
     }
 
-    private static void loadCmdFile(String name, ListBuffer<String> args)
-        throws IOException
-    {
+    private static void loadCmdFile(String name, ListBuffer<String> args) throws IOException {
         try (Reader r = Files.newBufferedReader(Paths.get(name))) {
-            StreamTokenizer st = new StreamTokenizer(r);
-            st.resetSyntax();
-            st.wordChars(' ', 255);
-            st.whitespaceChars(0, ' ');
-            st.commentChar('#');
-            st.quoteChar('"');
-            st.quoteChar('\'');
-            while (st.nextToken() != StreamTokenizer.TT_EOF) {
-                args.append(st.sval);
+            Tokenizer t = new Tokenizer(r);
+            String s;
+            while ((s = t.nextToken()) != null) {
+                args.append(s);
+            }
+        }
+    }
+
+    public static class Tokenizer {
+        private final Reader in;
+        private int ch;
+
+        public Tokenizer(Reader in) throws IOException {
+            this.in = in;
+            ch = in.read();
+        }
+
+        public String nextToken() throws IOException {
+            skipWhite();
+            if (ch == -1) {
+                return null;
+            }
+
+            StringBuilder sb = new StringBuilder();
+            char quoteChar = 0;
+
+            while (ch != -1) {
+                switch (ch) {
+                    case ' ':
+                    case '\t':
+                    case '\f':
+                        if (quoteChar == 0) {
+                            return sb.toString();
+                        }
+                        sb.append((char) ch);
+                        break;
+
+                    case '\n':
+                    case '\r':
+                        return sb.toString();
+
+                    case '\'':
+                    case '"':
+                        if (quoteChar == 0) {
+                            quoteChar = (char) ch;
+                        } else if (quoteChar == ch) {
+                            quoteChar = 0;
+                        } else {
+                            sb.append((char) ch);
+                        }
+                        break;
+
+                    case '\\':
+                        if (quoteChar != 0) {
+                            ch = in.read();
+                            switch (ch) {
+                                case '\n':
+                                case '\r':
+                                    while (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '\f') {
+                                        ch = in.read();
+                                    }
+                                    continue;
+
+                                case 'n':
+                                    ch = '\n';
+                                    break;
+                                case 'r':
+                                    ch = '\r';
+                                    break;
+                                case 't':
+                                    ch = '\t';
+                                    break;
+                                case 'f':
+                                    ch = '\f';
+                                    break;
+                            }
+                        }
+                        sb.append((char) ch);
+                        break;
+
+                    default:
+                        sb.append((char) ch);
+                }
+
+                ch = in.read();
+            }
+
+            return sb.toString();
+        }
+
+        void skipWhite() throws IOException {
+            while (ch != -1) {
+                switch (ch) {
+                    case ' ':
+                    case '\t':
+                    case '\n':
+                    case '\r':
+                    case '\f':
+                        break;
+
+                    case '#':
+                        ch = in.read();
+                        while (ch != '\n' && ch != '\r' && ch != -1) {
+                            ch = in.read();
+                        }
+                        break;
+
+                    default:
+                        return;
+                }
+
+                ch = in.read();
             }
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavacToolProvider.java	Wed Jul 05 22:19:40 2017 +0200
@@ -0,0 +1,48 @@
+/*
+ * 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.javac.main;
+
+import java.io.PrintWriter;
+import java.util.spi.ToolProvider;
+
+/**
+ * An implementation of the {@link java.util.spi.ToolProvider ToolProvider} SPI,
+ * providing access to JDK Java compiler, javac.
+ *
+ * @since 9
+ */
+// This is currently a stand-alone top-level class so that it can easily be excluded
+// from interims builds of javac, used while building JDK.
+public class JavacToolProvider implements ToolProvider {
+    public String name() {
+        return "javac";
+    }
+
+    public int run(PrintWriter out, PrintWriter err, String... args) {
+        Main compiler = new Main("javac", out, err);
+        return compiler.compile(args).exitCode;
+    }
+}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Main.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Main.java	Wed Jul 05 22:19:40 2017 +0200
@@ -119,6 +119,18 @@
         this.stdOut = this.stdErr = out;
     }
 
+    /**
+     * Construct a compiler instance.
+     * @param name the name of this tool
+     * @param out a stream to which to write expected output
+     * @param err a stream to which to write diagnostic output
+     */
+    public Main(String name, PrintWriter out, PrintWriter err) {
+        this.ownName = name;
+        this.stdOut = out;
+        this.stdErr = err;
+    }
+
     /** Report a usage error.
      */
     void error(String key, Object... args) {
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Wed Jul 05 22:19:40 2017 +0200
@@ -2865,6 +2865,19 @@
 compiler.warn.service.provided.but.not.exported.or.used=\
     service interface provided but not exported or used
 
+# 0: kind name, 1: symbol, 2: symbol
+compiler.warn.leaks.not.accessible=\
+    {0} {1} in module {2} is not accessible to clients that require this module
+# 0: kind name, 1: symbol, 2: symbol
+compiler.warn.leaks.not.accessible.unexported=\
+    {0} {1} in module {2} is not exported
+# 0: kind name, 1: symbol, 2: symbol
+compiler.warn.leaks.not.accessible.not.required.public=\
+    {0} {1} in module {2} is not indirectly exported using 'requires public'
+# 0: kind name, 1: symbol, 2: symbol
+compiler.warn.leaks.not.accessible.unexported.qualified=\
+    {0} {1} in module {2} may not be visible to all clients that require this module
+
 ###
 # errors related to options
 
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocTreeMaker.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocTreeMaker.java	Wed Jul 05 22:19:40 2017 +0200
@@ -203,11 +203,10 @@
      * where the trees are being synthesized by a tool.
      */
     @Override @DefinedBy(Api.COMPILER_TREE)
-    public DCDocComment newDocCommentTree(List<? extends DocTree> firstSentence, List<? extends DocTree> body, List<? extends DocTree> tags) {
+    public DCDocComment newDocCommentTree(List<? extends DocTree> fullBody, List<? extends DocTree> tags) {
         ListBuffer<DCTree> lb = new ListBuffer<>();
-        lb.addAll(cast(firstSentence));
-        lb.addAll(cast(body));
-        List<DCTree> fullBody = lb.toList();
+        lb.addAll(cast(fullBody));
+        List<DCTree> fBody = lb.toList();
 
         // A dummy comment to keep the diagnostics logic happy.
         Comment c = new Comment() {
@@ -231,8 +230,8 @@
                 return false;
             }
         };
-
-        DCDocComment tree = new DCDocComment(c, fullBody, cast(firstSentence), cast(body), cast(tags));
+        Pair<List<DCTree>, List<DCTree>> pair = splitBody(fullBody);
+        DCDocComment tree = new DCDocComment(c, fBody, pair.fst, pair.snd, cast(tags));
         return tree;
     }
 
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Iterators.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Iterators.java	Wed Jul 05 22:19:40 2017 +0200
@@ -46,7 +46,8 @@
 
         private final Iterator<I> inputs;
         private final Function<I, Iterator<O>> convertor;
-        private Iterator<O> currentIterator;
+        @SuppressWarnings("unchecked")
+        private Iterator<O> currentIterator = EMPTY;
 
         public CompoundIterator(Iterable<I> inputs, Function<I, Iterator<O>> convertor) {
             this.inputs = inputs.iterator();
@@ -54,10 +55,10 @@
         }
 
         public boolean hasNext() {
-            while (inputs.hasNext() && (currentIterator == null || !currentIterator.hasNext())) {
-                currentIterator = convertor.apply(inputs.next());
+            if (currentIterator != null && !currentIterator.hasNext()) {
+                update();
             }
-            return currentIterator != null && currentIterator.hasNext();
+            return currentIterator != null;
         }
 
         public O next() {
@@ -70,5 +71,25 @@
         public void remove() {
             throw new UnsupportedOperationException();
         }
+
+        private void update() {
+            while (inputs.hasNext()) {
+                currentIterator = convertor.apply(inputs.next());
+                if (currentIterator.hasNext()) return;
+            }
+            currentIterator = null;
+        }
     }
+
+    @SuppressWarnings("rawtypes")
+    private final static Iterator EMPTY = new Iterator() {
+        public boolean hasNext() {
+            return false;
+        }
+
+        @Override
+        public Object next() {
+            return null;
+        }
+    };
 }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JDK9Wrappers.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JDK9Wrappers.java	Wed Jul 05 22:19:40 2017 +0200
@@ -25,6 +25,7 @@
 
 package com.sun.tools.javac.util;
 
+import java.io.IOException;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.nio.file.Path;
@@ -367,4 +368,41 @@
             }
         }
     }
+
+    /**
+     * Helper class for new method in jdk.internal.jmod.JmodFile
+     */
+    public static final class JmodFile {
+        public static final String JMOD_FILE_CLASSNAME = "jdk.internal.jmod.JmodFile";
+
+        public static void checkMagic(Path file) throws IOException {
+            try {
+                init();
+                checkMagicMethod.invoke(null, file);
+            } catch (InvocationTargetException ex) {
+                if (ex.getCause() instanceof IOException) {
+                    throw IOException.class.cast(ex.getCause());
+                }
+                throw new Abort(ex);
+            } catch (IllegalAccessException | IllegalArgumentException | SecurityException ex) {
+                throw new Abort(ex);
+            }
+        }
+
+        // -----------------------------------------------------------------------------------------
+
+        private static Class<?> jmodFileClass = null;
+        private static Method checkMagicMethod = null;
+
+        private static void init() {
+            if (jmodFileClass == null) {
+                try {
+                    jmodFileClass = Class.forName(JMOD_FILE_CLASSNAME, false, null);
+                    checkMagicMethod = jmodFileClass.getDeclaredMethod("checkMagic", Path.class);
+                } catch (ClassNotFoundException | NoSuchMethodException | SecurityException ex) {
+                    throw new Abort(ex);
+                }
+            }
+        }
+    }
 }
--- a/langtools/src/jdk.compiler/share/classes/module-info.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/module-info.java	Wed Jul 05 22:19:40 2017 +0200
@@ -70,6 +70,9 @@
     uses com.sun.source.util.Plugin;
     uses com.sun.tools.javac.platform.PlatformProvider;
 
+    provides java.util.spi.ToolProvider
+        with com.sun.tools.javac.main.JavacToolProvider;
+
     provides com.sun.tools.javac.platform.PlatformProvider
         with com.sun.tools.javac.platform.JDKPlatformProvider;
 
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java	Wed Jul 05 22:19:40 2017 +0200
@@ -368,7 +368,7 @@
      * @param htmltree the content tree to which the comment will be added.
      */
     protected void addComment(Element member, Content htmltree) {
-        if (!utils.getBody(member).isEmpty()) {
+        if (!utils.getFullBody(member).isEmpty()) {
             writer.addInlineComment(member, htmltree);
         }
     }
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeWriterImpl.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeWriterImpl.java	Wed Jul 05 22:19:40 2017 +0200
@@ -290,8 +290,8 @@
      */
     @Override
     public void addAnnotationTypeDescription(Content annotationInfoTree) {
-        if(!configuration.nocomment) {
-            if (!utils.getBody(annotationType).isEmpty()) {
+        if (!configuration.nocomment) {
+            if (!utils.getFullBody(annotationType).isEmpty()) {
                 addInlineComment(annotationType, annotationInfoTree);
             }
         }
@@ -302,7 +302,7 @@
      */
     @Override
     public void addAnnotationTypeTagInfo(Content annotationInfoTree) {
-        if(!configuration.nocomment) {
+        if (!configuration.nocomment) {
             addTagsInfo(annotationType, annotationInfoTree);
         }
     }
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java	Wed Jul 05 22:19:40 2017 +0200
@@ -353,7 +353,7 @@
     public void addClassDescription(Content classInfoTree) {
         if(!configuration.nocomment) {
             // generate documentation for the class.
-            if (!utils.getBody(typeElement).isEmpty()) {
+            if (!utils.getFullBody(typeElement).isEmpty()) {
                 addInlineComment(typeElement, classInfoTree);
             }
         }
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/FieldWriterImpl.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/FieldWriterImpl.java	Wed Jul 05 22:19:40 2017 +0200
@@ -146,7 +146,7 @@
      */
     @Override
     public void addComments(VariableElement field, Content fieldTree) {
-        if (!utils.getBody(field).isEmpty()) {
+        if (!utils.getFullBody(field).isEmpty()) {
             writer.addInlineComment(field, fieldTree);
         }
     }
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java	Wed Jul 05 22:19:40 2017 +0200
@@ -1704,7 +1704,7 @@
      * @param htmltree the documentation tree to which the inline comments will be added
      */
     public void addInlineComment(Element element, Content htmltree) {
-        addCommentTags(element, utils.getBody(element), false, false, htmltree);
+        addCommentTags(element, utils.getFullBody(element), false, false, htmltree);
     }
 
     /**
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlSerialFieldWriter.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlSerialFieldWriter.java	Wed Jul 05 22:19:40 2017 +0200
@@ -159,7 +159,7 @@
      * @param contentTree the tree to which the deprecated info will be added
      */
     public void addMemberDescription(VariableElement field, Content contentTree) {
-        if (!utils.getBody(field).isEmpty()) {
+        if (!utils.getFullBody(field).isEmpty()) {
             writer.addInlineComment(field, contentTree);
         }
         List<? extends DocTree> tags = utils.getBlockTags(field, DocTree.Kind.SERIAL);
@@ -210,7 +210,7 @@
      */
     public boolean shouldPrintOverview(VariableElement field) {
         if (!configuration.nocomment) {
-            if(!utils.getBody(field).isEmpty() ||
+            if(!utils.getFullBody(field).isEmpty() ||
                     writer.hasSerializationOverviewTags(field))
                 return true;
         }
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriterImpl.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriterImpl.java	Wed Jul 05 22:19:40 2017 +0200
@@ -172,7 +172,7 @@
     @Override
     public void addComments(TypeMirror holderType, ExecutableElement method, Content methodDocTree) {
         TypeElement holder = utils.asTypeElement(holderType);
-        if (!utils.getBody(method).isEmpty()) {
+        if (!utils.getFullBody(method).isEmpty()) {
             if (holder.equals(typeElement) ||
                     !(utils.isPublic(holder) ||
                     utils.isLinkable(holder))) {
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleIndexWriter.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleIndexWriter.java	Wed Jul 05 22:19:40 2017 +0200
@@ -182,7 +182,7 @@
     @Override
     protected void addOverviewHeader(Content body) {
         addConfigurationTitle(body);
-        if (!utils.getBody(configuration.overviewElement).isEmpty()) {
+        if (!utils.getFullBody(configuration.overviewElement).isEmpty()) {
             HtmlTree subTitleDiv = new HtmlTree(HtmlTag.DIV);
             subTitleDiv.addStyle(HtmlStyle.subTitle);
             addSummaryComment(configuration.overviewElement, subTitleDiv);
@@ -212,7 +212,7 @@
      *                 be added
      */
     protected void addOverviewComment(Content htmltree) {
-        if (!utils.getBody(configuration.overviewElement).isEmpty()) {
+        if (!utils.getFullBody(configuration.overviewElement).isEmpty()) {
             htmltree.addContent(getMarkerAnchor(SectionName.OVERVIEW_DESCRIPTION));
             addInlineComment(configuration.overviewElement, htmltree);
         }
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriterImpl.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriterImpl.java	Wed Jul 05 22:19:40 2017 +0200
@@ -484,7 +484,7 @@
      * {@inheritDoc}
      */
     public void addModuleDescription(Content moduleContentTree) {
-        if (!utils.getBody(mdle).isEmpty()) {
+        if (!utils.getFullBody(mdle).isEmpty()) {
             Content tree = configuration.allowTag(HtmlTag.SECTION) ? HtmlTree.SECTION() : moduleContentTree;
             tree.addContent(HtmlConstants.START_OF_MODULE_DESCRIPTION);
             tree.addContent(getMarkerAnchor(SectionName.MODULE_DESCRIPTION));
@@ -528,7 +528,7 @@
         li.addContent(Contents.SPACE);
         Content ulNav = HtmlTree.UL(HtmlStyle.subNavList, li);
         Content liNav = new HtmlTree(HtmlTag.LI);
-        liNav.addContent(!utils.getBody(mdle).isEmpty() && !configuration.nocomment
+        liNav.addContent(!utils.getFullBody(mdle).isEmpty() && !configuration.nocomment
                 ? getHyperLink(SectionName.MODULE_DESCRIPTION, contents.navModuleDescription)
                 : contents.navModuleDescription);
         addNavGap(liNav);
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageIndexWriter.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageIndexWriter.java	Wed Jul 05 22:19:40 2017 +0200
@@ -175,7 +175,7 @@
     @Override
     protected void addOverviewHeader(Content body) {
         addConfigurationTitle(body);
-        if (!utils.getBody(configuration.overviewElement).isEmpty()) {
+        if (!utils.getFullBody(configuration.overviewElement).isEmpty()) {
             HtmlTree subTitleDiv = new HtmlTree(HtmlTag.DIV);
             subTitleDiv.addStyle(HtmlStyle.subTitle);
             addSummaryComment(configuration.overviewElement, subTitleDiv);
@@ -205,7 +205,7 @@
      *                 be added
      */
     protected void addOverviewComment(Content htmltree) {
-        if (!utils.getBody(configuration.overviewElement).isEmpty()) {
+        if (!utils.getFullBody(configuration.overviewElement).isEmpty()) {
             htmltree.addContent(getMarkerAnchor(SectionName.OVERVIEW_DESCRIPTION));
             addInlineComment(configuration.overviewElement, htmltree);
         }
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java	Wed Jul 05 22:19:40 2017 +0200
@@ -143,19 +143,6 @@
         Content packageHead = new StringContent(heading);
         tHeading.addContent(packageHead);
         div.addContent(tHeading);
-        addDeprecationInfo(div);
-        if (!utils.getBody(packageElement).isEmpty() && !configuration.nocomment) {
-            HtmlTree docSummaryDiv = new HtmlTree(HtmlTag.DIV);
-            docSummaryDiv.addStyle(HtmlStyle.docSummary);
-            addSummaryComment(packageElement, docSummaryDiv);
-            div.addContent(docSummaryDiv);
-            Content space = Contents.SPACE;
-            Content descLink = getHyperLink(getDocLink(
-                    SectionName.PACKAGE_DESCRIPTION),
-                    contents.descriptionLabel, "", "");
-            Content descPara = new HtmlTree(HtmlTag.P, contents.seeLabel, space, descLink);
-            div.addContent(descPara);
-        }
         if (configuration.allowTag(HtmlTag.MAIN)) {
             mainTree.addContent(div);
         } else {
@@ -259,19 +246,9 @@
     @Override
     public void addPackageDescription(Content packageContentTree) {
         if (!utils.getBody(packageElement).isEmpty()) {
-            packageContentTree.addContent(
-                    getMarkerAnchor(SectionName.PACKAGE_DESCRIPTION));
-            Content h2Content = new StringContent(
-                    configuration.getText("doclet.Package_Description",
-                    packageElement.isUnnamed() ? "" : utils.getPackageName(packageElement)));
-            Content heading = HtmlTree.HEADING(HtmlConstants.PACKAGE_HEADING, true, h2Content);
-            if (configuration.allowTag(HtmlTag.SECTION)) {
-                sectionTree.addContent(heading);
-                addInlineComment(packageElement, sectionTree);
-            } else {
-                packageContentTree.addContent(heading);
-                addInlineComment(packageElement, packageContentTree);
-            }
+            Content tree = configuration.allowTag(HtmlTag.SECTION) ? sectionTree : packageContentTree;
+            addDeprecationInfo(tree);
+            addInlineComment(packageElement, tree);
         }
     }
 
@@ -284,6 +261,9 @@
                 ? sectionTree
                 : packageContentTree;
         addTagsInfo(packageElement, htmlTree);
+        if (configuration.allowTag(HtmlTag.SECTION)) {
+            packageContentTree.addContent(sectionTree);
+        }
     }
 
     /**
@@ -292,7 +272,6 @@
     @Override
     public void addPackageContent(Content contentTree, Content packageContentTree) {
         if (configuration.allowTag(HtmlTag.MAIN)) {
-            packageContentTree.addContent(sectionTree);
             mainTree.addContent(packageContentTree);
             contentTree.addContent(mainTree);
         } else {
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriterImpl.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriterImpl.java	Wed Jul 05 22:19:40 2017 +0200
@@ -147,7 +147,7 @@
     @Override
     public void addComments(ExecutableElement property, Content propertyDocTree) {
         TypeElement holder = (TypeElement)property.getEnclosingElement();
-        if (!utils.getBody(property).isEmpty()) {
+        if (!utils.getFullBody(property).isEmpty()) {
             if (holder.equals(typeElement) ||
                     (!utils.isPublic(holder) || utils.isLinkable(holder))) {
                 writer.addInlineComment(property, propertyDocTree);
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties	Wed Jul 05 22:19:40 2017 +0200
@@ -97,7 +97,6 @@
 doclet.deprecated_annotation_type_members=deprecated annotation type elements
 doclet.Generated_Docs_Untitled=Generated Documentation (Untitled)
 doclet.Other_Packages=Other Packages
-doclet.Package_Description=Package {0} Description
 doclet.Description=Description
 doclet.Specified_By=Specified by:
 doclet.in_interface=in interface
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/AbstractDoclet.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/AbstractDoclet.java	Wed Jul 05 22:19:40 2017 +0200
@@ -40,7 +40,6 @@
 import jdk.javadoc.internal.doclets.toolkit.builders.BuilderFactory;
 import jdk.javadoc.internal.doclets.toolkit.util.ClassTree;
 import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
-import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
 import jdk.javadoc.internal.doclets.toolkit.util.InternalException;
 import jdk.javadoc.internal.doclets.toolkit.util.PackageListWriter;
 import jdk.javadoc.internal.doclets.toolkit.util.ResourceIOException;
@@ -112,8 +111,6 @@
             return false;
         }
 
-        boolean dumpOnError = false;  // set true to always show stack traces
-
         try {
             startGeneration(docEnv);
             return true;
@@ -128,16 +125,16 @@
                     messages.error("doclet.exception.write.file",
                             e.fileName.getPath(), e.getCause());
             }
-            dumpStack(dumpOnError, e);
+            dumpStack(configuration.dumpOnError, e);
 
         } catch (ResourceIOException e) {
             messages.error("doclet.exception.read.resource",
                     e.resource.getPath(), e.getCause());
-            dumpStack(dumpOnError, e);
+            dumpStack(configuration.dumpOnError, e);
 
         } catch (SimpleDocletException e) {
             configuration.reporter.print(ERROR, e.getMessage());
-            dumpStack(dumpOnError, e);
+            dumpStack(configuration.dumpOnError, e);
 
         } catch (InternalException e) {
             configuration.reporter.print(ERROR, e.getMessage());
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/CommentUtils.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/CommentUtils.java	Wed Jul 05 22:19:40 2017 +0200
@@ -108,27 +108,22 @@
         Utils utils = config.utils;
         String klassName = utils.getSimpleName(utils.getEnclosingTypeElement(e));
 
-        List<DocTree> fs = new ArrayList<>();
-        fs.add(treeFactory.newTextTree(config.getText("doclet.enum_values_doc.firstsentence")));
-
-        List<DocTree> body = new ArrayList<>();
-        body.add(treeFactory.newTextTree(config.getText("doclet.enum_values_doc.body", klassName)));
+        List<DocTree> fullBody = new ArrayList<>();
+        fullBody.add(treeFactory.newTextTree(config.getText("doclet.enum_values_doc.fullbody", klassName)));
 
         List<DocTree> descriptions = new ArrayList<>();
         descriptions.add(treeFactory.newTextTree(config.getText("doclet.enum_values_doc.return")));
 
         List<DocTree> tags = new ArrayList<>();
         tags.add(treeFactory.newReturnTree(descriptions));
-        DocCommentTree docTree = treeFactory.newDocCommentTree(fs, body, tags);
+        DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, tags);
         dcTreesMap.put(e, new DocCommentDuo(null, docTree));
     }
 
     public void setEnumValueOfTree(Configuration config, Element e) {
-        List<DocTree> fs = new ArrayList<>();
-        fs.add(treeFactory.newTextTree(config.getText("doclet.enum_valueof_doc.firstsentence")));
 
-        List<DocTree> body = new ArrayList<>();
-        body.add(treeFactory.newTextTree(config.getText("doclet.enum_valueof_doc.body")));
+        List<DocTree> fullBody = new ArrayList<>();
+        fullBody.add(treeFactory.newTextTree(config.getText("doclet.enum_valueof_doc.fullbody")));
 
         List<DocTree> tags = new ArrayList<>();
 
@@ -156,7 +151,7 @@
         ref = treeFactory.newReferenceTree("java.lang.NullPointerException");
         tags.add(treeFactory.newThrowsTree(ref, throwsDescs));
 
-        DocCommentTree docTree = treeFactory.newDocCommentTree(fs, body, tags);
+        DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, tags);
 
         dcTreesMap.put(e, new DocCommentDuo(null, docTree));
     }
@@ -190,11 +185,9 @@
         return new DocCommentDuo(treePath.getTreePath(), dcTree);
     }
 
-    public void setDocCommentTree(Element element, List<DocTree> firstSentence,
-            List<DocTree> bodyTags, List<DocTree> blockTags, Utils utils) {
-        DocCommentTree docTree = treeFactory.newDocCommentTree(firstSentence,
-                                                      bodyTags,
-                                                      blockTags);
+    public void setDocCommentTree(Element element, List<DocTree> fullBody,
+            List<DocTree> blockTags, Utils utils) {
+        DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, blockTags);
         dcTreesMap.put(element, new DocCommentDuo(null, docTree));
         // There maybe an entry with the original comments usually null,
         // therefore remove that entry if it exists, and allow a new one
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Configuration.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Configuration.java	Wed Jul 05 22:19:40 2017 +0200
@@ -281,6 +281,8 @@
 
     private String pkglistUrlForLinkOffline;
 
+    public boolean dumpOnError = false;
+
     private List<GroupContainer> groups;
 
     public abstract Messages getMessages();
@@ -616,6 +618,13 @@
                     showversion = true;
                     return true;
                 }
+            },
+            new Hidden(resources, "--dump-on-error") {
+                @Override
+                public boolean process(String opt, ListIterator<String> args) {
+                    dumpOnError = true;
+                    return true;
+                }
             }
         };
         Set<Doclet.Option> set = new TreeSet<>();
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/MemberSummaryBuilder.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/MemberSummaryBuilder.java	Wed Jul 05 22:19:40 2017 +0200
@@ -386,8 +386,8 @@
         CommentUtils cmtutils = configuration.cmtUtils;
         final boolean isSetter = isSetter(member);
         final boolean isGetter = isGetter(member);
-        List<DocTree> firstSentence = new ArrayList<>();
-        List<DocTree> bodyTags = new ArrayList<>();
+
+        List<DocTree> fullBody = new ArrayList<>();
         List<DocTree> blockTags = new ArrayList<>();
         if (isGetter || isSetter) {
             //add "[GS]ets the value of the property PROPERTY_NAME."
@@ -395,21 +395,21 @@
                 String text = MessageFormat.format(
                         configuration.getText("doclet.PropertySetterWithName"),
                         utils.propertyName((ExecutableElement)member));
-                firstSentence.addAll(cmtutils.makeFirstSentenceTree(text));
+                fullBody.addAll(cmtutils.makeFirstSentenceTree(text));
             }
             if (isGetter) {
                 String text = MessageFormat.format(
                         configuration.getText("doclet.PropertyGetterWithName"),
                         utils.propertyName((ExecutableElement) member));
-                firstSentence.addAll(cmtutils.makeFirstSentenceTree(text));
+                fullBody.addAll(cmtutils.makeFirstSentenceTree(text));
             }
             List<? extends DocTree> propertyTags = utils.getBlockTags(property, "propertyDescription");
             if (propertyTags.isEmpty()) {
-                List<? extends DocTree> comment = utils.getBody(property);
+                List<? extends DocTree> comment = utils.getFullBody(property);
                 blockTags.addAll(cmtutils.makePropertyDescriptionTree(comment));
             }
         } else {
-            firstSentence.addAll(utils.getBody(property));
+            fullBody.addAll(utils.getFullBody(property));
         }
 
         // copy certain tags
@@ -452,7 +452,7 @@
                 blockTags.add(cmtutils.makeSeeTree(sb.toString(), setter));
             }
         }
-        cmtutils.setDocCommentTree(member, firstSentence, bodyTags, blockTags, utils);
+        cmtutils.setDocCommentTree(member, fullBody, blockTags, utils);
     }
 
     /**
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/MethodBuilder.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/MethodBuilder.java	Wed Jul 05 22:19:40 2017 +0200
@@ -210,7 +210,7 @@
     public void buildMethodComments(XMLNode node, Content methodDocTree) {
         if (!configuration.nocomment) {
             ExecutableElement method = currentMethod;
-            if (utils.getBody(currentMethod).isEmpty()) {
+            if (utils.getFullBody(currentMethod).isEmpty()) {
                 DocFinder.Output docs = DocFinder.search(configuration,
                         new DocFinder.Input(utils, currentMethod));
                 if (docs.inlineTags != null && !docs.inlineTags.isEmpty())
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclet.xml	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclet.xml	Wed Jul 05 22:19:40 2017 +0200
@@ -42,6 +42,8 @@
 
     <PackageDoc>
         <Content>
+            <PackageDescription/>
+            <PackageTags/>
             <Summary>
                 <InterfaceSummary/>
                 <ClassSummary/>
@@ -50,8 +52,6 @@
                 <ErrorSummary/>
                 <AnnotationTypeSummary/>
             </Summary>
-            <PackageDescription/>
-            <PackageTags/>
         </Content>
     </PackageDoc>
 
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties	Wed Jul 05 22:19:40 2017 +0200
@@ -207,22 +207,21 @@
 doclet.0_and_1={0} and {1}
 
 #Documentation for Enums
-doclet.enum_values_doc.firstsentence=\
-Returns an array containing the constants of this enum type, in\n\
-the order they are declared.
-doclet.enum_values_doc.body=\  This method may be used to iterate\n\
+doclet.enum_values_doc.fullbody=\
+ Returns an array containing the constants of this enum type, in\n\
+ the order they are declared. This method may be used to iterate\n\
  over the constants as follows:\n\
  <pre>\n\
  for ({0} c : {0}.values())\n\
  &nbsp;   System.out.println(c);\n\
  </pre>
+
 doclet.enum_values_doc.return=\
 an array containing the constants of this enum type, in the order they are declared
 
-doclet.enum_valueof_doc.firstsentence=\
-Returns the enum constant of this type with the specified name.
-doclet.enum_valueof_doc.body=\n\
-The string must match <i>exactly</i> an identifier used to declare an\n\
+doclet.enum_valueof_doc.fullbody=\
+ Returns the enum constant of this type with the specified name.\n\
+ The string must match <i>exactly</i> an identifier used to declare an\n\
  enum constant in this type.  (Extraneous whitespace characters are \n\
  not permitted.)
 
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletWriter.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletWriter.java	Wed Jul 05 22:19:40 2017 +0200
@@ -221,7 +221,7 @@
             List<Taglet> taglets, TagletWriter writer, Content output) {
         Utils utils = writer.configuration().utils;
         tagletManager.checkTags(utils, element, utils.getBlockTags(element), false);
-        tagletManager.checkTags(utils, element, utils.getBody(element), true);
+        tagletManager.checkTags(utils, element, utils.getFullBody(element), true);
         for (Taglet taglet : taglets) {
             if (utils.isTypeElement(element) && taglet instanceof ParamTaglet) {
                 //The type parameters are documented in a special section away
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocFinder.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocFinder.java	Wed Jul 05 22:19:40 2017 +0200
@@ -251,7 +251,7 @@
             //We want overall documentation.
             output.inlineTags = input.isFirstSentence
                     ? utils.getFirstSentenceTrees(input.element)
-                    : utils.getBody(input.element);
+                    : utils.getFullBody(input.element);
             output.holder = input.element;
         } else {
             input.taglet.inherit(input, output);
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java	Wed Jul 05 22:19:40 2017 +0200
@@ -1453,7 +1453,7 @@
     public void setEnumDocumentation(TypeElement elem) {
         for (Element e : getMethods(elem)) {
             ExecutableElement ee = (ExecutableElement)e;
-            if (!getBody(e).isEmpty()) // if already set skip it please
+            if (!getFullBody(e).isEmpty()) // ignore if already set
                 continue;
             if (ee.getSimpleName().contentEquals("values") && ee.getParameters().isEmpty()) {
                 configuration.cmtUtils.setEnumValuesTree(configuration, e);
@@ -2939,12 +2939,18 @@
         return dcTree;
     }
 
+    public List<? extends DocTree> getFullBody(Element element) {
+        DocCommentTree docCommentTree = getDocCommentTree(element);
+            return (docCommentTree == null)
+                    ? Collections.emptyList()
+                    : docCommentTree.getFullBody();
+    }
+
     public List<? extends DocTree> getBody(Element element) {
         DocCommentTree docCommentTree = getDocCommentTree(element);
-        if (docCommentTree == null)
-            return Collections.emptyList();
-
-        return docCommentTree.getFullBody();
+        return (docCommentTree == null)
+                ? Collections.emptyList()
+                : docCommentTree.getFullBody();
     }
 
     public List<? extends DocTree> getDeprecatedTrees(Element element) {
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ElementsTable.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ElementsTable.java	Wed Jul 05 22:19:40 2017 +0200
@@ -75,6 +75,7 @@
 import jdk.javadoc.doclet.DocletEnvironment.ModuleMode;
 
 import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
+import static jdk.javadoc.internal.tool.Main.Result.*;
 import static jdk.javadoc.internal.tool.JavadocTool.isValidClassName;
 
 /**
@@ -158,6 +159,7 @@
     private final Location location;
     private final Modules modules;
     private final Map<ToolOption, Object> opts;
+    private final Messager messager;
 
     private final Map<String, Entry> entries = new LinkedHashMap<>();
 
@@ -201,6 +203,8 @@
         this.fm = toolEnv.fileManager;
         this.modules = Modules.instance(context);
         this.opts = opts;
+        this.messager = Messager.instance0(context);
+
         this.location = modules.multiModuleMode
                 ? StandardLocation.MODULE_SOURCE_PATH
                 : toolEnv.fileManager.hasLocation(StandardLocation.SOURCE_PATH)
@@ -339,9 +343,9 @@
      * This is a terminal operation, thus no further modifications
      * are allowed to the specified data sets.
      *
-     * @throws IOException if an error occurs
+     * @throws ToolException if an error occurs
      */
-    void analyze() throws IOException {
+    void analyze() throws ToolException {
         // compute the specified element, by expanding module dependencies
         computeSpecifiedModules();
 
@@ -354,7 +358,6 @@
         // compute the packages belonging to all the specified modules
         Set<PackageElement> expandedModulePackages = computeModulePackages();
         initializeIncludedSets(expandedModulePackages);
-
     }
 
     ElementsTable classTrees(com.sun.tools.javac.util.List<JCCompilationUnit> classTrees) {
@@ -363,16 +366,17 @@
     }
 
     @SuppressWarnings("unchecked")
-    ElementsTable scanSpecifiedItems() throws IOException {
+    ElementsTable scanSpecifiedItems() throws ToolException {
 
         // scan modules specified on the command line
         List<String> moduleNames = (List<String>) opts.computeIfAbsent(ToolOption.MODULE,
                 s -> Collections.EMPTY_LIST);
         List<String> mlist = new ArrayList<>();
         for (String m : moduleNames) {
-            Location moduleLoc = fm.getModuleLocation(location, m);
+            Location moduleLoc = getModuleLocation(location, m);
             if (moduleLoc == null) {
-                toolEnv.error("main.module_not_found", m);
+                String text = messager.getText("main.module_not_found", m);
+                throw new ToolException(CMDERR, text);
             } else {
                 mlist.add(m);
                 ModuleSymbol msym = syms.enterModule(names.fromString(m));
@@ -457,7 +461,7 @@
     }
 
     @SuppressWarnings("unchecked")
-    private void computeSubpackages() throws IOException {
+    private void computeSubpackages() throws ToolException {
         ((List<String>) opts.computeIfAbsent(ToolOption.EXCLUDE, v -> Collections.EMPTY_LIST))
                 .stream()
                 .map((packageName) -> new ModulePackage(packageName))
@@ -469,7 +473,14 @@
 
         for (ModulePackage modpkg : subPackages) {
             Location packageLocn = getLocation(modpkg);
-            for (JavaFileObject fo : fm.list(packageLocn, modpkg.packageName, sourceKinds, true)) {
+            Iterable<JavaFileObject> list = null;
+            try {
+                list = fm.list(packageLocn, modpkg.packageName, sourceKinds, true);
+            } catch (IOException ioe) {
+                String text = messager.getText("main.file.manager.list", modpkg.packageName);
+                throw new ToolException(SYSERR, text, ioe);
+            }
+            for (JavaFileObject fo : list) {
                 String binaryName = fm.inferBinaryName(packageLocn, fo);
                 String pn = getPackageName(binaryName);
                 String simpleName = getSimpleName(binaryName);
@@ -554,22 +565,28 @@
         specifiedModuleElements = Collections.unmodifiableSet(result);
     }
 
-    private Set<PackageElement> getAllModulePackages(ModuleElement mdle) throws IOException {
+    private Set<PackageElement> getAllModulePackages(ModuleElement mdle) throws ToolException {
         Set<PackageElement> result = new HashSet<>();
-        ModuleSymbol msym = (ModuleSymbol)mdle;
-        Location msymloc = fm.getModuleLocation(location, msym.name.toString());
-        for (JavaFileObject fo : fm.list(msymloc, "", sourceKinds, true)) {
-            if (fo.getName().endsWith("module-info.java"))
-                continue;
-            String binaryName = fm.inferBinaryName(msymloc, fo);
-            String pn = getPackageName(binaryName);
-            PackageSymbol psym = syms.enterPackage(msym, names.fromString(pn));
-            result.add((PackageElement)psym);
+        ModuleSymbol msym = (ModuleSymbol) mdle;
+        Location msymloc = getModuleLocation(location, msym.name.toString());
+        try {
+            for (JavaFileObject fo : fm.list(msymloc, "", sourceKinds, true)) {
+                if (fo.getName().endsWith("module-info.java"))
+                    continue;
+                String binaryName = fm.inferBinaryName(msymloc, fo);
+                String pn = getPackageName(binaryName);
+                PackageSymbol psym = syms.enterPackage(msym, names.fromString(pn));
+                result.add((PackageElement) psym);
+            }
+
+        } catch (IOException ioe) {
+            String text = messager.getText("main.file.manager.list", msymloc.getName());
+            throw new ToolException(SYSERR, text, ioe);
         }
         return result;
     }
 
-    private Set<PackageElement> computeModulePackages() throws IOException {
+    private Set<PackageElement> computeModulePackages() throws ToolException {
         final AccessKind accessValue = accessFilter.getAccessValue(ElementKind.PACKAGE);
         final boolean documentAllModulePackages = (accessValue == AccessKind.PACKAGE ||
                 accessValue == AccessKind.PRIVATE);
@@ -662,10 +679,10 @@
         includedTypeElements = Collections.unmodifiableSet(iclasses);
     }
 
-    /**
+    /*
      * Computes the included packages and freezes the specified packages list.
      */
-    private void computeSpecifiedPackages() throws IOException {
+    private void computeSpecifiedPackages() throws ToolException {
 
         computeSubpackages();
 
@@ -683,7 +700,7 @@
             if (pkg != null) {
                 packlist.add(pkg);
             } else {
-                toolEnv.warning("main.package_not_found", modpkg.toString());
+                messager.printWarningUsingKey("main.package_not_found", modpkg.toString());
             }
         });
         specifiedPackageElements = Collections.unmodifiableSet(packlist);
@@ -693,7 +710,7 @@
      * Adds all classes as well as inner classes, to the specified
      * list.
      */
-    private void computeSpecifiedTypes() {
+    private void computeSpecifiedTypes() throws ToolException {
         Set<TypeElement> classes = new LinkedHashSet<>();
         classDecList.stream().filter((def) -> (shouldDocument(def.sym))).forEach((def) -> {
             TypeElement te = (TypeElement) def.sym;
@@ -701,24 +718,28 @@
                 addAllClasses(classes, te, true);
             }
         });
-        classArgList.forEach((className) -> {
+        for (String className : classArgList) {
             TypeElement te = toolEnv.loadClass(className);
             if (te == null) {
-                toolEnv.error("javadoc.class_not_found", className);
+                String text = messager.getText("javadoc.class_not_found", className);
+                throw new ToolException(CMDERR, text);
             } else {
                 addAllClasses(classes, te, true);
             }
-        });
+        }
         specifiedTypeElements = Collections.unmodifiableSet(classes);
     }
 
     private void addFilesForParser(Collection<JavaFileObject> result,
-            Collection<ModulePackage> collection, boolean recurse) throws IOException {
+            Collection<ModulePackage> collection,
+            boolean recurse) throws ToolException {
         for (ModulePackage modpkg : collection) {
             toolEnv.notice("main.Loading_source_files_for_package", modpkg.toString());
             List<JavaFileObject> files = getFiles(modpkg, recurse);
             if (files.isEmpty()) {
-                    toolEnv.error("main.no_source_files_for_package", modpkg.toString());
+                String text = messager.getText("main.no_source_files_for_package",
+                        modpkg.toString());
+                throw new ToolException(CMDERR, text);
             } else {
                 result.addAll(files);
             }
@@ -732,7 +753,7 @@
      * @return a list of java file objects
      * @throws IOException if an error occurs
      */
-    List<JavaFileObject> getFilesToParse() throws IOException {
+    List<JavaFileObject> getFilesToParse() throws ToolException {
         List<JavaFileObject> result = new ArrayList<>();
         addFilesForParser(result, cmdLinePackages, false);
         addFilesForParser(result, subPackages, true);
@@ -744,9 +765,10 @@
      *
      * @param packageName the specified package
      * @return the set of file objects for the specified package
-     * @throws IOException if an error occurs while accessing the files
+     * @throws ToolException if an error occurs while accessing the files
      */
-    private List<JavaFileObject> getFiles(ModulePackage modpkg, boolean recurse) throws IOException {
+    private List<JavaFileObject> getFiles(ModulePackage modpkg,
+            boolean recurse) throws ToolException {
         Entry e = getEntry(modpkg);
         // The files may have been found as a side effect of searching for subpackages
         if (e.files != null) {
@@ -759,12 +781,18 @@
             return Collections.emptyList();
         }
         String pname = modpkg.packageName;
-        for (JavaFileObject fo : fm.list(packageLocn, pname, sourceKinds, recurse)) {
-            String binaryName = fm.inferBinaryName(packageLocn, fo);
-            String simpleName = getSimpleName(binaryName);
-            if (isValidClassName(simpleName)) {
-                lb.append(fo);
+
+        try {
+            for (JavaFileObject fo : fm.list(packageLocn, pname, sourceKinds, recurse)) {
+                String binaryName = fm.inferBinaryName(packageLocn, fo);
+                String simpleName = getSimpleName(binaryName);
+                if (isValidClassName(simpleName)) {
+                    lb.append(fo);
+                }
             }
+        } catch (IOException ioe) {
+            String text = messager.getText("main.file.manager.list", pname);
+            throw new ToolException(SYSERR, text, ioe);
         }
 
         return lb.toList();
@@ -781,20 +809,30 @@
             return null;
     }
 
-    private Location getLocation(ModulePackage modpkg) throws IOException {
+    private Location getLocation(ModulePackage modpkg) throws ToolException {
         if (location != StandardLocation.MODULE_SOURCE_PATH) {
             return location;
         }
 
         if (modpkg.hasModule()) {
-            return fm.getModuleLocation(location, modpkg.moduleName);
+            return getModuleLocation(location, modpkg.moduleName);
         }
         // TODO: handle invalid results better.
         ModuleSymbol msym = findModuleOfPackageName(modpkg.packageName);
         if (msym == null) {
             return null;
         }
-        return fm.getModuleLocation(location, msym.name.toString());
+        return getModuleLocation(location, msym.name.toString());
+    }
+
+    private Location getModuleLocation(Location location, String msymName)
+            throws ToolException {
+        try {
+            return fm.getModuleLocation(location, msymName);
+        } catch (IOException ioe) {
+            String text = messager.getText("main.doclet_could_not_get_location", msymName);
+            throw new ToolException(ERROR, text, ioe);
+        }
     }
 
     private Entry getEntry(String name) {
@@ -841,7 +879,10 @@
                 }
             }
         } catch (CompletionFailure e) {
-            // quietly ignore completion failures
+            if (e.getMessage() != null)
+                messager.printWarning(e.getMessage());
+            else
+                messager.printWarningUsingKey("main.unexpected.exception", e);
         }
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/IllegalOptionValue.java	Wed Jul 05 22:19:40 2017 +0200
@@ -0,0 +1,52 @@
+/*
+ * 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.  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.javadoc.internal.tool;
+
+import static jdk.javadoc.internal.tool.Main.Result.CMDERR;
+
+/**
+ * Provides a mechanism for the javadoc tool to indicate an option
+ * decoding issue, arising from command line error.
+ *
+ * <p><b>This is NOT part of any supported API.
+ * If you write code that depends on this, you do so at your own risk.
+ * This code and its internal interfaces are subject to change or
+ * deletion without notice.</b>
+ */
+
+class IllegalOptionValue extends OptionException {
+
+    private static final long serialVersionUID = 0;
+
+    /**
+     * Constructs an object containing a runnable and a message.
+     * @param method a method to display suitable usage text
+     * @param message the detailed message
+     */
+    IllegalOptionValue(Runnable method, String message) {
+        super(CMDERR, method, message);
+    }
+}
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/JavadocTool.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/JavadocTool.java	Wed Jul 05 22:19:40 2017 +0200
@@ -27,7 +27,6 @@
 
 
 import java.io.File;
-import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.LinkedHashSet;
@@ -51,6 +50,8 @@
 import com.sun.tools.javac.util.Position;
 import jdk.javadoc.doclet.DocletEnvironment;
 
+import static jdk.javadoc.internal.tool.Main.Result.*;
+
 /**
  *  This class could be the main entry point for Javadoc when Javadoc is used as a
  *  component in a larger software system. It provides operations to
@@ -120,9 +121,10 @@
         }
     }
 
-    public DocletEnvironment getEnvironment(Map<ToolOption, Object> jdtoolOpts,
-                                      List<String> javaNames,
-                                      Iterable<? extends JavaFileObject> fileObjects) throws IOException {
+    public DocletEnvironment getEnvironment(Map<ToolOption,
+            Object> jdtoolOpts,
+            List<String> javaNames,
+            Iterable<? extends JavaFileObject> fileObjects) throws ToolException {
         toolEnv = ToolEnvironment.instance(context);
         toolEnv.initialize(jdtoolOpts);
         ElementsTable etable = new ElementsTable(context, jdtoolOpts);
@@ -133,10 +135,12 @@
         if (etable.xclasses) {
             // If -Xclasses is set, the args should be a list of class names
             for (String arg: javaNames) {
-                if (!isValidPackageName(arg)) // checks
-                    toolEnv.error("main.illegal_class_name", arg);
+                if (!isValidPackageName(arg)) { // checks
+                    String text = messager.getText("main.illegal_class_name", arg);
+                    throw new ToolException(CMDERR, text);
+                }
             }
-            if (messager.nerrors() != 0) {
+            if (messager.hasErrors()) {
                 return null;
             }
             etable.setClassArgList(javaNames);
@@ -157,19 +161,23 @@
             for (String arg: javaNames) {
                 if (fm != null && arg.endsWith(".java") && new File(arg).exists()) {
                     if (new File(arg).getName().equals("module-info.java")) {
-                        toolEnv.warning("main.file_ignored", arg);
+                        messager.printWarningUsingKey("main.file_ignored", arg);
                     } else {
                         parse(fm.getJavaFileObjects(arg), classTrees, true);
                     }
                 } else if (isValidPackageName(arg)) {
                     packageNames.add(arg);
                 } else if (arg.endsWith(".java")) {
-                    if (fm == null)
-                        throw new IllegalArgumentException();
-                    else
-                        toolEnv.error("main.file_not_found", arg);
+                    if (fm == null) {
+                        String text = messager.getText("main.assertion.error", "fm == null");
+                        throw new ToolException(ABNORMAL, text);
+                    } else {
+                        String text = messager.getText("main.file_not_found", arg);
+                        throw new ToolException(ERROR, text);
+                    }
                 } else {
-                    toolEnv.error("main.illegal_package_name", arg);
+                    String text = messager.getText("main.illegal_package_name", arg);
+                    throw new ToolException(CMDERR, text);
                 }
             }
 
@@ -185,7 +193,7 @@
             parse(etable.getFilesToParse(), packageTrees, false);
             modules.enter(packageTrees.toList(), null);
 
-            if (messager.nerrors() != 0) {
+            if (messager.hasErrors()) {
                 return null;
             }
 
@@ -197,10 +205,19 @@
             enterDone = true;
             etable.analyze();
         } catch (CompletionFailure cf) {
-            toolEnv.printError(cf.getMessage());
-        } catch (Abort ex) {}
+            throw new ToolException(ABNORMAL, cf.getMessage(), cf);
+        } catch (Abort abort) {
+            if (messager.hasErrors()) {
+                // presumably a message has been emitted, keep silent
+                throw new ToolException(ABNORMAL, "", abort);
+            } else {
+                String text = messager.getText("main.internal.error");
+                Throwable t = abort.getCause() == null ? abort : abort.getCause();
+                throw new ToolException(ABNORMAL, text, t);
+            }
+        }
 
-        if (messager.nerrors() != 0)
+        if (messager.hasErrors())
             return null;
 
         toolEnv.docEnv = new DocEnvImpl(toolEnv, etable);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/JavadocToolProvider.java	Wed Jul 05 22:19:40 2017 +0200
@@ -0,0 +1,47 @@
+/*
+ * 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.  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.javadoc.internal.tool;
+
+import java.io.PrintWriter;
+import java.util.spi.ToolProvider;
+
+/**
+ * An implementation of the {@link java.util.spi.ToolProvider ToolProvider} SPI,
+ * providing access to JDK documentation tool, javadoc.
+ *
+ * @since 9
+ */
+// This is currently a stand-alone top-level class so that it can easily be excluded
+// from interims builds of javadoc, used while building JDK.
+public class JavadocToolProvider implements ToolProvider {
+    public String name() {
+        return "javadoc";
+    }
+
+    public int run(PrintWriter out, PrintWriter err, String... args) {
+        return Main.execute(args, out, err);
+    }
+}
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Main.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Main.java	Wed Jul 05 22:19:40 2017 +0200
@@ -60,18 +60,61 @@
      */
     public static int execute(String... args) {
         Start jdoc = new Start();
-        return jdoc.begin(args);
+        return jdoc.begin(args).exitCode;
+    }
+
+    /**
+     * Programmatic interface.
+     *
+     * @param writer a stream for all output
+     * @param args The command line parameters.
+     * @return The return code.
+     */
+    public static int execute(String[] args, PrintWriter writer) {
+        Start jdoc = new Start(writer, writer);
+        return jdoc.begin(args).exitCode;
     }
 
     /**
      * Programmatic interface.
      *
-     * @param writer PrintWriter to receive notice messages.
+     * @param outWriter a stream for expected output
+     * @param errWriter a stream for diagnostic output
      * @param args The command line parameters.
      * @return The return code.
      */
-    public static int execute(String[] args, PrintWriter writer) {
-        Start jdoc = new Start(writer);
-        return jdoc.begin(args);
+    public static int execute(String[] args, PrintWriter outWriter, PrintWriter errWriter) {
+        Start jdoc = new Start(outWriter, errWriter);
+        return jdoc.begin(args).exitCode;
+    }
+
+    public static enum Result {
+        /** completed with no errors */
+        OK(0),
+        /** Completed with reported errors */
+        ERROR(1),
+        /** Bad command-line arguments */
+        CMDERR(2),
+        /** System error or resource exhaustion */
+        SYSERR(3),
+        /** Terminated abnormally */
+        ABNORMAL(4);
+
+        private static final long serialVersionUID = 1L;
+
+        Result(int exitCode) {
+            this.exitCode = exitCode;
+        }
+
+        public boolean isOK() {
+            return (exitCode == 0);
+        }
+
+        public final int exitCode;
+
+        @Override
+        public String toString() {
+            return name() + '(' + exitCode + ')';
+        }
     }
 }
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Messager.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Messager.java	Wed Jul 05 22:19:40 2017 +0200
@@ -48,10 +48,8 @@
 
 /**
  * Utility for integrating with javadoc tools and for localization.
- * Handle Resources. Access to error and warning counts.
- * Message formatting.
- * <br>
- * Also provides implementation for DocErrorReporter.
+ * Handle resources, access to error and warning counts and
+ * message formatting.
  *
  *  <p><b>This is NOT part of any supported API.
  *  If you write code that depends on this, you do so at your own risk.
@@ -139,10 +137,6 @@
         }
     }
 
-    public static class ExitJavadoc extends Error {
-        private static final long serialVersionUID = 0;
-    }
-
     final String programName;
 
     private Locale locale;
@@ -165,8 +159,8 @@
     /**
      * Constructor
      * @param programName  Name of the program (for error messages).
-     * @param stdOut    Stream for notices etc.
-     * @param stdErr    Stream for errors and warnings
+     * @param outWriter    Stream for notices etc.
+     * @param errWriter    Stream for errors and warnings
      */
     @SuppressWarnings("deprecation")
     public Messager(Context context, String programName, PrintWriter outWriter, PrintWriter errWriter) {
@@ -240,7 +234,7 @@
             report(DiagnosticType.ERROR, prefix, msg);
             return;
         }
-        incrementErrorCount(prefix, msg);
+        printError(prefix, msg);
     }
 
     public void printError(Element e, String msg) {
@@ -249,10 +243,15 @@
             report(DiagnosticType.ERROR, prefix, msg);
             return;
         }
-        incrementErrorCount(prefix, msg);
+        printError(prefix, msg);
     }
 
-    private void incrementErrorCount(String prefix, String msg) {
+    public void printErrorUsingKey(String key, Object... args) {
+        printError((Element)null, getText(key, args));
+    }
+
+    // print the error and increment count
+    private void printError(String prefix, String msg) {
         if (nerrors < MaxErrors) {
             PrintWriter errWriter = getWriter(WriterKind.ERROR);
             printRawLines(errWriter, prefix + ": " + getText("javadoc.error") + " - " + msg);
@@ -272,13 +271,21 @@
         printWarning((DocTreePath)null, msg);
     }
 
+    public void printWarningUsingKey(String key, Object... args) {
+        printWarning((Element)null, getText(key, args));
+    }
+
+    public void printWarning(Element e, String key, Object... args) {
+        printWarning(getText(key, args));
+    }
+
     public void printWarning(DocTreePath path, String msg) {
         String prefix = getDiagSource(path);
         if (diagListener != null) {
             report(DiagnosticType.WARNING, prefix, msg);
             return;
         }
-        incrementWarningCount(prefix, msg);
+        printWarning(prefix, msg);
     }
 
     public void printWarning(Element e, String msg) {
@@ -287,10 +294,11 @@
             report(DiagnosticType.WARNING, prefix, msg);
             return;
         }
-        incrementWarningCount(prefix, msg);
+        printWarning(prefix, msg);
     }
 
-    private void incrementWarningCount(String prefix, String msg) {
+    // print the warning and increment count
+    private void printWarning(String prefix, String msg) {
         if (nwarnings < MaxWarnings) {
             PrintWriter warnWriter = getWriter(WriterKind.WARNING);
             printRawLines(warnWriter, prefix + ": " + getText("javadoc.warning") + " - " + msg);
@@ -342,50 +350,6 @@
     }
 
     /**
-     * Print error message, increment error count.
-     *
-     * @param key selects message from resource
-     */
-    public void error(Element e, String key, Object... args) {
-        printError(e, getText(key, args));
-    }
-
-    /**
-     * Print error message, increment error count.
-     *
-     * @param key selects message from resource
-     */
-    public void error(DocTreePath path, String key, Object... args) {
-        printError(path, getText(key, args));
-    }
-
-    public void error(String key, Object... args) {
-        printError((Element)null, getText(key, args));
-    }
-
-    public void warning(String key, Object... args) {
-        printWarning((Element)null, getText(key, args));
-    }
-
-    /**
-     * Print warning message, increment warning count.
-     *
-     * @param key selects message from resource
-     */
-    public void warning(Element e, String key, Object... args) {
-        printWarning(e, getText(key, args));
-    }
-
-    /**
-     * Print warning message, increment warning count.
-     *
-     * @param key selects message from resource
-     */
-    public void warning(DocTreePath path, String key, Object... args) {
-        printWarning(path, getText(key, args));
-    }
-
-    /**
      * Print a message.
      *
      * @param key selects message from resource
@@ -395,21 +359,23 @@
     }
 
     /**
-     * Return total number of errors, including those recorded
-     * in the compilation log.
+     * Returns true if errors have been recorded.
      */
-    public int nerrors() { return nerrors; }
+    public boolean hasErrors() {
+        return nerrors != 0;
+    }
 
     /**
-     * Return total number of warnings, including those recorded
-     * in the compilation log.
+     * Returns true if warnings have been recorded.
      */
-    public int nwarnings() { return nwarnings; }
+    public boolean hasWarnings() {
+        return nwarnings != 0;
+    }
 
     /**
      * Print exit message.
      */
-    public void exitNotice() {
+    public void printErrorWarningCounts() {
         if (nerrors > 0) {
             notice((nerrors > 1) ? "main.errors" : "main.error",
                    "" + nerrors);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/OptionException.java	Wed Jul 05 22:19:40 2017 +0200
@@ -0,0 +1,80 @@
+/*
+ * 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.  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.javadoc.internal.tool;
+
+import jdk.javadoc.internal.tool.Main.Result;
+
+/**
+ * Provides a general mechanism for the javadoc tool to indicate an option
+ * decoding issue.
+ *
+ * <p><b>This is NOT part of any supported API.
+ * If you write code that depends on this, you do so at your own risk.
+ * This code and its internal interfaces are subject to change or
+ * deletion without notice.</b>
+ */
+
+class OptionException extends Exception {
+
+    private static final long serialVersionUID = 0;
+
+    public final Result result;
+    public final String message;
+    public final Runnable m;
+
+    /**
+     * Constructs an object with a result, runnable and a message
+     * to be printed out by the catcher. The runnable can be invoked
+     * by the catcher to display the usage text.
+     * @param result the exit code
+     * @param method the method to invoke
+     * @param message the detailed message
+     */
+    public OptionException(Result result, Runnable method, String message) {
+        this.result = result;
+        this.m = method;
+        this.message = message;
+        if (result == null || result.isOK() || method == null || message == null) {
+            throw new AssertionError("result == null || result.isOK() || " +
+                    "method == null || message == null");
+        }
+    }
+
+    /**
+     * Constructs an object with a result and a runnable.
+     * The runnable can be invoked by the catcher to display the usage text.
+     * @param result the exit code
+     * @param method the method to invoke
+     */
+    public OptionException(Result result, Runnable method) {
+        this.result = result;
+        this.m = method;
+        this.message = null;
+        if (result == null || method == null) {
+            throw new AssertionError("result == null || method == null");
+        }
+    }
+}
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java	Wed Jul 05 22:19:40 2017 +0200
@@ -26,7 +26,6 @@
 package jdk.javadoc.internal.tool;
 
 import java.io.File;
-import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.nio.file.Path;
@@ -65,11 +64,12 @@
 import jdk.javadoc.doclet.Doclet;
 import jdk.javadoc.doclet.Doclet.Option;
 import jdk.javadoc.doclet.DocletEnvironment;
-import jdk.javadoc.internal.doclets.toolkit.Resources;
+import jdk.javadoc.internal.tool.Main.Result;
 
 import static javax.tools.DocumentationTool.Location.*;
 
 import static com.sun.tools.javac.main.Option.*;
+import static jdk.javadoc.internal.tool.Main.Result.*;
 
 /**
  * Main program of Javadoc.
@@ -119,20 +119,21 @@
     private JavaFileManager fileManager;
 
     Start() {
-        this(null, null, null, null, null);
+        this(null, null, null, null, null, null);
     }
 
-    Start(PrintWriter writer) {
-        this(null, null, writer, null, null);
+    Start(PrintWriter outWriter, PrintWriter errWriter) {
+        this(null, null, outWriter, errWriter, null, null);
     }
 
-    Start(Context context, String programName, PrintWriter writer,
+    Start(Context context, String programName,
+            PrintWriter outWriter, PrintWriter errWriter,
             String docletName, ClassLoader classLoader) {
         this.context = context == null ? new Context() : context;
         String pname = programName == null ? ProgramName : programName;
-        this.messager = writer == null
+        this.messager = (outWriter == null && errWriter == null)
                 ? new Messager(this.context, pname)
-                : new Messager(this.context, pname, writer, writer);
+                : new Messager(this.context, pname, outWriter, errWriter);
         this.docletName = docletName;
         this.classLoader = classLoader;
         this.docletClass = null;
@@ -169,41 +170,28 @@
      */
     @Override
     void usage() {
-        usage(true);
-    }
-
-    void usage(boolean exit) {
-        usage("main.usage", "-help", "main.usage.foot");
-
-        if (exit)
-            throw new Messager.ExitJavadoc();
+        usage("main.usage", OptionKind.STANDARD, "main.usage.foot");
     }
 
     @Override
     void Xusage() {
-        Xusage(true);
+        usage("main.Xusage", OptionKind.EXTENDED, "main.Xusage.foot");
     }
 
-    void Xusage(boolean exit) {
-        usage("main.Xusage", "-X", "main.Xusage.foot");
-
-        if (exit)
-            throw new Messager.ExitJavadoc();
-    }
-
-    private void usage(String header, String option, String footer) {
-        messager.notice(header);
-        showToolOptions(option.equals("-X") ? OptionKind.EXTENDED : OptionKind.STANDARD);
+    private void usage(String headerKey, OptionKind kind, String footerKey) {
+        messager.notice(headerKey);
+        showToolOptions(kind);
 
         // let doclet print usage information
         if (docletClass != null) {
             String name = doclet.getName();
             messager.notice("main.doclet.usage.header", name);
-            showDocletOptions(option.equals("-X") ? Option.Kind.EXTENDED : Option.Kind.STANDARD);
+            showDocletOptions(kind == OptionKind.EXTENDED
+                    ? Option.Kind.EXTENDED
+                    : Option.Kind.STANDARD);
         }
-
-        if (footer != null)
-            messager.notice(footer);
+        if (footerKey != null)
+            messager.notice(footerKey);
     }
 
     void showToolOptions(OptionKind kind) {
@@ -325,25 +313,23 @@
      * of class loader creation, needed to detect the doclet/taglet class variants.
      */
     @SuppressWarnings("deprecation")
-    int begin(String... argv) {
+    Result begin(String... argv) {
         // Preprocess @file arguments
         try {
             argv = CommandLine.parse(argv);
-        } catch (FileNotFoundException e) {
-            messager.error("main.cant.read", e.getMessage());
-            throw new Messager.ExitJavadoc();
         } catch (IOException e) {
-            e.printStackTrace(System.err);
-            throw new Messager.ExitJavadoc();
+            error("main.cant.read", e.getMessage());
+            return ERROR;
         }
 
         if (argv.length > 0 && "-Xold".equals(argv[0])) {
-            messager.warning("main.legacy_api");
+            warn("main.legacy_api");
             String[] nargv = Arrays.copyOfRange(argv, 1, argv.length);
-            return com.sun.tools.javadoc.Main.execute(nargv);
+            return com.sun.tools.javadoc.Main.execute(nargv) == 0
+                    ? OK
+                    : ERROR;
         }
-        boolean ok = begin(Arrays.asList(argv), Collections.<JavaFileObject> emptySet());
-        return ok ? 0 : 1;
+        return begin(Arrays.asList(argv), Collections.<JavaFileObject> emptySet());
     }
 
     // Called by 199 API.
@@ -355,11 +341,11 @@
         for (String opt: options)
             opts.add(opt);
 
-        return begin(opts, fileObjects);
+        return begin(opts, fileObjects).isOK();
     }
 
     @SuppressWarnings("deprecation")
-    private boolean begin(List<String> options, Iterable<? extends JavaFileObject> fileObjects) {
+    private Result begin(List<String> options, Iterable<? extends JavaFileObject> fileObjects) {
         fileManager = context.get(JavaFileManager.class);
         if (fileManager == null) {
             JavacFileManager.preRegister(context);
@@ -368,8 +354,28 @@
                 ((BaseFileManager) fileManager).autoClose = true;
             }
         }
+
         // locale, doclet and maybe taglet, needs to be determined first
-        docletClass = preProcess(fileManager, options);
+        try {
+            docletClass = preprocess(fileManager, options);
+        } catch (ToolException te) {
+            if (!te.result.isOK()) {
+                if (te.message != null) {
+                    messager.printError(te.message);
+                }
+                Throwable t = te.getCause();
+                dumpStack(t == null ? te : t);
+            }
+            return te.result;
+        } catch (OptionException oe) {
+            if (oe.message != null) {
+                messager.printError(oe.message);
+            }
+            oe.m.run();
+            Throwable t = oe.getCause();
+            dumpStack(t == null ? oe : t);
+            return oe.result;
+        }
         if (jdk.javadoc.doclet.Doclet.class.isAssignableFrom(docletClass)) {
             // no need to dispatch to old, safe to init now
             initMessager();
@@ -378,43 +384,62 @@
                 Object o = docletClass.getConstructor().newInstance();
                 doclet = (Doclet) o;
             } catch (ReflectiveOperationException exc) {
-                exc.printStackTrace();
-                if (!apiMode) {
-                    error("main.could_not_instantiate_class", docletClass);
-                    throw new Messager.ExitJavadoc();
+                if (apiMode) {
+                    throw new ClientCodeException(exc);
                 }
-                throw new ClientCodeException(exc);
+                error("main.could_not_instantiate_class", docletClass);
+                return ERROR;
             }
         } else {
-            if (this.apiMode) {
+            if (apiMode) {
                 com.sun.tools.javadoc.main.Start ostart
                         = new com.sun.tools.javadoc.main.Start(context);
-                return ostart.begin(docletClass, options, fileObjects);
+                return ostart.begin(docletClass, options, fileObjects)
+                        ? OK
+                        : ERROR;
             }
             warn("main.legacy_api");
             String[] array = options.toArray(new String[options.size()]);
-            return com.sun.tools.javadoc.Main.execute(array) == 0;
+            return com.sun.tools.javadoc.Main.execute(array) == 0
+                    ? OK
+                    : ERROR;
         }
 
-        boolean failed = false;
+        Result result = OK;
         try {
-            failed = !parseAndExecute(options, fileObjects);
-        } catch (Messager.ExitJavadoc exc) {
-            // ignore, we just exit this way
+            result = parseAndExecute(options, fileObjects)
+                    ? OK
+                    : ERROR;
+        } catch (OptionException toe) {
+            if (toe.message != null)
+                messager.printError(toe.message);
+
+            toe.m.run();
+            Throwable t = toe.getCause();
+            dumpStack(t == null ? toe : t);
+            return toe.result;
+        } catch (ToolException exc) {
+            if (exc.message != null) {
+                messager.printError(exc.message);
+            }
+            Throwable t = exc.getCause();
+            if (result == ABNORMAL) {
+                reportInternalError(t == null ? exc : t);
+            } else {
+                dumpStack(t == null ? exc : t);
+            }
+            return exc.result;
         } catch (OutOfMemoryError ee) {
-            messager.error("main.out.of.memory");
-            failed = true;
+            error("main.out.of.memory");
+            result = SYSERR;
+            dumpStack(ee);
         } catch (ClientCodeException e) {
             // simply rethrow these exceptions, to be caught and handled by JavadocTaskImpl
             throw e;
-        } catch (Error ee) {
-            ee.printStackTrace(System.err);
-            messager.error("main.fatal.error");
-            failed = true;
-        } catch (Exception ee) {
-            ee.printStackTrace(System.err);
-            messager.error("main.fatal.exception");
-            failed = true;
+        } catch (Error | Exception ee) {
+            error("main.fatal.error", ee);
+            reportInternalError(ee);
+            result = ABNORMAL;
         } finally {
             if (fileManager != null
                     && fileManager instanceof BaseFileManager
@@ -423,17 +448,34 @@
                     fileManager.close();
                 } catch (IOException ignore) {}
             }
-            boolean haveErrorWarnings = messager.nerrors() > 0 ||
-                    (rejectWarnings && messager.nwarnings() > 0);
-            if (failed && !haveErrorWarnings) {
+            boolean haveErrorWarnings = messager.hasErrors()
+                    || (rejectWarnings && messager.hasWarnings());
+            if (!result.isOK() && !haveErrorWarnings) {
                 // the doclet failed, but nothing reported, flag it!.
-                messager.error("main.unknown.error");
+                error("main.unknown.error");
             }
-            failed |= haveErrorWarnings;
-            messager.exitNotice();
+            if (haveErrorWarnings && result.isOK()) {
+                result = ERROR;
+            }
+            messager.printErrorWarningCounts();
             messager.flush();
         }
-        return !failed;
+        return result;
+    }
+
+    private void reportInternalError(Throwable t) {
+        messager.printErrorUsingKey("doclet.internal.report.bug");
+        dumpStack(true, t);
+    }
+
+    private void dumpStack(Throwable t) {
+        dumpStack(false, t);
+    }
+
+    private void dumpStack(boolean enabled, Throwable t) {
+        if (t != null && (enabled || dumpOnError)) {
+            t.printStackTrace(System.err);
+        }
     }
 
     /**
@@ -441,7 +483,7 @@
      */
     @SuppressWarnings("unchecked")
     private boolean parseAndExecute(List<String> argList,
-            Iterable<? extends JavaFileObject> fileObjects) throws IOException {
+            Iterable<? extends JavaFileObject> fileObjects) throws ToolException, OptionException {
         long tm = System.currentTimeMillis();
 
         List<String> javaNames = new ArrayList<>();
@@ -462,17 +504,21 @@
 
         if (platformString != null) {
             if (compOpts.isSet("-source")) {
-                usageError("main.release.bootclasspath.conflict", "-source");
+                String text = messager.getText("main.release.bootclasspath.conflict", "-source");
+                throw new ToolException(CMDERR, text);
             }
             if (fileManagerOpts.containsKey(BOOT_CLASS_PATH)) {
-                usageError("main.release.bootclasspath.conflict", BOOT_CLASS_PATH.getPrimaryName());
+                String text = messager.getText("main.release.bootclasspath.conflict",
+                        BOOT_CLASS_PATH.getPrimaryName());
+                throw new ToolException(CMDERR, text);
             }
 
             PlatformDescription platformDescription =
                     PlatformUtils.lookupPlatformDescription(platformString);
 
             if (platformDescription == null) {
-                usageError("main.unsupported.release.version", platformString);
+                String text = messager.getText("main.unsupported.release.version", platformString);
+                throw new IllegalArgumentException(text);
             }
 
             compOpts.put(SOURCE, platformDescription.getSourceVersion());
@@ -484,10 +530,15 @@
             if (platformCP != null) {
                 if (fileManager instanceof StandardJavaFileManager) {
                     StandardJavaFileManager sfm = (StandardJavaFileManager) fileManager;
-
-                    sfm.setLocationFromPaths(StandardLocation.PLATFORM_CLASS_PATH, platformCP);
+                    try {
+                        sfm.setLocationFromPaths(StandardLocation.PLATFORM_CLASS_PATH, platformCP);
+                    } catch (IOException ioe) {
+                        throw new ToolException(SYSERR, ioe.getMessage(), ioe);
+                    }
                 } else {
-                    usageError("main.release.not.standard.file.manager", platformString);
+                    String text = messager.getText("main.release.not.standard.file.manager",
+                                                    platformString);
+                    throw new ToolException(ABNORMAL, text);
                 }
             }
         }
@@ -501,7 +552,8 @@
                     s -> Collections.EMPTY_LIST);
             if (subpkgs.isEmpty()) {
                 if (javaNames.isEmpty() && isEmpty(fileObjects)) {
-                    usageError("main.No_modules_packages_or_classes_specified");
+                    String text = messager.getText("main.No_modules_packages_or_classes_specified");
+                    throw new ToolException(CMDERR, text);
                 }
             }
         }
@@ -534,7 +586,8 @@
     }
 
     Set<Doclet.Option> docletOptions = null;
-    int handleDocletOptions(int idx, List<String> args, boolean isToolOption) {
+    int handleDocletOptions(int idx, List<String> args, boolean isToolOption)
+            throws OptionException {
         if (docletOptions == null) {
             docletOptions = doclet.getSupportedOptions();
         }
@@ -548,24 +601,25 @@
             argBase = arg;
             argVal = null;
         }
-
+        String text = null;
         for (Doclet.Option opt : docletOptions) {
             if (opt.matches(argBase)) {
                 if (argVal != null) {
                     switch (opt.getArgumentCount()) {
                         case 0:
-                            usageError("main.unnecessary_arg_provided", argBase);
-                            break;
+                            text = messager.getText("main.unnecessary_arg_provided", argBase);
+                            throw new OptionException(ERROR, this::usage, text);
                         case 1:
                             opt.process(arg, Arrays.asList(argVal).listIterator());
                             break;
                         default:
-                            usageError("main.only_one_argument_with_equals", argBase);
-                            break;
+                            text = messager.getText("main.only_one_argument_with_equals", argBase);
+                            throw new OptionException(ERROR, this::usage, text);
                     }
                 } else {
                     if (args.size() - idx -1 < opt.getArgumentCount()) {
-                        usageError("main.requires_argument", arg);
+                        text = messager.getText("main.requires_argument", arg);
+                        throw new OptionException(ERROR, this::usage, text);
                     }
                     opt.process(arg, args.listIterator(idx + 1));
                     idx += opt.getArgumentCount();
@@ -574,12 +628,15 @@
             }
         }
         // check if arg is accepted by the tool before emitting error
-        if (!isToolOption)
-            usageError("main.invalid_flag", arg);
+        if (!isToolOption) {
+            text = messager.getText("main.invalid_flag", arg);
+            throw new OptionException(ERROR, this::usage, text);
+        }
         return idx;
     }
 
-    private Class<?> preProcess(JavaFileManager jfm, List<String> argv) {
+    private Class<?> preprocess(JavaFileManager jfm,
+            List<String> argv) throws ToolException, OptionException {
         // doclet specifying arguments
         String userDocletPath = null;
         String userDocletName = null;
@@ -592,19 +649,31 @@
         // Step 1: loop through the args, set locale early on, if found.
         for (int i = 0 ; i < argv.size() ; i++) {
             String arg = argv.get(i);
-            if (arg.equals(ToolOption.LOCALE.primaryName)) {
+            if (arg.equals(ToolOption.DUMPONERROR.primaryName)) {
+                dumpOnError = true;
+            } else if (arg.equals(ToolOption.LOCALE.primaryName)) {
                 checkOneArg(argv, i++);
                 String lname = argv.get(i);
                 locale = getLocale(lname);
             } else if (arg.equals(ToolOption.DOCLET.primaryName)) {
                 checkOneArg(argv, i++);
                 if (userDocletName != null) {
-                    usageError("main.more_than_one_doclet_specified_0_and_1",
+                    if (apiMode) {
+                        throw new IllegalArgumentException("More than one doclet specified (" +
+                                userDocletName + " and " + argv.get(i) + ").");
+                    }
+                    String text = messager.getText("main.more_than_one_doclet_specified_0_and_1",
                             userDocletName, argv.get(i));
+                    throw new ToolException(CMDERR, text);
                 }
                 if (docletName != null) {
-                    usageError("main.more_than_one_doclet_specified_0_and_1",
+                    if (apiMode) {
+                        throw new IllegalArgumentException("More than one doclet specified (" +
+                                docletName + " and " + argv.get(i) + ").");
+                    }
+                    String text = messager.getText("main.more_than_one_doclet_specified_0_and_1",
                             docletName, argv.get(i));
+                    throw new ToolException(CMDERR, text);
                 }
                 userDocletName = argv.get(i);
             } else if (arg.equals(ToolOption.DOCLETPATH.primaryName)) {
@@ -643,23 +712,37 @@
                     try {
                         ((StandardJavaFileManager)fileManager).setLocation(DOCLET_PATH, paths);
                     } catch (IOException ioe) {
-                        error("main.doclet_could_not_set_location", paths);
-                        throw new Messager.ExitJavadoc();
+                        if (apiMode) {
+                            throw new IllegalArgumentException("Could not set location for " +
+                                    userDocletPath, ioe);
+                        }
+                        String text = messager.getText("main.doclet_could_not_set_location",
+                                userDocletPath);
+                        throw new ToolException(CMDERR, text, ioe);
                     }
                 }
                 cl = fileManager.getClassLoader(DOCLET_PATH);
                 if (cl == null) {
                     // despite doclet specified on cmdline no classloader found!
-                    error("main.doclet_no_classloader_found", userDocletName);
-                    throw new Messager.ExitJavadoc();
+                    if (apiMode) {
+                        throw new IllegalArgumentException("Could not obtain classloader to load "
+                                + userDocletPath);
+                    }
+                    String text = messager.getText("main.doclet_no_classloader_found",
+                            userDocletName);
+                    throw new ToolException(CMDERR, text);
                 }
             }
             try {
                 Class<?> klass = cl.loadClass(userDocletName);
                 return klass;
             } catch (ClassNotFoundException cnfe) {
-                error("main.doclet_class_not_found", userDocletName);
-                throw new Messager.ExitJavadoc();
+                if (apiMode) {
+                    throw new IllegalArgumentException("Cannot find doclet class " + userDocletName,
+                            cnfe);
+                }
+                String text = messager.getText("main.doclet_class_not_found", userDocletName);
+                throw new ToolException(CMDERR, text, cnfe);
             }
         }
 
@@ -668,8 +751,11 @@
             try {
                 return Class.forName(docletName, true, getClass().getClassLoader());
             } catch (ClassNotFoundException cnfe) {
-                error("main.doclet_class_not_found", userDocletName);
-                throw new Messager.ExitJavadoc();
+                if (apiMode) {
+                    throw new IllegalArgumentException("Cannot find doclet class " + userDocletName);
+                }
+                String text = messager.getText("main.doclet_class_not_found", userDocletName);
+                throw new ToolException(CMDERR, text, cnfe);
             }
         }
 
@@ -689,20 +775,20 @@
      * nature to take its own course.
      */
     @SuppressWarnings("deprecation")
-    private boolean hasOldTaglet(List<String> tagletNames, List<File> tagletPaths) {
+    private boolean hasOldTaglet(List<String> tagletNames, List<File> tagletPaths) throws ToolException {
         if (!fileManager.hasLocation(TAGLET_PATH)) {
             try {
                 ((StandardJavaFileManager) fileManager).setLocation(TAGLET_PATH, tagletPaths);
             } catch (IOException ioe) {
-                error("main.doclet_could_not_set_location", tagletPaths);
-                throw new Messager.ExitJavadoc();
+                String text = messager.getText("main.doclet_could_not_set_location", tagletPaths);
+                throw new ToolException(CMDERR, text, ioe);
             }
         }
         ClassLoader cl = fileManager.getClassLoader(TAGLET_PATH);
         if (cl == null) {
             // no classloader found!
-            error("main.doclet_no_classloader_found", tagletNames.get(0));
-            throw new Messager.ExitJavadoc();
+            String text = messager.getText("main.doclet_no_classloader_found", tagletNames.get(0));
+            throw new ToolException(CMDERR, text);
         }
         for (String tagletName : tagletNames) {
             try {
@@ -711,14 +797,15 @@
                     return true;
                 }
             } catch (ClassNotFoundException cnfe) {
-                error("main.doclet_class_not_found", tagletName);
-                throw new Messager.ExitJavadoc();
+                String text = messager.getText("main.doclet_class_not_found", tagletName);
+                throw new ToolException(CMDERR, text, cnfe);
             }
         }
         return false;
     }
 
-    private void parseArgs(List<String> args, List<String> javaNames) {
+    private void parseArgs(List<String> args, List<String> javaNames) throws ToolException,
+            OptionException {
         for (int i = 0 ; i < args.size() ; i++) {
             String arg = args.get(i);
             ToolOption o = ToolOption.get(arg);
@@ -726,7 +813,6 @@
                 // handle a doclet argument that may be needed however
                 // don't increment the index, and allow the tool to consume args
                 handleDocletOptions(i, args, true);
-
                 if (o.hasArg) {
                     if (arg.startsWith("--") && arg.contains("=")) {
                         o.process(this, arg.substring(arg.indexOf('=') + 1));
@@ -762,24 +848,19 @@
      * Check the one arg option.
      * Error and exit if one argument is not provided.
      */
-    private void checkOneArg(List<String> args, int index) {
+    private void checkOneArg(List<String> args, int index) throws OptionException {
         if ((index + 1) >= args.size() || args.get(index + 1).startsWith("-d")) {
-            usageError("main.requires_argument", args.get(index));
+            String text = messager.getText("main.requires_argument", args.get(index));
+            throw new OptionException(CMDERR, this::usage, text);
         }
     }
 
-    @Override
-    void usageError(String key, Object... args) {
-        error(key, args);
-        usage(true);
-    }
-
     void error(String key, Object... args) {
-        messager.error(key, args);
+        messager.printErrorUsingKey(key, args);
     }
 
     void warn(String key, Object... args)  {
-        messager.warning(key, args);
+        messager.printWarningUsingKey(key, args);
     }
 
     /**
@@ -787,7 +868,7 @@
      * else return null and if locale option is not used
      * then return default locale.
      */
-    private Locale getLocale(String localeName) {
+    private Locale getLocale(String localeName) throws ToolException {
         Locale userlocale = null;
         if (localeName == null || localeName.isEmpty()) {
             return Locale.getDefault();
@@ -803,8 +884,8 @@
             if (seconduscore > 0) {
                 if (seconduscore != firstuscore + 3
                         || localeName.length() <= seconduscore + 1) {
-                    usageError("main.malformed_locale_name", localeName);
-                    return null;
+                    String text = messager.getText("main.malformed_locale_name", localeName);
+                    throw new ToolException(CMDERR, text);
                 }
                 country = localeName.substring(firstuscore + 1,
                         seconduscore);
@@ -812,19 +893,19 @@
             } else if (localeName.length() == firstuscore + 3) {
                 country = localeName.substring(firstuscore + 1);
             } else {
-                usageError("main.malformed_locale_name", localeName);
-                return null;
+                String text = messager.getText("main.malformed_locale_name", localeName);
+                throw new ToolException(CMDERR, text);
             }
         } else if (firstuscore == -1 && localeName.length() == 2) {
             language = localeName;
         } else {
-            usageError("main.malformed_locale_name", localeName);
-            return null;
+            String text = messager.getText("main.malformed_locale_name", localeName);
+            throw new ToolException(CMDERR, text);
         }
         userlocale = searchLocale(language, country, variant);
         if (userlocale == null) {
-            usageError("main.illegal_locale_name", localeName);
-            return null;
+            String text = messager.getText("main.illegal_locale_name", localeName);
+            throw new ToolException(CMDERR, text);
         } else {
             return userlocale;
         }
@@ -860,4 +941,9 @@
             }
         };
     }
+
+    @Override
+    String getLocalizedMessage(String msg, Object... args) {
+        return messager.getText(msg, args);
+    }
 }
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ToolEnvironment.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ToolEnvironment.java	Wed Jul 05 22:19:40 2017 +0200
@@ -87,7 +87,7 @@
         return instance;
     }
 
-    private final Messager messager;
+    final Messager messager;
 
     /** Predefined symbols known to the compiler. */
     public final Symtab syms;
@@ -204,182 +204,8 @@
         return path != null;
     }
 
-    //---------------- print forwarders ----------------//
-
-    // ERRORS
     /**
-     * Print error message, increment error count.
-     *
-     * @param msg message to print.
-     */
-    public void printError(String msg) {
-        messager.printError(msg);
-    }
-
-//    /**
-//     * Print error message, increment error count.
-//     *
-//     * @param key selects message from resource
-//     */
-//    public void error(Element element, String key) {
-//        if (element == null)
-//            messager.error(key);
-//        else
-//            messager.error(element, key);
-//    }
-//
-//    public void error(String prefix, String key) {
-//        printError(prefix + ":" + messager.getText(key));
-//    }
-//
-//    /**
-//     * Print error message, increment error count.
-//     *
-//     * @param path the path to the source
-//     * @param key selects message from resource
-//     */
-//    public void error(DocTreePath path, String key) {
-//        messager.error(path, key);
-//    }
-//
-//    /**
-//     * Print error message, increment error count.
-//     *
-//     * @param path the path to the source
-//     * @param msg message to print.
-//     */
-//    public void printError(DocTreePath path, String msg) {
-//        messager.printError(path, msg);
-//    }
-//
-//    /**
-//     * Print error message, increment error count.
-//     * @param e the target element
-//     * @param msg message to print.
-//     */
-//    public void printError(Element e, String msg) {
-//        messager.printError(e, msg);
-//    }
-
-    /**
-     * Print error message, increment error count.
-     * @param key selects message from resource
-     * @param args replacement arguments
-     */
-    public void error(String key, String... args) {
-        error(null, key, args);
-    }
-
-    /**
-     * Print error message, increment error count.
-     *
-     * @param element the source element
-     * @param key selects message from resource
-     * @param args replacement arguments
-     */
-    public void error(Element element, String key, String... args) {
-        if (element == null)
-            messager.error(key, (Object[]) args);
-        else
-            messager.error(element, key, (Object[]) args);
-    }
-
-    // WARNINGS
-
-//    /**
-//     * Print warning message, increment warning count.
-//     *
-//     * @param msg message to print.
-//     */
-//    public void printWarning(String msg) {
-//        messager.printWarning(msg);
-//    }
-//
-//    public void warning(String key) {
-//        warning((Element)null, key);
-//    }
-
-    public void warning(String key, String... args) {
-        warning((Element)null, key, args);
-    }
-
-//    /**
-//     * Print warning message, increment warning count.
-//     *
-//     * @param element the source element
-//     * @param key selects message from resource
-//     */
-//    public void warning(Element element, String key) {
-//        if (element == null)
-//            messager.warning(key);
-//        else
-//            messager.warning(element, key);
-//    }
-//
-//    /**
-//     * Print warning message, increment warning count.
-//     *
-//     * @param path the path to the source
-//     * @param msg message to print.
-//     */
-//    public void printWarning(DocTreePath path, String msg) {
-//        messager.printWarning(path, msg);
-//    }
-//
-//    /**
-//     * Print warning message, increment warning count.
-//     *
-//     * @param e  the source element
-//     * @param msg message to print.
-//     */
-//    public void printWarning(Element e, String msg) {
-//        messager.printWarning(e, msg);
-//    }
-
-    /**
-     * Print warning message, increment warning count.
-     *
-     * @param e    the source element
-     * @param key  selects message from resource
-     * @param args the replace arguments
-     */
-    public void warning(Element e, String key, String... args) {
-        if (e == null)
-            messager.warning(key, (Object[]) args);
-        else
-            messager.warning(e, key, (Object[]) args);
-    }
-
-//    Note: no longer required
-//    /**
-//     * Print a message.
-//     *
-//     * @param msg message to print.
-//     */
-//    public void printNotice(String msg) {
-//        if (quiet) {
-//            return;
-//        }
-//        messager.printNotice(msg);
-//    }
-
-//  Note: no longer required
-//    /**
-//     * Print a message.
-//     *
-//     * @param e the source element
-//     * @param msg message to print.
-//     */
-//    public void printNotice(Element e, String msg) {
-//        if (quiet) {
-//            return;
-//        }
-//        messager.printNotice(e, msg);
-//    }
-
-    //  NOTICES
-    /**
-     * Print a message.
+     * Print a notice, iff <em>quiet</em> is not specified.
      *
      * @param key selects message from resource
      */
@@ -390,22 +216,8 @@
         messager.notice(key);
     }
 
-//    Note: not used anymore
-//    /**
-//     * Print a message.
-//     *
-//     * @param path the path to the source
-//     * @param msg message to print.
-//     */
-//    public void printNotice(DocTreePath path, String msg) {
-//        if (quiet) {
-//            return;
-//        }
-//        messager.printNotice(path, msg);
-//    }
-
     /**
-     * Print a message.
+     * Print a notice, iff <em>quiet</em> is not specified.
      *
      * @param key selects message from resource
      * @param a1 first argument
@@ -417,48 +229,6 @@
         messager.notice(key, a1);
     }
 
-//    Note: not used anymore
-//    /**
-//     * Print a message.
-//     *
-//     * @param key selects message from resource
-//     * @param a1 first argument
-//     * @param a2 second argument
-//     */
-//    public void notice(String key, String a1, String a2) {
-//        if (quiet) {
-//            return;
-//        }
-//        messager.notice(key, a1, a2);
-//    }
-//
-
-//    Note: not used anymore
-//    /**
-//     * Print a message.
-//     *
-//     * @param key selects message from resource
-//     * @param a1 first argument
-//     * @param a2 second argument
-//     * @param a3 third argument
-//     */
-//    public void notice(String key, String a1, String a2, String a3) {
-//        if (quiet) {
-//            return;
-//        }
-//        messager.notice(key, a1, a2, a3);
-//    }
-
-    /**
-     * Exit, reporting errors and warnings.
-     */
-    public void exit() {
-        // Messager should be replaced by a more general
-        // compilation environment.  This can probably
-        // subsume DocEnv as well.
-        throw new Messager.ExitJavadoc();
-    }
-
     TreePath getTreePath(JCCompilationUnit tree) {
         TreePath p = treePaths.get(tree);
         if (p == null)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ToolException.java	Wed Jul 05 22:19:40 2017 +0200
@@ -0,0 +1,79 @@
+/*
+ * 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.  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.javadoc.internal.tool;
+
+import jdk.javadoc.internal.tool.Main.Result;
+
+/**
+ * Provides a mechanism for the javadoc tool to terminate execution.
+ * This class is constructed with a result and an error message,
+ * that can be printed out before termination, a cause can also
+ * be wrapped to supply extended information about the exception.
+ *
+ * <p><b>This is NOT part of any supported API.
+ * If you write code that depends on this, you do so at your own risk.
+ * This code and its internal interfaces are subject to change or
+ * deletion without notice.</b>
+ */
+
+class ToolException extends Exception {
+
+    private static final long serialVersionUID = 0;
+
+    final String message;
+
+    final Result result;
+
+    /**
+     * Constructs an object containing a result and a message to be
+     * printed out by the catcher.
+     * @param result the exit code
+     * @param message the detailed message
+     */
+    ToolException(Result result, String message) {
+        this.message = message;
+        this.result = result;
+        if (result == null || result.isOK() || message == null) {
+            throw new AssertionError("result == null || result.isOK() || message == null");
+        }
+    }
+
+    /**
+     * Constructs an object containing a result, a messages and an underlying cause.
+     * @param result the exit code
+     * @param message the detailed message
+     * @param cause the underlying cause
+     */
+    ToolException(Result result, String message, Throwable cause) {
+        super(cause);
+        this.message = message;
+        this.result = result;
+        if (result == null || message == null || cause == null || result.isOK()) {
+            throw new AssertionError("result == null || message == null"
+                    + " || cause == null || result.isOK()");
+        }
+    }
+}
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ToolOption.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ToolOption.java	Wed Jul 05 22:19:40 2017 +0200
@@ -40,6 +40,7 @@
 import com.sun.tools.javac.util.Options;
 
 import static com.sun.tools.javac.main.Option.OptionKind.*;
+import static jdk.javadoc.internal.tool.Main.Result.*;
 
 /**
  * javadoc tool options.
@@ -226,63 +227,63 @@
 
     PACKAGE("-package", STANDARD) {
         @Override
-        public void process(Helper helper) {
+        public void process(Helper helper) throws OptionException {
             helper.setSimpleFilter("package");
         }
     },
 
     PRIVATE("-private", STANDARD) {
         @Override
-        public void process(Helper helper) {
+        public void process(Helper helper) throws OptionException {
             helper.setSimpleFilter("private");
         }
     },
 
     PROTECTED("-protected", STANDARD) {
         @Override
-        public void process(Helper helper) {
+        public void process(Helper helper) throws OptionException {
             helper.setSimpleFilter("protected");
         }
     },
 
     PUBLIC("-public", STANDARD) {
         @Override
-        public void process(Helper helper) {
+        public void process(Helper helper) throws OptionException {
             helper.setSimpleFilter("public");
         }
     },
 
     SHOW_MEMBERS("--show-members", STANDARD, true) {
         @Override
-        public void process(Helper helper, String arg) {
+        public void process(Helper helper, String arg) throws OptionException {
             helper.setFilter(this, arg);
         }
     },
 
     SHOW_TYPES("--show-types", STANDARD, true) {
         @Override
-        public void process(Helper helper, String arg) {
+        public void process(Helper helper, String arg) throws OptionException {
             helper.setFilter(this, arg);
         }
     },
 
     SHOW_PACKAGES("--show-packages", STANDARD, true) {
         @Override
-        public void process(Helper helper, String arg) {
+        public void process(Helper helper, String arg) throws OptionException {
             helper.setShowPackageAccess(SHOW_PACKAGES, arg);
         }
     },
 
     SHOW_MODULE_CONTENTS("--show-module-contents", STANDARD, true) {
         @Override
-        public void process(Helper helper, String arg) {
+        public void process(Helper helper, String arg) throws OptionException {
             helper.setShowModuleContents(SHOW_MODULE_CONTENTS, arg);
         }
     },
 
     EXPAND_REQUIRES("--expand-requires", STANDARD, true) {
         @Override
-        public void process(Helper helper, String arg) {
+        public void process(Helper helper, String arg) throws OptionException {
             helper.setExpandRequires(EXPAND_REQUIRES, arg);
         }
     },
@@ -342,19 +343,26 @@
         }
     },
 
+    DUMPONERROR("--dump-on-error", HIDDEN) {
+        @Override
+        public void process(Helper helper) {
+            helper.dumpOnError = true;
+        }
+    },
+
     // ----- help options -----
 
     HELP("--help -help", STANDARD) {
         @Override
-        public void process(Helper helper) {
-            helper.usage();
+        public void process(Helper helper) throws OptionException {
+            throw new OptionException(OK, helper::usage);
         }
     },
 
     X("-X", STANDARD) {
         @Override
-        public void process(Helper helper) {
-            helper.Xusage();
+        public void process(Helper helper) throws OptionException {
+           throw new OptionException(OK, helper::Xusage);
         }
     },
 
@@ -395,9 +403,9 @@
         this.hasSuffix = lastChar == ':' || lastChar == '=';
     }
 
-    void process(Helper helper, String arg) { }
+    void process(Helper helper, String arg) throws OptionException { }
 
-    void process(Helper helper) { }
+    void process(Helper helper) throws OptionException { }
 
     List<String> getNames() {
         return names;
@@ -451,6 +459,9 @@
         /** Javadoc tool options */
         final Map<ToolOption, Object> jdtoolOpts = new EnumMap<>(ToolOption.class);
 
+        /** dump stack traces for debugging etc.*/
+        boolean dumpOnError = false;
+
         /** Set by -breakiterator. */
         boolean breakiterator = false;
 
@@ -470,7 +481,8 @@
         abstract void usage();
         abstract void Xusage();
 
-        abstract void usageError(String msg, Object... args);
+        abstract String getLocalizedMessage(String msg, Object... args);
+
         abstract OptionHelper getOptionHelper();
 
         @SuppressWarnings("unchecked")
@@ -480,7 +492,7 @@
             jdtoolOpts.put(opt, list);
         }
 
-        void setExpandRequires(ToolOption opt, String arg) {
+        void setExpandRequires(ToolOption opt, String arg) throws OptionException {
             switch (arg) {
                 case "public":
                     jdtoolOpts.put(opt, AccessKind.PUBLIC);
@@ -489,11 +501,12 @@
                     jdtoolOpts.put(opt, AccessKind.PRIVATE);
                     break;
                 default:
-                    usageError("main.illegal_option_value", arg);
+                    String text = getLocalizedMessage("main.illegal_option_value", arg);
+                    throw new IllegalOptionValue(this::usage, text);
             }
         }
 
-        void setShowModuleContents(ToolOption opt, String arg) {
+        void setShowModuleContents(ToolOption opt, String arg) throws OptionException {
             switch (arg) {
                 case "api":
                     jdtoolOpts.put(opt, AccessKind.PUBLIC);
@@ -502,11 +515,12 @@
                     jdtoolOpts.put(opt, AccessKind.PRIVATE);
                     break;
                 default:
-                    usageError("main.illegal_option_value", arg);
+                    String text = getLocalizedMessage("main.illegal_option_value", arg);
+                    throw new IllegalOptionValue(this::usage, text);
             }
         }
 
-        void setShowPackageAccess(ToolOption opt, String arg) {
+        void setShowPackageAccess(ToolOption opt, String arg) throws OptionException {
             switch (arg) {
                 case "exported":
                     jdtoolOpts.put(opt, AccessKind.PUBLIC);
@@ -515,16 +529,17 @@
                     jdtoolOpts.put(opt, AccessKind.PRIVATE);
                     break;
                 default:
-                    usageError("main.illegal_option_value", arg);
+                    String text = getLocalizedMessage("main.illegal_option_value", arg);
+                    throw new IllegalOptionValue(this::usage, text);
             }
         }
 
 
-        void setFilter(ToolOption opt, String arg) {
+        void setFilter(ToolOption opt, String arg) throws OptionException {
             jdtoolOpts.put(opt, getAccessValue(arg));
         }
 
-        void setSimpleFilter(String arg) {
+        void setSimpleFilter(String arg) throws OptionException {
             handleSimpleOption(arg);
         }
 
@@ -532,7 +547,7 @@
             fileManagerOpts.put(opt, arg);
         }
 
-        void handleSimpleOption(String arg) {
+        void handleSimpleOption(String arg) throws OptionException {
             populateSimpleAccessMap(getAccessValue(arg));
         }
 
@@ -541,7 +556,7 @@
          * -private, so on, in addition to the new ones such as
          * --show-types:public and so on.
          */
-        private AccessKind getAccessValue(String arg) {
+        private AccessKind getAccessValue(String arg) throws OptionException {
             int colon = arg.indexOf(':');
             String value = (colon > 0)
                     ? arg.substring(colon + 1)
@@ -556,8 +571,8 @@
                 case "private":
                     return AccessKind.PRIVATE;
                 default:
-                    usageError("main.illegal_option_value", value);
-                    return null;
+                    String text = getLocalizedMessage("main.illegal_option_value", value);
+                    throw new IllegalOptionValue(this::usage, text);
             }
         }
 
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/resources/javadoc.properties	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/resources/javadoc.properties	Wed Jul 05 22:19:40 2017 +0200
@@ -265,13 +265,13 @@
 main.Building_tree=Constructing Javadoc information...
 main.no_source_files_for_package=No source files for package {0}
 main.package_not_found=Package {0} not found
-main.fatal.error=fatal error
-main.fatal.exception=fatal exception
+main.fatal.error=fatal error encountered: {0}
 main.out.of.memory=java.lang.OutOfMemoryError: Please increase memory.\n\
 For example, on the JDK Classic or HotSpot VMs, add the option -J-Xmx\n\
 such as -J-Xmx32m.
 main.done_in=[done in {0} ms]
 main.more_than_one_doclet_specified_0_and_1=More than one doclet specified ({0} and {1}).
+main.doclet_could_not_get_location=Could not get location for {0}
 main.doclet_could_not_set_location=Could not set location for {0}
 main.doclet_no_classloader_found=Could not obtain classloader to load {0}
 main.could_not_instantiate_class=Could not instantiate class {0}
@@ -286,7 +286,15 @@
 main.release.bootclasspath.conflict=option {0} cannot be used together with -release
 main.unsupported.release.version=release version {0} not supported
 main.release.not.standard.file.manager=-release option specified, but the provided JavaFileManager is not a StandardJavaFileManager.
+main.file.manager.list=FileManager error listing files: "{0}"
+main.assertion.error=assertion failed: "{0}}"
 main.unknown.error=an unknown error has occurred
+main.internal.error=an internal error has occurred
+main.unexpected.exception=an unexpected exception was caught: {0}
+doclet.internal.report.bug=\
+Please file a bug against the javadoc tool via the Java bug reporting page\n\
+(http://bugreport.java.com) after checking the Bug Database (http://bugs.java.com)\n\
+for duplicates. Include error messages and the following diagnostic in your report. Thank you.
 main.legacy_api=The old Doclet and Taglet APIs in the packages\n\
     com.sun.javadoc, com.sun.tools.doclets and their implementations\n\
     are planned to be removed in a future JDK release. These\n\
--- a/langtools/src/jdk.javadoc/share/classes/module-info.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/module-info.java	Wed Jul 05 22:19:40 2017 +0200
@@ -41,6 +41,9 @@
     exports jdk.javadoc.doclet.taglet;
     exports jdk.javadoc.doclets;
 
+    provides java.util.spi.ToolProvider
+        with jdk.javadoc.internal.tool.JavadocToolProvider;
+
     provides javax.tools.DocumentationTool
         with jdk.javadoc.internal.api.JavadocTool;
 }
--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/javap/Main.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/javap/Main.java	Wed Jul 05 22:19:40 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -26,6 +26,7 @@
 package com.sun.tools.javap;
 
 import java.io.PrintWriter;
+import java.util.spi.ToolProvider;
 
 /**
  *  Main entry point.
@@ -58,4 +59,14 @@
         t.setLog(out);
         return t.run(args);
     }
+
+    public static class JavapToolProvider implements ToolProvider {
+        public String name() {
+            return "javap";
+        }
+
+        public int run(PrintWriter out, PrintWriter err, String... args) {
+            return Main.run(args, out);
+        }
+    }
 }
--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Main.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Main.java	Wed Jul 05 22:19:40 2017 +0200
@@ -89,8 +89,6 @@
  *  - multi-version jar
  */
 public class Main implements DiagnosticListener<JavaFileObject> {
-    public static Main instance;
-
     final PrintStream out;
     final PrintStream err;
     final List<File> bootClassPath = new ArrayList<>();
@@ -415,13 +413,6 @@
     }
 
     /**
-     * Prints a usage message to the err stream.
-     */
-    void usage() {
-
-    }
-
-    /**
      * An enum denoting the mode in which the tool is running.
      * Different modes correspond to the different process* methods.
      * The exception is UNKNOWN, which indicates that a mode wasn't
@@ -504,7 +495,6 @@
                     args.remove();
                     switch (a) {
                         case "--class-path":
-                        case "-cp":
                             classPath.clear();
                             Arrays.stream(args.remove().split(File.pathSeparator))
                                   .map(File::new)
@@ -699,12 +689,7 @@
      * @return true on success, false otherwise
      */
     public static boolean call(PrintStream out, PrintStream err, String... args) {
-        try {
-            instance = new Main(out, err);
-            return instance.run(args);
-        } finally {
-            instance = null;
-        }
+        return new Main(out, err).run(args);
     }
 
     /**
--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/readme.md	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/readme.md	Wed Jul 05 22:19:40 2017 +0200
@@ -39,7 +39,6 @@
 
 **OPTIONS**
 
-        -cp PATH
         --class-path PATH
 
             Sets the classpath to PATH.
@@ -103,7 +102,7 @@
 
         java.lang.Thread$State
 
-The `--class-path` and `-cp` options specify the classpath used for
+The `--class-path` option specifies the classpath used for
 class searching. The classpath is used for classes named on the
 command line, as well as for dependencies of the classes in jar file
 or directory hierarchy to be scanned.
--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/resources/jdeprscan.properties	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/resources/jdeprscan.properties	Wed Jul 05 22:19:40 2017 +0200
@@ -2,7 +2,7 @@
 Usage: jdeprscan [options] '{dir|jar|class}' ...\n\
 \n\
 options:\n\
-\  -cp  --class-path PATH\n\
+\       --class-path PATH\n\
 \       --for-removal\n\
 \       --full-version\n\
 \  -h   --help\n\
@@ -20,7 +20,7 @@
 \n\
 \    java.lang.Thread$State\n\
 \n\
-The --class-path (-cp) option provides a search path for resolution\n\
+The --class-path option provides a search path for resolution\n\
 of dependent classes.\n\
 \n\
 The --for-removal option limits scanning or listing to APIs that are\n\
--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ClassFileReader.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ClassFileReader.java	Wed Jul 05 22:19:40 2017 +0200
@@ -63,7 +63,7 @@
      * Returns a ClassFileReader instance of a given path.
      */
     public static ClassFileReader newInstance(Path path) throws IOException {
-        return newInstance(path, JarFile.baseVersion());
+        return newInstance(path, null);
     }
 
     /**
@@ -438,7 +438,10 @@
                     cf = reader.readClassFile(jf, nextEntry);
                     return true;
                 } catch (ClassFileError | IOException ex) {
-                    skippedEntries.add(nextEntry.getName());
+                    skippedEntries.add(String.format("%s: %s (%s)",
+                                                     ex.getMessage(),
+                                                     nextEntry.getName(),
+                                                     jf.getName()));
                 }
                 nextEntry = nextEntry();
             }
--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java	Wed Jul 05 22:19:40 2017 +0200
@@ -483,6 +483,7 @@
             }
             if (options.checkModuleDeps != null && !inputArgs.isEmpty()) {
                 reportError("err.invalid.module.option", inputArgs, "--check");
+                return EXIT_CMDERR;
             }
 
             boolean ok = run();
@@ -604,11 +605,12 @@
         boolean ok = analyzer.run(options.compileTimeView, options.depth);
 
         // print skipped entries, if any
-        analyzer.archives()
-            .forEach(archive -> archive.reader()
-                .skippedEntries().stream()
-                .forEach(name -> warning("warn.skipped.entry",
-                                         name, archive.getPathName())));
+        if (!options.nowarning) {
+            analyzer.archives()
+                .forEach(archive -> archive.reader()
+                    .skippedEntries().stream()
+                    .forEach(name -> warning("warn.skipped.entry", name)));
+        }
 
         if (options.findJDKInternals && !options.nowarning) {
             Map<String, String> jdkInternals = new TreeMap<>();
@@ -676,17 +678,29 @@
     }
 
     private boolean genModuleInfo(JdepsConfiguration config) throws IOException {
+        // check if any JAR file contains unnamed package
+        for (String arg : inputArgs) {
+            Optional<String> classInUnnamedPackage =
+                ClassFileReader.newInstance(Paths.get(arg))
+                    .entries().stream()
+                    .filter(n -> n.endsWith(".class"))
+                    .filter(cn -> toPackageName(cn).isEmpty())
+                    .findFirst();
+
+            if (classInUnnamedPackage.isPresent()) {
+                if (classInUnnamedPackage.get().equals("module-info.class")) {
+                    reportError("err.genmoduleinfo.not.jarfile", arg);
+                } else {
+                    reportError("err.genmoduleinfo.unnamed.package", arg);
+                }
+                return false;
+            }
+        }
+
         ModuleInfoBuilder builder
             = new ModuleInfoBuilder(config, inputArgs, options.genModuleInfo);
         boolean ok = builder.run();
 
-        builder.modules().forEach(module -> {
-            if (module.packages().contains("")) {
-                reportError("ERROR: %s contains unnamed package.  " +
-                    "module-info.java not generated%n", module.getPathName());
-            }
-        });
-
         if (!ok && !options.nowarning) {
             log.println("ERROR: missing dependencies");
             builder.visitMissingDeps(
@@ -703,6 +717,11 @@
         return ok;
     }
 
+    private String toPackageName(String name) {
+        int i = name.lastIndexOf('/');
+        return i > 0 ? name.replace('/', '.').substring(0, i) : "";
+    }
+
     /**
      * Returns a filter used during dependency analysis
      */
--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Main.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Main.java	Wed Jul 05 22:19:40 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, 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
@@ -26,6 +26,7 @@
 package com.sun.tools.jdeps;
 
 import java.io.*;
+import java.util.spi.ToolProvider;
 
 /**
  *
@@ -62,4 +63,14 @@
         t.setLog(out);
         return t.run(args);
     }
+
+    public static class JDepsToolProvider implements ToolProvider {
+        public String name() {
+            return "jdeps";
+        }
+
+        public int run(PrintWriter out, PrintWriter err, String... args) {
+            return Main.run(args, out);
+        }
+    }
 }
--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties	Wed Jul 05 22:19:40 2017 +0200
@@ -166,7 +166,8 @@
 err.missing.arg=no value given for {0}
 err.invalid.arg.for.option=invalid argument for option: {0}
 err.option.after.class=option must be specified before classes: {0}
-err.genmoduleinfo.not.jarfile={0} not valid for --generate-module-info option (must be non-modular JAR file)
+err.genmoduleinfo.not.jarfile={0} is a modular JAR file that cannot be specified with the --generate-module-info option
+err.genmoduleinfo.unnamed.package={0} contains an unnamed package that is not allowed in a module
 err.profiles.msg=No profile information
 err.exception.message={0}
 err.invalid.path=invalid path: {0}
@@ -180,6 +181,7 @@
 err.multirelease.version.associated=class {0} already associated with version {1}, trying to add version {2}
 err.multirelease.jar.malformed=malformed multi-release jar, {0}, bad entry: {1}
 warn.invalid.arg=Path does not exist: {0}
+warn.skipped.entry={0}
 warn.split.package=package {0} defined in {1} {2}
 warn.replace.useJDKInternals=\
 JDK internal APIs are unsupported and private to JDK implementation that are\n\
--- a/langtools/src/jdk.jdeps/share/classes/module-info.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.jdeps/share/classes/module-info.java	Wed Jul 05 22:19:40 2017 +0200
@@ -32,4 +32,10 @@
     requires jdk.compiler;
     exports com.sun.tools.classfile to
         jdk.jlink;
+
+    provides java.util.spi.ToolProvider
+        with com.sun.tools.javap.Main.JavapToolProvider;
+
+    provides java.util.spi.ToolProvider
+        with com.sun.tools.jdeps.Main.JDepsToolProvider;
 }
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java	Wed Jul 05 22:19:40 2017 +0200
@@ -166,6 +166,7 @@
     private static final int XTERM         = 0b100000000;               // Can terminate (last before EOF)
     private static final int XSTART        = 0b1000000000;              // Boundary, must be XTERM before
     private static final int XERRO         = 0b10000000000;             // Is an error
+    private static final int XBRACESNEEDED = 0b100000000000;            // Expect {ANY} LBRACE
 
     /**
      * An extension of the compiler's TokenKind which adds our combined/processed
@@ -190,7 +191,7 @@
         ERROR(TokenKind.ERROR, XERRO),  //
         IDENTIFIER(TokenKind.IDENTIFIER, XEXPR1|XDECL1|XTERM),  //
         UNDERSCORE(TokenKind.UNDERSCORE, XERRO),  //  _
-        CLASS(TokenKind.CLASS, XEXPR|XDECL1),  //  class decl (MAPPED: DOTCLASS)
+        CLASS(TokenKind.CLASS, XEXPR|XDECL1|XBRACESNEEDED),  //  class decl (MAPPED: DOTCLASS)
         MONKEYS_AT(TokenKind.MONKEYS_AT, XEXPR|XDECL1),  //  @
         IMPORT(TokenKind.IMPORT, XDECL1|XSTART),  //  import -- consider declaration
         SEMI(TokenKind.SEMI, XSTMT1|XTERM|XSTART),  //  ;
@@ -202,10 +203,10 @@
         CUSTOM(TokenKind.CUSTOM, XERRO),  // No uses
 
         // Declarations
-        ENUM(TokenKind.ENUM, XDECL1),  //  enum
+        ENUM(TokenKind.ENUM, XDECL1|XBRACESNEEDED),  //  enum
         IMPLEMENTS(TokenKind.IMPLEMENTS, XDECL),  //  implements
-        INTERFACE(TokenKind.INTERFACE, XDECL1),  //  interface
-        THROWS(TokenKind.THROWS, XDECL),  //  throws
+        INTERFACE(TokenKind.INTERFACE, XDECL1|XBRACESNEEDED),  //  interface
+        THROWS(TokenKind.THROWS, XDECL|XBRACESNEEDED),  //  throws
 
         // Primarive type names
         BOOLEAN(TokenKind.BOOLEAN, XEXPR1|XDECL1),  //  boolean
@@ -381,6 +382,10 @@
             return (belongs & XSTART) != 0;
         }
 
+        boolean isBracesNeeded() {
+            return (belongs & XBRACESNEEDED) != 0;
+        }
+
         /**
          * After construction, check that all compiler TokenKind values have
          * corresponding TK values.
@@ -641,7 +646,9 @@
 
         public Completeness parseDeclaration() {
             boolean isImport = token.kind == IMPORT;
+            boolean isBracesNeeded = false;
             while (token.kind.isDeclaration()) {
+                isBracesNeeded |= token.kind.isBracesNeeded();
                 nextToken();
             }
             switch (token.kind) {
@@ -666,6 +673,9 @@
                         case SEMI:
                             return Completeness.COMPLETE;
                         case IDENTIFIER:
+                            return isBracesNeeded
+                                    ? Completeness.DEFINITELY_INCOMPLETE
+                                    : Completeness.COMPLETE_WITH_SEMI;
                         case BRACKETS:
                             return Completeness.COMPLETE_WITH_SEMI;
                         case DOTSTAR:
--- a/langtools/test/Makefile	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/Makefile	Wed Jul 05 22:19:40 2017 +0200
@@ -157,6 +157,15 @@
 	-refvmoptions:-Xbootclasspath/p:$(TESTBOOTCLASSPATH)
 endif
 
+ifeq ($(ARCH_DATA_MODEL),32)
+  # Set the GC options for test vms
+  JTREG_GC_OPTION = -vmoption:-XX:+UseSerialGC
+  JTREG_OPTIONS += $(JTREG_GC_OPTION)
+endif
+# Set the max memory for jtreg target test JVMs
+JTREG_TESTVM_MEMORY_OPTION = -vmoption:-Xmx768m
+JTREG_OPTIONS += $(JTREG_TESTVM_MEMORY_OPTION)
+
 ifdef EXTRA_JTREG_OPTIONS
   JTREG_OPTIONS += $(EXTRA_JTREG_OPTIONS)
 endif
@@ -304,8 +313,6 @@
 	    $(JTREG_OUTPUT_DIR)/diff.html $(JTREG_OUTPUT_DIR)/status.txt
 	@mkdir -p $(JTREG_OUTPUT_DIR)
 	JT_JAVA=$(JT_JAVA) $(JTREG) \
-	  -J-Xmx512m \
-	  -vmoption:-Xmx768m \
 	  -a -ignore:quiet $(if $(JTREG_VERBOSE),-v:$(JTREG_VERBOSE)) \
 	  -r:$(JTREG_OUTPUT_DIR)/JTreport \
 	  -w:$(JTREG_OUTPUT_DIR)/JTwork \
--- a/langtools/test/jdk/javadoc/doclet/T6735320/T6735320.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/jdk/javadoc/doclet/T6735320/T6735320.java	Wed Jul 05 22:19:40 2017 +0200
@@ -42,7 +42,7 @@
     void test() {
         javadoc("-d", "out",
                 testSrc("SerialFieldTest.java"));
-        checkExit(Exit.FAILED);
+        checkExit(Exit.ERROR);
         checkOutput(Output.STDERR, false,
                 "OutOfBoundsException");
     }
--- a/langtools/test/jdk/javadoc/doclet/dupThrowsTags/TestDupThrowsTags.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/jdk/javadoc/doclet/dupThrowsTags/TestDupThrowsTags.java	Wed Jul 05 22:19:40 2017 +0200
@@ -42,7 +42,7 @@
     void test() {
         javadoc("-d", "out",
                 testSrc("TestDupThrowsTags.java"));
-        checkExit(Exit.FAILED);
+        checkExit(Exit.ERROR);
 
         checkOutput("TestDupThrowsTags.html", true,
                 "Test 1 passes",
--- a/langtools/test/jdk/javadoc/doclet/lib/JavadocTester.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/jdk/javadoc/doclet/lib/JavadocTester.java	Wed Jul 05 22:19:40 2017 +0200
@@ -327,15 +327,27 @@
         outputDirectoryCheck = c;
     }
 
+    /**
+     * The exit codes returned by the javadoc tool.
+     * @see jdk.javadoc.internal.tool.Main.Result
+     */
     public enum Exit {
-        OK(0),
-        FAILED(1);
+        OK(0),        // Javadoc completed with no errors.
+        ERROR(1),     // Completed but reported errors.
+        CMDERR(2),    // Bad command-line arguments
+        SYSERR(3),    // System error or resource exhaustion.
+        ABNORMAL(4);  // Javadoc terminated abnormally
 
         Exit(int code) {
             this.code = code;
         }
 
         final int code;
+
+        @Override
+        public String toString() {
+            return name() + '(' + code + ')';
+        }
     }
 
     /**
@@ -349,7 +361,7 @@
         if (exitCode == expected.code) {
             passed("return code " + exitCode);
         } else {
-            failed("return code " + exitCode +"; expected " + expected.code + " (" + expected + ")");
+            failed("return code " + exitCode +"; expected " + expected);
         }
     }
 
--- a/langtools/test/jdk/javadoc/doclet/testBadSourceFile/TestBadSourceFile.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/jdk/javadoc/doclet/testBadSourceFile/TestBadSourceFile.java	Wed Jul 05 22:19:40 2017 +0200
@@ -50,6 +50,6 @@
         javadoc("-Xdoclint:none",
                 "-d", "out",
                 testSrc("C2.java"));
-        checkExit(Exit.FAILED);
+        checkExit(Exit.ERROR);
     }
 }
--- a/langtools/test/jdk/javadoc/doclet/testConstantValuesPage/TestConstantValuesPage.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/jdk/javadoc/doclet/testConstantValuesPage/TestConstantValuesPage.java	Wed Jul 05 22:19:40 2017 +0200
@@ -45,7 +45,7 @@
         javadoc("-d", "out",
                 "-sourcepath", testSrc,
                 "foo");
-        checkExit(Exit.FAILED);
+        checkExit(Exit.CMDERR);
 
         checkOutput(Output.OUT, false,
                 "constant-values.html...");
--- a/langtools/test/jdk/javadoc/doclet/testDocErrorReporter/TestDocErrorReporter.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/jdk/javadoc/doclet/testDocErrorReporter/TestDocErrorReporter.java	Wed Jul 05 22:19:40 2017 +0200
@@ -52,6 +52,8 @@
                 "-encoding", "xyz",
                 testSrc("TestDocErrorReporter.java"));
 
-        checkExit(Exit.FAILED);
+        checkExit(Exit.ERROR);
+
+        checkOutput(Output.OUT, true, "error: unsupported encoding: xyz");
     }
 }
--- a/langtools/test/jdk/javadoc/doclet/testHelpOption/TestHelpOption.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/jdk/javadoc/doclet/testHelpOption/TestHelpOption.java	Wed Jul 05 22:19:40 2017 +0200
@@ -111,7 +111,7 @@
                 "-helpfile", testSrc("test-help.html"),
                 "-helpfile", testSrc("test-help.html"),
                 testSrc("Sample.java"));
-        checkExit(Exit.FAILED);
+        checkExit(Exit.ERROR);
     }
 
     @Test
@@ -121,7 +121,7 @@
                 "-helpfile", testSrc("test-help.html"),
                 "-nohelp",
                 testSrc("Sample.java"));
-        checkExit(Exit.FAILED);
+        checkExit(Exit.ERROR);
     }
 
     private void checkOutput(boolean withOption) {
--- a/langtools/test/jdk/javadoc/doclet/testHtmlTag/TestHtmlTag.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/jdk/javadoc/doclet/testHtmlTag/TestHtmlTag.java	Wed Jul 05 22:19:40 2017 +0200
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 6786682
+ * @bug 6786682 4649116
  * @summary This test verifies the use of lang attribute by <HTML>.
  * @author Bhavesh Patel
  * @library ../lib
@@ -106,7 +106,7 @@
         checkExit(Exit.OK);
 
         checkOutput("pkg3/package-summary.html", true,
-                "<h2 title=\"Package pkg3 Description\">Package pkg3 Description</h2>\n"
+                "<div class=\"contentContainer\">\n"
                 + "<div class=\"block\"><p>This is the first line."
                 + " Note the newlines before the &lt;p&gt; is relevant.</div>");
 
--- a/langtools/test/jdk/javadoc/doclet/testHtmlVersion/TestHtmlVersion.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/jdk/javadoc/doclet/testHtmlVersion/TestHtmlVersion.java	Wed Jul 05 22:19:40 2017 +0200
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8072945 8081854 8141492 8148985 8150188
+ * @bug 8072945 8081854 8141492 8148985 8150188 4649116
  * @summary Test the version of HTML generated by the javadoc tool.
  * @author bpatel
  * @library ../lib
@@ -162,10 +162,17 @@
                 "<main role=\"main\">\n"
                 + "<div class=\"header\">",
                 "<section role=\"region\">\n"
-                + "<h2 title=\"Package pkg Description\">Package pkg Description</h2>\n",
+                + "<div class=\"block\">Test package.</div>",
                 "<footer role=\"contentinfo\">\n"
                 + "<nav role=\"navigation\">\n"
                 + "<!-- ======= START OF BOTTOM NAVBAR ====== -->");
+        // No package description
+        checkOutput("pkg1/package-summary.html", true,
+                "<div class=\"contentContainer\">\n"
+                + "<ul class=\"blockList\">\n"
+                + "<li class=\"blockList\">\n"
+                + "<table class=\"typeSummary\">\n"
+                + "<caption><span>Class Summary</span><span class=\"tabEnd\">&nbsp;</span></caption>");
 
         // Test for package-tree page
         checkOutput("pkg/package-tree.html", true,
@@ -662,6 +669,8 @@
                 "<a name=\"navbar.top.firstrow\">\n"
                 + "<!--   -->\n"
                 + "</a>",
+                "<section role=\"region\">\n"
+                + "<h2 title=\"Package pkg Description\">Package pkg Description</h2>\n",
                 "<table class=\"typeSummary\" summary=\"Interface Summary table, listing interfaces, and an explanation\">",
                 "<table class=\"typeSummary\" summary=\"Class Summary table, listing classes, and an explanation\">",
                 "<table class=\"typeSummary\" summary=\"Enum Summary table, listing enums, and an explanation\">",
@@ -1060,12 +1069,21 @@
                 "<a name=\"navbar.top.firstrow\">\n"
                 + "<!--   -->\n"
                 + "</a>",
+                "<div class=\"contentContainer\">\n"
+                + "<div class=\"block\">Test package.</div>",
                 "<table class=\"typeSummary\" summary=\"Interface Summary table, listing interfaces, and an explanation\">",
                 "<table class=\"typeSummary\" summary=\"Class Summary table, listing classes, and an explanation\">",
                 "<table class=\"typeSummary\" summary=\"Enum Summary table, listing enums, and an explanation\">",
                 "<table class=\"typeSummary\" summary=\"Exception Summary table, listing exceptions, and an explanation\">",
                 "<table class=\"typeSummary\" summary=\"Error Summary table, listing errors, and an explanation\">",
                 "<table class=\"typeSummary\" summary=\"Annotation Types Summary table, listing annotation types, and an explanation\">");
+        // No Package description
+        checkOutput("pkg1/package-summary.html", true,
+                "<div class=\"contentContainer\">\n"
+                + "<ul class=\"blockList\">\n"
+                + "<li class=\"blockList\">\n"
+                + "<table class=\"typeSummary\" summary=\"Class Summary table, listing classes, and an explanation\">\n"
+                + "<caption><span>Class Summary</span><span class=\"tabEnd\">&nbsp;</span></caption>");
 
         // Test for package-tree page
         checkOutput("pkg/package-tree.html", true,
@@ -1485,8 +1503,7 @@
                 + "<!-- ========= START OF TOP NAVBAR ======= -->",
                 "<main role=\"main\">\n"
                 + "<div class=\"header\">",
-                "<section role=\"region\">\n"
-                + "<h2 title=\"Package pkg Description\">Package pkg Description</h2>\n",
+                "<h2 title=\"Package pkg Description\">Package pkg Description</h2>\n",
                 "<footer role=\"contentinfo\">\n"
                 + "<nav role=\"navigation\">\n"
                 + "<!-- ======= START OF BOTTOM NAVBAR ====== -->");
--- a/langtools/test/jdk/javadoc/doclet/testIOException/TestIOException.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/jdk/javadoc/doclet/testIOException/TestIOException.java	Wed Jul 05 22:19:40 2017 +0200
@@ -57,7 +57,7 @@
         try {
             javadoc("-d", outDir.toString(),
                     new File(testSrc, "TestIOException.java").getPath());
-            checkExit(Exit.FAILED);
+            checkExit(Exit.ERROR);
             checkOutput(Output.OUT, true,
                 "Destination directory not writable: " + outDir);
         } finally {
@@ -85,7 +85,7 @@
             javadoc("-d", outDir.toString(),
                     new File(testSrc, "TestIOException.java").getPath());
 
-            checkExit(Exit.FAILED);
+            checkExit(Exit.ERROR);
             checkOutput(Output.OUT, true,
                 "Error writing file: " + index);
         } finally {
@@ -123,7 +123,7 @@
             setOutputDirectoryCheck(DirectoryCheck.NONE);
             javadoc("-d", outDir.toString(),
                     src_p_C.getPath());
-            checkExit(Exit.FAILED);
+            checkExit(Exit.ERROR);
             checkOutput(Output.OUT, true,
                 "Error writing file: " + new File(pkgOutDir, "C.html"));
         } finally {
@@ -167,7 +167,7 @@
             javadoc("-d", outDir.toString(),
                     "-sourcepath", srcDir.getPath(),
                     "p");
-            checkExit(Exit.FAILED);
+            checkExit(Exit.ERROR);
             checkOutput(Output.OUT, true,
                 "Error writing file: " + new File(docFilesOutDir, "info.txt"));
         } finally {
--- a/langtools/test/jdk/javadoc/doclet/testJavaFX/TestJavaFX.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/jdk/javadoc/doclet/testJavaFX/TestJavaFX.java	Wed Jul 05 22:19:40 2017 +0200
@@ -61,8 +61,14 @@
                     + "<div class=\"block\">Gets the value of the property rate.</div>\n"
                     + "<dl>\n"
                     + "<dt><span class=\"simpleTagLabel\">Property description:</span></dt>",
-                "<th class=\"colSecond\" scope=\"row\"><code><span class=\"memberNameLink\">"
-                    + "<a href=\"../pkg1/C.html#rateProperty\">rate</a></span></code>",
+                "<td class=\"colFirst\"><code><a href=\"../pkg1/C.DoubleProperty.html\" "
+                    + "title=\"class in pkg1\">C.DoubleProperty</a></code></td>\n"
+                    + "<th class=\"colSecond\" scope=\"row\"><code><span class=\"memberNameLink\">"
+                    + "<a href=\"../pkg1/C.html#rateProperty\">rate</a></span></code></th>\n"
+                    + "<td class=\"colLast\">\n"
+                    + "<div class=\"block\">Defines the direction/speed at which the "
+                    + "<code>Timeline</code> is expected to\n"
+                    + " be played.</div>\n</td>",
                 "<span class=\"simpleTagLabel\">Default value:</span>",
                 "<span class=\"simpleTagLabel\">Since:</span></dt>\n"
                     + "<dd>JavaFX 8.0</dd>",
@@ -72,13 +78,70 @@
                 "<th class=\"colSecond\" scope=\"row\"><code><span class=\"memberNameLink\">"
                     + "<a href=\"../pkg1/C.html#setTestMethodProperty--\">"
                     + "setTestMethodProperty</a></span>()</code></th>",
+                "<th class=\"colSecond\" scope=\"row\"><code><span class=\"memberNameLink\">"
+                    + "<a href=\"../pkg1/C.html#pausedProperty\">paused</a></span></code></th>\n"
+                    + "<td class=\"colLast\">\n"
+                    + "<div class=\"block\">Defines if paused.</div>",
+                "<h4>paused</h4>\n"
+                    + "<pre>public final&nbsp;<a href=\"../pkg1/C.BooleanProperty.html\" "
+                    + "title=\"class in pkg1\">C.BooleanProperty</a> pausedProperty</pre>\n"
+                    + "<div class=\"block\">Defines if paused. The second line.</div>",
+                "<h4>isPaused</h4>\n"
+                    + "<pre>public final&nbsp;double&nbsp;isPaused()</pre>\n"
+                    + "<div class=\"block\">Gets the value of the property paused.</div>",
+                "<h4>setPaused</h4>\n"
+                    + "<pre>public final&nbsp;void&nbsp;setPaused(boolean&nbsp;value)</pre>\n"
+                    + "<div class=\"block\">Sets the value of the property paused.</div>\n"
+                    + "<dl>\n"
+                    + "<dt><span class=\"simpleTagLabel\">Property description:</span></dt>\n"
+                    + "<dd>Defines if paused. The second line.</dd>\n"
+                    + "<dt><span class=\"simpleTagLabel\">Default value:</span></dt>\n"
+                    + "<dd>false</dd>",
                 "<h4>isPaused</h4>\n"
                     + "<pre>public final&nbsp;double&nbsp;isPaused()</pre>\n"
-                    + "<div class=\"block\">Gets the value of the property paused.</div>");
+                    + "<div class=\"block\">Gets the value of the property paused.</div>\n"
+                    + "<dl>\n"
+                    + "<dt><span class=\"simpleTagLabel\">Property description:</span></dt>\n"
+                    + "<dd>Defines if paused. The second line.</dd>\n"
+                    + "<dt><span class=\"simpleTagLabel\">Default value:</span></dt>\n"
+                    + "<dd>false</dd>",
+                "<h4>rate</h4>\n"
+                    + "<pre>public final&nbsp;<a href=\"../pkg1/C.DoubleProperty.html\" "
+                    + "title=\"class in pkg1\">C.DoubleProperty</a> rateProperty</pre>\n"
+                    + "<div class=\"block\">Defines the direction/speed at which the "
+                    + "<code>Timeline</code> is expected to\n"
+                    + " be played. This is the second line.</div>",
+                "<h4>setRate</h4>\n"
+                    + "<pre>public final&nbsp;void&nbsp;setRate(double&nbsp;value)</pre>\n"
+                    + "<div class=\"block\">Sets the value of the property rate.</div>\n"
+                    + "<dl>\n"
+                    + "<dt><span class=\"simpleTagLabel\">Property description:</span></dt>\n"
+                    + "<dd>Defines the direction/speed at which the <code>Timeline</code> is expected to\n"
+                    + " be played. This is the second line.</dd>\n"
+                    + "<dt><span class=\"simpleTagLabel\">Default value:</span></dt>\n"
+                    + "<dd>11</dd>\n"
+                    + "<dt><span class=\"simpleTagLabel\">Since:</span></dt>\n"
+                    + "<dd>JavaFX 8.0</dd>",
+                "<h4>getRate</h4>\n"
+                    + "<pre>public final&nbsp;double&nbsp;getRate()</pre>\n"
+                    + "<div class=\"block\">Gets the value of the property rate.</div>\n"
+                    + "<dl>\n"
+                    + "<dt><span class=\"simpleTagLabel\">Property description:</span></dt>\n"
+                    + "<dd>Defines the direction/speed at which the <code>Timeline</code> is expected to\n"
+                    + " be played. This is the second line.</dd>\n"
+                    + "<dt><span class=\"simpleTagLabel\">Default value:</span></dt>\n"
+                    + "<dd>11</dd>\n"
+                    + "<dt><span class=\"simpleTagLabel\">Since:</span></dt>\n"
+                    + "<dd>JavaFX 8.0</dd>",
+                "");
 
         checkOutput("pkg1/C.html", false,
                 "A()");
 
+        checkOutput("index-all.html", true,
+                "<div class=\"block\">Gets the value of the property paused.</div>",
+                "<div class=\"block\">Defines if paused.</div>");
+
         checkOutput("pkg1/D.html", true,
                 "<h3>Properties inherited from class&nbsp;pkg1."
                     + "<a href=\"../pkg1/C.html\" title=\"class in pkg1\">C</a></h3>\n"
--- a/langtools/test/jdk/javadoc/doclet/testJavaFX/pkg1/C.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/jdk/javadoc/doclet/testJavaFX/pkg1/C.java	Wed Jul 05 22:19:40 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, 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
@@ -52,7 +52,7 @@
 
     /**
      * Defines the direction/speed at which the {@code Timeline} is expected to
-     * be played.
+     * be played. This is the second line.
      * @defaultValue 11
      * @since JavaFX 8.0
      */
@@ -71,7 +71,7 @@
     public final double isPaused() {}
 
     /**
-     * Defines if paused
+     * Defines if paused. The second line.
      * @defaultValue false
      */
     public final BooleanProperty pausedProperty() {}
@@ -87,7 +87,7 @@
 
         /**
          * Defines the direction/speed at which the {@code Timeline} is expected to
-         * be played.
+         * be played. This is the second line.
          * @defaultValue 11
          */
         private DoubleProperty rate;
--- a/langtools/test/jdk/javadoc/doclet/testPackageHtml/TestPackageHtml.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/jdk/javadoc/doclet/testPackageHtml/TestPackageHtml.java	Wed Jul 05 22:19:40 2017 +0200
@@ -42,7 +42,7 @@
         javadoc("-d", "out-pkg-html",
                 "-sourcepath", testSrc,
                 "pkg1");
-        checkExit(Exit.FAILED);
+        checkExit(Exit.ERROR);
         checkOutput(Output.OUT, true, "package.html:10: error: bad use of '>'");
     }
 }
--- a/langtools/test/jdk/javadoc/doclet/testParamTaglet/TestParamTaglet.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/jdk/javadoc/doclet/testParamTaglet/TestParamTaglet.java	Wed Jul 05 22:19:40 2017 +0200
@@ -46,7 +46,7 @@
         javadoc("-d", "out",
                 "-sourcepath", testSrc,
                 "pkg");
-        checkExit(Exit.FAILED);
+        checkExit(Exit.ERROR);
 
         checkOutput("pkg/C.html", true,
                 //Regular param tags.
--- a/langtools/test/jdk/javadoc/doclet/testSearch/TestSearch.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/jdk/javadoc/doclet/testSearch/TestSearch.java	Wed Jul 05 22:19:40 2017 +0200
@@ -73,7 +73,7 @@
     void test2a() {
         javadoc("-d", "out-2a", "-Xdoclint:all", "-sourcepath", testSrc,
                 "-use", "pkg", "pkg1", "pkg2", "pkg3");
-        checkExit(Exit.FAILED);
+        checkExit(Exit.ERROR);
         checkDocLintErrors();
         checkSearchOutput(true);
         checkSingleIndex(true);
--- a/langtools/test/jdk/javadoc/doclet/testSerializedFormDeprecationInfo/TestSerializedFormDeprecationInfo.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/jdk/javadoc/doclet/testSerializedFormDeprecationInfo/TestSerializedFormDeprecationInfo.java	Wed Jul 05 22:19:40 2017 +0200
@@ -44,7 +44,7 @@
         javadoc("-d", "out-default",
                 "-sourcepath", testSrc,
                 "pkg1");
-        checkExit(Exit.FAILED); // TODO: should be OK
+        checkExit(Exit.OK);
 
         checkCommentDeprecated(true);
         checkNoComment(false);
@@ -56,7 +56,7 @@
                 "-nocomment",
                 "-sourcepath", testSrc,
                 "pkg1");
-        checkExit(Exit.FAILED); // TODO: should be OK
+        checkExit(Exit.OK);
 
         checkNoComment(true);
         checkCommentDeprecated(false);
@@ -68,7 +68,7 @@
                 "-nodeprecated",
                 "-sourcepath", testSrc,
                 "pkg1");
-        checkExit(Exit.FAILED); // TODO: should be OK
+        checkExit(Exit.OK);
 
         checkNoDeprecated(true);
         checkNoCommentNoDeprecated(false);
@@ -81,7 +81,7 @@
                 "-nodeprecated",
                 "-sourcepath", testSrc,
                 "pkg1");
-        checkExit(Exit.FAILED); // TODO: should be OK
+        checkExit(Exit.OK);
         checkNoCommentNoDeprecated(true);
         checkNoDeprecated(false);
     }
@@ -93,7 +93,7 @@
                 "<dl>\n"
                 + "<dt><span class=\"throwsLabel\">Throws:</span></dt>\n"
                 + "<dd><code>"
-                + "java.io.IOException</code></dd>\n"
+                + "java.io.IOException</code> - on error</dd>\n"
                 + "<dt><span class=\"seeLabel\">See Also:</span>"
                 + "</dt>\n"
                 + "<dd><a href=\"pkg1/C1.html#setUndecorated-boolean-\">"
@@ -121,7 +121,7 @@
                 + "<div class=\"block\">Reads the object stream.</div>\n"
                 + "<dl>\n"
                 + "<dt><span class=\"throwsLabel\">Throws:</span></dt>\n"
-                + "<dd><code>java.io.IOException</code></dd>\n"
+                + "<dd><code>java.io.IOException</code> - on error</dd>\n"
                 + "</dl>",
                 "<span class=\"deprecatedLabel\">Deprecated.</span>"
                 + "&nbsp;</div>\n"
--- a/langtools/test/jdk/javadoc/doclet/testSerializedFormDeprecationInfo/pkg1/C1.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/jdk/javadoc/doclet/testSerializedFormDeprecationInfo/pkg1/C1.java	Wed Jul 05 22:19:40 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -75,7 +75,6 @@
      * @param test boolean value
      * @exception IllegalArgumentException if the <code>owner</code>'s
      *     <code>GraphicsConfiguration</code> is not from a screen device
-     * @exception HeadlessException
      */
      public C1(String title, boolean test) {
 
@@ -98,6 +97,7 @@
     }
 
     /**
+     * @throws java.io.IOException on error
      * @see #setUndecorated(boolean)
      */
     public void readObject() throws IOException {
--- a/langtools/test/jdk/javadoc/doclet/testSerializedFormDeprecationInfo/pkg1/C2.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/jdk/javadoc/doclet/testSerializedFormDeprecationInfo/pkg1/C2.java	Wed Jul 05 22:19:40 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -74,7 +74,7 @@
      * Reads the object stream.
      *
      * @param s ObjectInputStream
-     * @throws IOException
+     * @throws IOException on error
      * @deprecated As of JDK version 1.5, replaced by
      * {@link C1#setUndecorated(boolean) setUndecorated(boolean)}.
      */
--- a/langtools/test/jdk/javadoc/doclet/testSinceTag/TestSinceTag.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/jdk/javadoc/doclet/testSinceTag/TestSinceTag.java	Wed Jul 05 22:19:40 2017 +0200
@@ -45,7 +45,7 @@
         javadoc("-d", "out-since",
                 "-sourcepath", testSrc,
                 "pkg1");
-        checkExit(Exit.FAILED); // TODO: investigate
+        checkExit(Exit.OK);
 
         checkSince(true);
     }
@@ -56,7 +56,7 @@
                 "-sourcepath", testSrc,
                 "-nosince",
                 "pkg1");
-        checkExit(Exit.FAILED); // TODO: investigate
+        checkExit(Exit.OK);
 
         checkSince(false);
     }
--- a/langtools/test/jdk/javadoc/doclet/testSinceTag/pkg1/C1.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/jdk/javadoc/doclet/testSinceTag/pkg1/C1.java	Wed Jul 05 22:19:40 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 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
@@ -72,7 +72,6 @@
      * @param test boolean value
      * @exception IllegalArgumentException if the <code>owner</code>'s
      *     <code>GraphicsConfiguration</code> is not from a screen device
-     * @exception HeadlessException
      */
     public C1(String title, boolean test) {
     }
@@ -93,6 +92,7 @@
     }
 
     /**
+     * @throws java.io.IOException on error
      * @see #setUndecorated(boolean)
      */
     public void readObject() throws IOException {
--- a/langtools/test/jdk/javadoc/doclet/testSupplementary/TestSupplementary.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/jdk/javadoc/doclet/testSupplementary/TestSupplementary.java	Wed Jul 05 22:19:40 2017 +0200
@@ -52,7 +52,7 @@
         javadoc("-locale", "en_US",
                 "-d", "out",
                 testSrc("C.java"));
-        checkExit(Exit.FAILED);
+        checkExit(Exit.ERROR);
 
         checkOutput(Output.OUT, true,
             "C.java:36: error: unexpected text",
--- a/langtools/test/jdk/javadoc/doclet/testThrowsTag/TestThrowsTag.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/jdk/javadoc/doclet/testThrowsTag/TestThrowsTag.java	Wed Jul 05 22:19:40 2017 +0200
@@ -45,7 +45,7 @@
         javadoc("-d", "out",
                 "-sourcepath", testSrc,
                 "pkg");
-        checkExit(Exit.FAILED);  // TODO: investigate why failed
+        checkExit(Exit.OK);
 
         checkOutput("pkg/C.html", true,
             "<dd><code><a href=\"../pkg/T1.html\" title=\"class in pkg\">T1</a></code> - the first throws tag.</dd>\n" +
--- a/langtools/test/jdk/javadoc/doclet/testThrowsTag/pkg/T1.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/jdk/javadoc/doclet/testThrowsTag/pkg/T1.java	Wed Jul 05 22:19:40 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 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,4 +23,4 @@
 
 package pkg;
 
-public class T1 extends Exception {}
+public class T1 extends RuntimeException {}
--- a/langtools/test/jdk/javadoc/doclet/testThrowsTag/pkg/T2.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/jdk/javadoc/doclet/testThrowsTag/pkg/T2.java	Wed Jul 05 22:19:40 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 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,4 +23,4 @@
 
 package pkg;
 
-public class T2 extends Exception {}
+public class T2 extends RuntimeException {}
--- a/langtools/test/jdk/javadoc/doclet/testThrowsTag/pkg/T3.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/jdk/javadoc/doclet/testThrowsTag/pkg/T3.java	Wed Jul 05 22:19:40 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 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,4 +23,4 @@
 
 package pkg;
 
-public class T3 extends Exception {}
+public class T3 extends RuntimeException {}
--- a/langtools/test/jdk/javadoc/doclet/testThrowsTag/pkg/T4.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/jdk/javadoc/doclet/testThrowsTag/pkg/T4.java	Wed Jul 05 22:19:40 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 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,4 +23,4 @@
 
 package pkg;
 
-public class T4 extends Exception {}
+public class T4 extends RuntimeException {}
--- a/langtools/test/jdk/javadoc/doclet/testValueTag/TestValueTag.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/jdk/javadoc/doclet/testValueTag/TestValueTag.java	Wed Jul 05 22:19:40 2017 +0200
@@ -46,7 +46,7 @@
                 "-sourcepath", testSrc,
                 "-tag", "todo",
                 "pkg1", "pkg2");
-        checkExit(Exit.FAILED);
+        checkExit(Exit.ERROR);
 
         checkOutput("pkg1/Class1.html", true,
                 // Base case:  using @value on a constant.
--- a/langtools/test/jdk/javadoc/doclet/testWarnings/TestWarnings.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/jdk/javadoc/doclet/testWarnings/TestWarnings.java	Wed Jul 05 22:19:40 2017 +0200
@@ -47,7 +47,7 @@
         javadoc("-d", "out-default",
                 "-sourcepath", testSrc,
                 "pkg");
-        checkExit(Exit.FAILED);
+        checkExit(Exit.ERROR);
 
         checkOutput(Output.OUT, true,
                 "X.java:23: error: self-closing element not allowed");
@@ -75,7 +75,7 @@
                 "-private",
                 "-sourcepath", testSrc,
                 "pkg");
-        checkExit(Exit.FAILED);
+        checkExit(Exit.ERROR);
 
         checkOutput("pkg/X.html", true,
             "<a href=\"../pkg/X.html#m--\"><code>m()</code></a><br/>",
--- a/langtools/test/jdk/javadoc/tool/ReleaseOption.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/jdk/javadoc/tool/ReleaseOption.java	Wed Jul 05 22:19:40 2017 +0200
@@ -28,7 +28,11 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.function.Predicate;
+
 import jdk.javadoc.internal.tool.Main;
+import jdk.javadoc.internal.tool.Main.Result;
+
+import static jdk.javadoc.internal.tool.Main.Result.*;
 
 /**
  * @test
@@ -43,13 +47,13 @@
     }
 
     void run() {
-        doRunTest(0, out -> out.contains("compiler.err.doesnt.exist: java.util.stream"), "--release", "7");
-        doRunTest(0, out -> !out.contains("compiler.err.doesnt.exist: java.util.stream"), "--release", "8");
-        doRunTest(1, out -> true, "--release", "7", "-source", "7");
-        doRunTest(1, out -> true, "--release", "7", "-bootclasspath", "any");
+        doRunTest(OK, out -> out.contains("compiler.err.doesnt.exist: java.util.stream"), "--release", "7");
+        doRunTest(OK, out -> !out.contains("compiler.err.doesnt.exist: java.util.stream"), "--release", "8");
+        doRunTest(CMDERR, out -> true, "--release", "7", "-source", "7");
+        doRunTest(CMDERR, out -> true, "--release", "7", "-bootclasspath", "any");
     }
 
-    void doRunTest(int expectedResult, Predicate<String> validate, String... args) {
+    void doRunTest(Result expectedResult, Predicate<String> validate, String... args) {
         System.err.println("running with args: " + Arrays.asList(args));
         List<String> options = new ArrayList<>();
         options.addAll(Arrays.asList(args));
@@ -60,7 +64,7 @@
         int actualResult = Main.execute(options.toArray(new String[0]), pw);
         System.err.println("actual result=" + actualResult);
         System.err.println("actual output=" + out.toString());
-        if (actualResult != expectedResult)
+        if (actualResult != expectedResult.exitCode)
             throw new Error("Exit code not as expected");
         if (!validate.test(out.toString())) {
             throw new Error("Output not as expected");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/jdk/javadoc/tool/ToolProviderTest.java	Wed Jul 05 22:19:40 2017 +0200
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8159855
+ * @summary test javadoc's ToolProvider
+ * @library /tools/lib
+ * @build toolbox.TestRunner toolbox.ToolBox
+ * @run main ToolProviderTest
+ */
+
+import java.io.*;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.*;
+import java.util.spi.ToolProvider;
+
+import toolbox.TestRunner;
+import toolbox.ToolBox;
+
+public class ToolProviderTest extends TestRunner {
+    public static void main(String... args) throws Exception {
+        new ToolProviderTest().runTests();
+    }
+
+    ToolBox tb = new ToolBox();
+    ToolProvider javadoc;
+
+    ToolProviderTest() {
+        super(System.err);
+        javadoc = ToolProvider.findFirst("javadoc").get();
+    }
+
+    @Test
+    public void testProviders() throws Exception {
+        Map<String, ToolProvider> providers = new LinkedHashMap<>();
+        for (ToolProvider tp : ServiceLoader.load(ToolProvider.class,
+                ClassLoader.getSystemClassLoader())) {
+            System.out.println("Provider: " + tp.name() + ": " + tp.getClass().getName());
+            providers.put(tp.name(), tp);
+        }
+        if (!providers.containsKey("javadoc")) {
+            error("javadoc ToolProvider not found");
+        }
+    }
+
+    @Test
+    public void testOneStream() throws Exception {
+        StringWriter sw = new StringWriter();
+        try (PrintWriter pw = new PrintWriter(sw)) {
+            int rc = javadoc.run(pw, pw, "-help");
+            if (rc != 0) {
+                error("unexpected exit code: " + rc);
+            }
+        }
+        String out = sw.toString();
+        if (!out.contains("Usage:")) {
+            error("expected output not found");
+        }
+    }
+
+    @Test
+    public void testTwoStreamsOut() throws Exception {
+        StringWriter swOut = new StringWriter();
+        StringWriter swErr = new StringWriter();
+        try (PrintWriter pwOut = new PrintWriter(swOut);
+                PrintWriter pwErr = new PrintWriter(swErr)) {
+            int rc = javadoc.run(pwOut, pwErr, "-help");
+            if (rc != 0) {
+                error("unexpected exit code: " + rc);
+            }
+        }
+        String out = swOut.toString();
+        String err = swErr.toString();
+        if (!out.contains("Usage:")) {
+            error("stdout: expected output not found");
+        }
+        if (!err.isEmpty()) {
+            error("stderr: unexpected output");
+        }
+    }
+
+    @Test
+    public void testTwoStreamsErr() throws Exception {
+        Path src = Paths.get("src");
+        Path classes = Paths.get("classes");
+        tb.writeJavaFiles(src,
+            "import java.util.*; class C { # }");
+
+        StringWriter swOut = new StringWriter();
+        StringWriter swErr = new StringWriter();
+        try (PrintWriter pwOut = new PrintWriter(swOut);
+                PrintWriter pwErr = new PrintWriter(swErr)) {
+            int rc = javadoc.run(pwOut, pwErr,
+                "-d", classes.toString(),
+                src.resolve("C.java").toString());
+            if (rc != 1) {
+                error("unexpected exit code: " + rc);
+            }
+        }
+
+        String out = swOut.toString();
+        String err = swErr.toString();
+
+        if (!out.contains("Loading")) {
+            error("stdout: unexpected output");
+        }
+        if (!err.contains("illegal character")) {
+            error("stderr: expected output not found");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/jdk/javadoc/tool/exceptionHandling/TestExceptionHandling.java	Wed Jul 05 22:19:40 2017 +0200
@@ -0,0 +1,146 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8151102
+ * @summary verify that option --dump-on-error functions correctly
+ * @library /tools/lib
+ * @modules
+ *      jdk.javadoc/jdk.javadoc.internal.api
+ *      jdk.javadoc/jdk.javadoc.internal.tool
+ *      jdk.compiler/com.sun.tools.javac.api
+ *      jdk.compiler/com.sun.tools.javac.main
+ * @build toolbox.ToolBox toolbox.TestRunner
+ * @run main TestExceptionHandling
+ */
+
+import java.io.File;
+import java.io.PrintStream;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+
+import toolbox.*;
+
+/**
+ * This class tests if stack traces printed when
+ * --dump-on-error. The standard doclet is used,
+ * to test the doclet as well as the tool.
+ */
+public class TestExceptionHandling  extends TestRunner {
+
+    final ToolBox tb;
+    final File testSrcFile;
+    final PrintStream ostream;
+    final JavadocTask cmdTask;
+    final JavadocTask apiTask;
+
+    public static void main(String... args) throws Exception {
+        TestExceptionHandling tester = new TestExceptionHandling();
+        tester.runTests();
+    }
+
+    TestExceptionHandling() {
+        super(System.err);
+        tb = new ToolBox();
+        ostream = System.err;
+        testSrcFile = new File(System.getProperty("test.src"), "TestExceptionHandling.java");
+        cmdTask = new JavadocTask(tb, Task.Mode.CMDLINE);
+        apiTask = new JavadocTask(tb, Task.Mode.API);
+    }
+
+    @Test
+    public void testDocletTrace() throws Exception {
+        Path out = Paths.get("out");
+        // create a file with the same name as the output
+        out.toFile().createNewFile();
+        cmdTask.outdir(out);
+        cmdTask.options("--dump-on-error");
+        cmdTask.files(testSrcFile.getAbsolutePath());
+        Task.Result tr = cmdTask.run(Task.Expect.FAIL);
+
+        String errString = "Destination directory is not a directory: " + out.toString();
+        // check the regular message
+        assertPresent("javadoc: error - " + errString, tr.getOutputLines(Task.OutputKind.DIRECT));
+        // check that first line of the stack trace is present
+        assertPresent("jdk.javadoc.internal.doclets.toolkit.util.SimpleDocletException: " +
+                errString, tr.getOutputLines(Task.OutputKind.STDERR));
+
+    }
+
+    @Test
+    public void testToolTrace() throws Exception {
+        Path out = Paths.get("out.dir");
+        cmdTask.options("--dump-on-error", "-doclet", "NonExistentDoclet");
+        cmdTask.outdir(out);
+        cmdTask.files(testSrcFile.getAbsolutePath());
+        Task.Result tr = cmdTask.run(Task.Expect.FAIL);
+
+        // check the regular message
+        assertPresent("javadoc: error - Cannot find doclet class NonExistentDoclet",
+                tr.getOutputLines(Task.OutputKind.DIRECT));
+
+        // check that first line of the stack trace is present
+        assertPresent("java.lang.ClassNotFoundException: NonExistentDoclet",
+                tr.getOutputLines(Task.OutputKind.STDERR));
+
+    }
+
+    @Test
+    public void testApiModeMissingDoclet() throws Exception {
+        apiTask.options("-doclet", "MissingDoclet");
+        try {
+            Task.Result result = apiTask.run(Task.Expect.FAIL);
+        } catch (IllegalArgumentException iae) {
+            // ok got the right exception
+            return;
+        }
+        throw new Exception("expected exception/error not found");
+    }
+
+    @Test
+    public void testApiModeMultipleDoclets() throws Exception {
+        apiTask.options("-doclet", "MissingDoclet",
+                "-doclet", "SomeDoclet");
+        try {
+            Task.Result result = apiTask.run(Task.Expect.FAIL);
+        } catch (IllegalArgumentException iae) {
+            // ok got the right exception
+            return;
+        }
+        throw new Exception("expected exception/error not found");
+    }
+
+    void assertPresent(String regex, List<String> output) throws Exception {
+        List<String> gresult = tb.grep(regex, output);
+        if (gresult.isEmpty()) {
+            ostream.println("Expected: " + regex);
+            ostream.println("Output: ");
+            output.forEach(s -> {
+                ostream.println(s);
+            });
+            throw new Exception("Test fails expected output not found: " + regex);
+        }
+    }
+}
--- a/langtools/test/jdk/jshell/CompletenessTest.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/jdk/jshell/CompletenessTest.java	Wed Jul 05 22:19:40 2017 +0200
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8149524 8131024 8165211 8080071 8130454
+ * @bug 8149524 8131024 8165211 8080071 8130454 8167343
  * @summary Test SourceCodeAnalysis
  * @build KullaTesting TestingInputStream
  * @run testng CompletenessTest
@@ -117,6 +117,7 @@
         "bar: g()",
         "baz: while (true) if (t()) printf('-'); else break baz",
         "java.util.function.IntFunction<int[]> ggg = int[]::new",
+        "List<? extends Object> l",
     };
 
     static final String[] considered_incomplete = new String[] {
@@ -162,7 +163,19 @@
         "enum TK { EOF(TokenKind.EOF, 0),",
         "enum TK { EOF(TokenKind.EOF, 0), NEW_MIDDLE(XEXPR1|XTERM)",
         "enum TK { EOF(TokenKind.EOF, 0), NEW_MIDDLE(XEXPR1|XTERM); ",
-        "enum Tt { FOO, BAR, BAZ,;"
+        "enum Tt { FOO, BAR, BAZ,;",
+        "class C",
+        "class C extends D",
+        "class C implements D",
+        "class C implements D, E",
+        "interface I extends D",
+        "interface I extends D, E",
+        "enum E",
+        "enum E implements I1",
+        "enum E implements I1, I2",
+        "@interface Anno",
+        "void f()",
+        "void f() throws E",
     };
 
     static final String[] unknown = new String[] {
--- a/langtools/test/tools/javac/T8003967/DetectMutableStaticFields.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/tools/javac/T8003967/DetectMutableStaticFields.java	Wed Jul 05 22:19:40 2017 +0200
@@ -118,6 +118,8 @@
                 "loadMethod");
         ignore("com/sun/tools/javac/util/JDK9Wrappers$VMHelper",
                 "vmClass", "getRuntimeArgumentsMethod");
+        ignore("com/sun/tools/javac/util/JDK9Wrappers$JmodFile",
+                "jmodFileClass", "checkMagicMethod");
     }
 
     private final List<String> errors = new ArrayList<>();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/LeaksNotAccessible/LeaksNotAccessible.java	Wed Jul 05 22:19:40 2017 +0200
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+// key: compiler.warn.leaks.not.accessible
+// options: -Xlint:exports
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/LeaksNotAccessible/modulesourcepath/m1/api/Api.java	Wed Jul 05 22:19:40 2017 +0200
@@ -0,0 +1,32 @@
+/*
+ * 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 api;
+
+public class Api {
+     public Impl getImpl() {
+         return null;
+     }
+}
+
+class Impl {}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/LeaksNotAccessible/modulesourcepath/m1/module-info.java	Wed Jul 05 22:19:40 2017 +0200
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+module m1 {
+     exports api;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/LeaksNotAccessibleNotRequiredPublic/LeaksNotAccessibleNotRequiredPublic.java	Wed Jul 05 22:19:40 2017 +0200
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+// key: compiler.warn.leaks.not.accessible.not.required.public
+// options: -Xlint:exports
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/LeaksNotAccessibleNotRequiredPublic/modulesourcepath/m1/api1/Api1.java	Wed Jul 05 22:19:40 2017 +0200
@@ -0,0 +1,27 @@
+/*
+ * 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 api1;
+
+public class Api1 {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/LeaksNotAccessibleNotRequiredPublic/modulesourcepath/m1/module-info.java	Wed Jul 05 22:19:40 2017 +0200
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+module m1 {
+     exports api1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/LeaksNotAccessibleNotRequiredPublic/modulesourcepath/m2/api2/Api2.java	Wed Jul 05 22:19:40 2017 +0200
@@ -0,0 +1,30 @@
+/*
+ * 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 api2;
+
+public class Api2 {
+     public api1.Api1 getApi1() {
+         return null;
+     }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/LeaksNotAccessibleNotRequiredPublic/modulesourcepath/m2/module-info.java	Wed Jul 05 22:19:40 2017 +0200
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+module m2 {
+     requires m1;
+     exports api2;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/LeaksNotAccessibleUnexported/LeaksNotAccessibleUnexported.java	Wed Jul 05 22:19:40 2017 +0200
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+// key: compiler.warn.leaks.not.accessible.unexported
+// options: -Xlint:exports
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/LeaksNotAccessibleUnexported/modulesourcepath/m1/api/Api.java	Wed Jul 05 22:19:40 2017 +0200
@@ -0,0 +1,30 @@
+/*
+ * 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 api;
+
+public class Api {
+     public impl.Impl getImpl() {
+         return null;
+     }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/LeaksNotAccessibleUnexported/modulesourcepath/m1/impl/Impl.java	Wed Jul 05 22:19:40 2017 +0200
@@ -0,0 +1,27 @@
+/*
+ * 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 impl;
+
+public class Impl {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/LeaksNotAccessibleUnexported/modulesourcepath/m1/module-info.java	Wed Jul 05 22:19:40 2017 +0200
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+module m1 {
+     exports api;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/LeaksNotAccessibleUnexportedQualified/LeaksNotAccessibleUnexportedQualified.java	Wed Jul 05 22:19:40 2017 +0200
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+// key: compiler.warn.leaks.not.accessible.unexported.qualified
+// options: -Xlint:exports
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/LeaksNotAccessibleUnexportedQualified/modulesourcepath/m1/api/Api.java	Wed Jul 05 22:19:40 2017 +0200
@@ -0,0 +1,30 @@
+/*
+ * 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 api;
+
+public class Api {
+     public qapi.QApi get() {
+         return null;
+     }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/LeaksNotAccessibleUnexportedQualified/modulesourcepath/m1/module-info.java	Wed Jul 05 22:19:40 2017 +0200
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+module m1 {
+     exports api;
+     exports qapi to m2;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/LeaksNotAccessibleUnexportedQualified/modulesourcepath/m1/qapi/QApi.java	Wed Jul 05 22:19:40 2017 +0200
@@ -0,0 +1,27 @@
+/*
+ * 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 qapi;
+
+public class QApi {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/LeaksNotAccessibleUnexportedQualified/modulesourcepath/m2/module-info.java	Wed Jul 05 22:19:40 2017 +0200
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+module m2 {
+     requires m1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/main/AtFileTest.java	Wed Jul 05 22:19:40 2017 +0200
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8166472 8162810
+ * @summary Align javac support for at-files with launcher support
+ * @modules jdk.compiler/com.sun.tools.javac.main
+ */
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import com.sun.tools.javac.main.CommandLine.Tokenizer;
+
+public class AtFileTest {
+
+    public static void main(String... args) throws IOException {
+        AtFileTest t = new AtFileTest();
+        if (args.length > 0) {
+            System.out.println(String.join(" ", args));
+        } else {
+            t.run();
+        }
+    }
+
+    void run() throws IOException {
+        test("-version -cp \"c:\\\\java libs\\\\one.jar\" \n",
+                "-version", "-cp", "c:\\java libs\\one.jar");
+
+        // note the open quote at the end
+        test("com.foo.Panda \"Furious 5\"\fand\t'Shi Fu' \"escape\tprison",
+                "com.foo.Panda", "Furious 5", "and", "Shi Fu", "escape\tprison");
+
+        test("escaped chars testing \"\\a\\b\\c\\f\\n\\r\\t\\v\\9\\6\\23\\82\\28\\377\\477\\278\\287\"",
+                "escaped", "chars", "testing", "abc\f\n\r\tv96238228377477278287");
+
+        test("\"mix 'single quote' in double\" 'mix \"double quote\" in single' partial\"quote me\"this",
+                "mix 'single quote' in double", "mix \"double quote\" in single", "partialquote methis");
+
+        test("line one #comment\n'line #2' #rest are comment\r\n#comment on line 3\nline 4 #comment to eof",
+                "line", "one", "line #2", "line", "4");
+
+        test("This is an \"open quote \n    across line\n\t, note for WS.",
+                "This", "is", "an", "open quote ", "across", "line", ",", "note", "for", "WS.");
+
+        test("Try \"this \\\\\\\\ escape\\n double quote \\\" in open quote",
+                "Try", "this \\\\ escape\n double quote \" in open quote");
+
+        test("'-Dmy.quote.single'='Property in single quote. Here a double quote\" Add some slashes \\\\/'",
+                "-Dmy.quote.single=Property in single quote. Here a double quote\" Add some slashes \\/");
+
+        test("\"Open quote to \n  new \"line \\\n\r   third\\\n\r\\\tand\ffourth\"",
+                "Open quote to ", "new", "line third\tand\ffourth");
+
+        test("c:\\\"partial quote\"\\lib",
+                "c:\\partial quote\\lib");
+    }
+
+    void test(String full, String... expect) throws IOException {
+        System.out.println("test: >>>" + full + "<<<");
+        List<String> found = expand(full);
+        if (found.equals(Arrays.asList(expect))) {
+            System.out.println("OK");
+        } else {
+            for (int i = 0; i < Math.max(found.size(), expect.length); i++) {
+                if (i < found.size()) {
+                    System.out.println("found[" + i + "]:  >>>" + found.get(i) + "<<<");
+                }
+                if (i < expect.length) {
+                    System.out.println("expect[" + i + "]: >>>" + expect[i] + "<<<");
+                }
+            }
+        }
+        System.out.println();
+    }
+
+    List<String> expand(String full) throws IOException {
+        Tokenizer t = new Tokenizer(new StringReader(full));
+        List<String> result = new ArrayList<>();
+        String s;
+        while ((s = t.nextToken()) != null) {
+//            System.err.println("token: " + s);
+            result.add(s);
+        }
+        return result;
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/main/ToolProviderTest.java	Wed Jul 05 22:19:40 2017 +0200
@@ -0,0 +1,132 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8159855
+ * @summary test javac's ToolProvider
+ * @library /tools/lib
+ * @build toolbox.TestRunner toolbox.ToolBox
+ * @run main ToolProviderTest
+ */
+
+import java.io.*;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.*;
+import java.util.spi.ToolProvider;
+
+import toolbox.TestRunner;
+import toolbox.ToolBox;
+
+public class ToolProviderTest extends TestRunner {
+    public static void main(String... args) throws Exception {
+        new ToolProviderTest().runTests();
+    }
+
+    ToolBox tb = new ToolBox();
+    ToolProvider javac;
+
+    ToolProviderTest() {
+        super(System.err);
+        javac = ToolProvider.findFirst("javac").get();
+    }
+
+    @Test
+    public void testProviders() throws Exception {
+        Map<String, ToolProvider> providers = new LinkedHashMap<>();
+        for (ToolProvider tp : ServiceLoader.load(ToolProvider.class,
+                ClassLoader.getSystemClassLoader())) {
+            System.out.println("Provider: " + tp.name() + ": " + tp.getClass().getName());
+            providers.put(tp.name(), tp);
+        }
+        if (!providers.containsKey("javac")) {
+            error("javac ToolProvider not found");
+        }
+    }
+
+    @Test
+    public void testOneStream() throws Exception {
+        StringWriter sw = new StringWriter();
+        try (PrintWriter pw = new PrintWriter(sw)) {
+            int rc = javac.run(pw, pw, "-help");
+            if (rc != 0) {
+                error("unexpected exit code: " + rc);
+            }
+        }
+        String out = sw.toString();
+        if (!out.contains("Usage:")) {
+            error("expected output not found");
+        }
+    }
+
+    @Test
+    public void testTwoStreamsOut() throws Exception {
+        StringWriter swOut = new StringWriter();
+        StringWriter swErr = new StringWriter();
+        try (PrintWriter pwOut = new PrintWriter(swOut);
+                PrintWriter pwErr = new PrintWriter(swErr)) {
+            int rc = javac.run(pwOut, pwErr, "-help");
+            if (rc != 0) {
+                error("unexpected exit code: " + rc);
+            }
+        }
+        String out = swOut.toString();
+        String err = swErr.toString();
+        if (!out.contains("Usage:")) {
+            error("stdout: expected output not found");
+        }
+        if (!err.isEmpty()) {
+            error("stderr: unexpected output");
+        }
+    }
+
+    @Test
+    public void testTwoStreamsErr() throws Exception {
+        Path src = Paths.get("src");
+        Path classes = Paths.get("classes");
+        tb.writeJavaFiles(src,
+            "import java.util.*; class C { # }");
+
+        StringWriter swOut = new StringWriter();
+        StringWriter swErr = new StringWriter();
+        try (PrintWriter pwOut = new PrintWriter(swOut);
+                PrintWriter pwErr = new PrintWriter(swErr)) {
+            int rc = javac.run(pwOut, pwErr,
+                "-d", classes.toString(),
+                src.resolve("C.java").toString());
+            if (rc != 1) {
+                error("unexpected exit code: " + rc);
+            }
+        }
+
+        String out = swOut.toString();
+        String err = swErr.toString();
+        if (!out.isEmpty()) {
+            error("stdout: unexpected output");
+        }
+        if (!err.contains("illegal character")) {
+            error("stderr: expected output not found");
+        }
+    }
+}
--- a/langtools/test/tools/javac/modules/AddLimitMods.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/tools/javac/modules/AddLimitMods.java	Wed Jul 05 22:19:40 2017 +0200
@@ -345,6 +345,7 @@
 
         Files.createDirectories(classpathOut);
 
+        System.err.println("Compiling classpath-src files:");
         new JavacTask(tb)
                 .outdir(classpathOut)
                 .files(findJavaFiles(classpathSrc))
@@ -360,6 +361,7 @@
 
         Files.createDirectories(automaticOut);
 
+        System.err.println("Compiling automatic-src files:");
         new JavacTask(tb)
                 .outdir(automaticOut)
                 .files(findJavaFiles(automaticSrc))
@@ -373,6 +375,7 @@
 
         Path automaticJar = modulePath.resolve("automatic.jar");
 
+        System.err.println("Creating automatic.jar:");
         new JarTask(tb, automaticJar)
           .baseDir(automaticOut)
           .files("automatic/Automatic.class")
@@ -385,6 +388,7 @@
                           "module m1 { exports api; }",
                           "package api; public class Api { public void test() { } }");
 
+        System.err.println("Compiling module-src files:");
         new JavacTask(tb)
                 .options("--module-source-path", moduleSrc.toString())
                 .outdir(modulePath)
@@ -399,7 +403,7 @@
             for (String[] options : OPTIONS_VARIANTS) {
                 index++;
 
-                System.err.println("running check: " + moduleInfo + "; " + Arrays.asList(options));
+                System.err.println("Running check: " + moduleInfo + "; " + Arrays.asList(options));
 
                 Path m2Runtime = base.resolve(index + "-runtime").resolve("m2");
                 Path out = base.resolve(index + "-runtime").resolve("out").resolve("m2");
@@ -427,6 +431,7 @@
 
                 tb.writeJavaFiles(m2Runtime, moduleInfo, testClassNamed.toString());
 
+                System.err.println("Compiling " + m2Runtime + " files:");
                 new JavacTask(tb)
                    .options("--module-path", modulePath.toString())
                    .outdir(out)
@@ -438,6 +443,7 @@
                 String output;
 
                 try {
+                    System.err.println("Running m2/test.Test:");
                     output = new JavaTask(tb)
                        .vmOptions(augmentOptions(options,
                                                  Collections.emptyList(),
@@ -468,6 +474,8 @@
                     "-Aoutput=" + output,
                     "-XDaccessInternalAPI=true"
                 ) : Collections.emptyList();
+
+                System.err.println("Compiling/processing m2 files:");
                 new JavacTask(tb)
                    .options(augmentOptions(options,
                                            auxOptions,
@@ -510,8 +518,6 @@
         MODULES_TO_CHECK_TO_SAMPLE_CLASS.put("m1", "api.Api");
         MODULES_TO_CHECK_TO_SAMPLE_CLASS.put("m2", "test.Test");
         MODULES_TO_CHECK_TO_SAMPLE_CLASS.put("java.base", "java.lang.Object");
-        MODULES_TO_CHECK_TO_SAMPLE_CLASS.put("java.compiler", "javax.tools.ToolProvider");
-        MODULES_TO_CHECK_TO_SAMPLE_CLASS.put("jdk.compiler", "com.sun.tools.javac.Main");
     };
 
     @SupportedAnnotationTypes("*")
@@ -573,8 +579,7 @@
 
     private static final String[] MODULE_INFO_VARIANTS = {
         "module m2 { exports test; }",
-        "module m2 { requires m1; exports test; }",
-        "module m2 { requires jdk.compiler; exports test; }",
+        "module m2 { requires m1; exports test; }"
     };
 
     private static final String[][] OPTIONS_VARIANTS = {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/modules/ExportsUnexported.java	Wed Jul 05 22:19:40 2017 +0200
@@ -0,0 +1,375 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @summary tests for module declarations
+ * @library /tools/lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ *          jdk.compiler/com.sun.tools.javac.main
+ * @build toolbox.ToolBox toolbox.JavacTask ModuleTestBase
+ * @run main ExportsUnexported
+ */
+
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import toolbox.JavacTask;
+import toolbox.Task;
+
+public class ExportsUnexported extends ModuleTestBase {
+
+    public static void main(String... args) throws Exception {
+        ExportsUnexported t = new ExportsUnexported();
+        t.runTests();
+    }
+
+    @Test
+    public void testLocations(Path base) throws Exception {
+        String warningsTest = "package api;\n" +
+                      "import impl.impl.*;\n" +
+                      "@impl.impl^.DocAnn\n" +
+                      "public abstract class Api<T extends impl.impl^.Cls&impl.impl^.Intf> extends impl.impl^.Cls implements impl.impl^.Intf, impl.impl^.NonDocAnn, impl.impl^.DocAnn {\n" +
+                      "    public static <E extends impl.impl^.Cls&impl.impl^.Intf> impl.impl^.Cls m(impl.impl^.Intf i, impl.impl^.Cls c) throws impl.impl^.Exc { return null; }\n" +
+                      "    public static impl.impl^.Cls f;\n" +
+                      "}";
+        String noWarningsTest = "package api;\n" +
+                      "import impl.impl.*;\n" +
+                      "@impl.impl.NonDocAnn\n" +
+                      "public abstract class Api {\n" +
+                      "    private static abstract class I <T extends impl.impl.Cls&impl.impl.Intf> extends impl.impl.Cls implements impl.impl.Intf, impl.impl.NonDocAnn, impl.impl.DocAnn {\n" +
+                      "        public static abstract class II <T extends impl.impl.Cls&impl.impl.Intf> extends impl.impl.Cls implements impl.impl.Intf, impl.impl.NonDocAnn, impl.impl.DocAnn { }\n" +
+                      "        public static <E extends impl.impl.Cls&impl.impl.Intf> impl.impl.Cls m(impl.impl.Intf i, impl.impl.Cls c) throws impl.impl.Exc { return null; }\n" +
+                      "        public static impl.impl.Cls f;\n" +
+                      "    }\n" +
+                      "    private static <E extends impl.impl.Cls&impl.impl.Intf> impl.impl.Cls m(impl.impl.Intf i, impl.impl.Cls c) throws impl.impl.Exc { return null; }\n" +
+                      "    private static impl.impl.Cls f1;\n" +
+                      "    public static void m() { new impl.impl.Cls(); }\n" +
+                      "    public static Object f2 = new impl.impl.Cls();\n" +
+                      "}";
+        for (String genericTest : new String[] {warningsTest, noWarningsTest}) {
+            for (String test : new String[] {genericTest, genericTest.replaceAll("impl\\.impl\\^.([A-Za-z])", "^$1").replaceAll("impl\\.impl\\.([A-Za-z])", "$1")}) {
+                System.err.println("testing: " + test);
+
+                Path src = base.resolve("src");
+                Path src_m1 = src.resolve("m1");
+                StringBuilder testCode = new StringBuilder();
+                List<String> expectedLog = new ArrayList<>();
+                int line = 1;
+                int col  = 1;
+
+                for (int i = 0; i < test.length(); i++) {
+                    char c = test.charAt(i);
+
+                    if (c == '^') {
+                        StringBuilder typeName = new StringBuilder();
+                        for (int j = i + 1 + (test.charAt(i + 1) == '.' ? 1 : 0);
+                             j < test.length() && Character.isJavaIdentifierPart(test.charAt(j));
+                             j++) {
+                            typeName.append(test.charAt(j));
+                        }
+                        String kindName;
+                        switch (typeName.toString()) {
+                            case "Exc": case "DocAnn": case "NonDocAnn":
+                            case "Cls": kindName = "kindname.class"; break;
+                            case "Intf": kindName = "kindname.interface"; break;
+                            default:
+                                throw new AssertionError(typeName.toString());
+                        }
+                        expectedLog.add("Api.java:" + line + ":" + col + ": compiler.warn.leaks.not.accessible.unexported: " + kindName + ", impl.impl." + typeName + ", m1");
+                        continue;
+                    }
+
+                    if (c == '\n') {
+                        line++;
+                        col = 0;
+                    }
+
+                    testCode.append(c);
+                    col++;
+                }
+
+                if (!expectedLog.isEmpty()) {
+                    expectedLog.add("" + expectedLog.size() + " warning" + (expectedLog.size() == 1 ? "" : "s"));
+                    expectedLog.add("- compiler.err.warnings.and.werror");
+                    expectedLog.add("1 error");
+                }
+
+                Collections.sort(expectedLog);
+
+                tb.writeJavaFiles(src_m1,
+                                  "module m1 { exports api; }",
+                                  testCode.toString(),
+                                  "package impl.impl; public class Cls { }",
+                                  "package impl.impl; public class Exc extends Exception { }",
+                                  "package impl.impl; public interface Intf { }",
+                                  "package impl.impl; @java.lang.annotation.Documented public @interface DocAnn { }",
+                                  "package impl.impl; public @interface NonDocAnn { }");
+                Path classes = base.resolve("classes");
+                tb.createDirectories(classes);
+
+                List<String> log = new JavacTask(tb)
+                        .options("-XDrawDiagnostics",
+                                 "-Werror",
+                                 "--module-source-path", src.toString(),
+                                 "-Xlint:exports")
+                        .outdir(classes)
+                        .files(findJavaFiles(src))
+                        .run(expectedLog.isEmpty() ? Task.Expect.SUCCESS : Task.Expect.FAIL)
+                        .writeAll()
+                        .getOutputLines(Task.OutputKind.DIRECT);
+
+                log = new ArrayList<>(log);
+                Collections.sort(log);
+
+                if (expectedLog.isEmpty() ? !log.equals(Arrays.asList("")) : !log.equals(expectedLog)) {
+                    throw new Exception("expected output not found in: " + log + "; " + expectedLog);
+                }
+            }
+        }
+    }
+
+    @Test
+    public void testAccessibleToSpecificOrAll(Path base) throws Exception {
+        Path src = base.resolve("src");
+        Path src_lib1 = src.resolve("lib1");
+        tb.writeJavaFiles(src_lib1,
+                          "module lib1 { exports lib1; }",
+                          "package lib1; public class Lib1 {}");
+        Path src_lib2 = src.resolve("lib2");
+        tb.writeJavaFiles(src_lib2,
+                          "module lib2 { exports lib2; }",
+                          "package lib2; public class Lib2 {}");
+        Path src_api = src.resolve("api");
+        tb.writeJavaFiles(src_api,
+                          "module api {\n" +
+                          "    exports api;\n" +
+                          "    exports qapi1 to qual1;\n" +
+                          "    exports qapi2 to qual1, qual2;\n" +
+                          "    requires public lib1;\n" +
+                          "    requires lib2;\n" +
+                          "}\n",
+                          "package api;\n" +
+                          "public class Api {\n" +
+                          "    public lib1.Lib1 lib1;\n" +
+                          "    public lib2.Lib2 lib2;\n" +
+                          "    public qapi1.QApi1 qapi1;\n" +
+                          "    public impl.Impl impl;\n" +
+                          "}",
+                          "package qapi1;\n" +
+                          "public class QApi1 {\n" +
+                          "    public qapi2.QApi2 qapi2;\n" +
+                          "}",
+                          "package qapi2;\n" +
+                          "public class QApi2 {\n" +
+                          "    public qapi1.QApi1 qapi1;\n" +
+                          "}",
+                          "package impl;\n" +
+                          "public class Impl {\n" +
+                          "}");
+        Path src_qual1 = src.resolve("qual1");
+        tb.writeJavaFiles(src_qual1, "module qual1 { }");
+        Path src_qual2 = src.resolve("qual2");
+        tb.writeJavaFiles(src_qual2, "module qual2 { }");
+        Path classes = base.resolve("classes");
+        tb.createDirectories(classes);
+
+        List<String> log = new JavacTask(tb)
+                .options("-XDrawDiagnostics",
+                         "-Werror",
+                         "--module-source-path", src.toString(),
+                         "-Xlint:exports")
+                .outdir(classes)
+                .files(findJavaFiles(src))
+                .run(Task.Expect.FAIL)
+                .writeAll()
+                .getOutputLines(Task.OutputKind.DIRECT);
+
+        List<String> expected = Arrays.asList(
+            "Api.java:4:16: compiler.warn.leaks.not.accessible.not.required.public: kindname.class, lib2.Lib2, lib2",
+            "Api.java:5:17: compiler.warn.leaks.not.accessible.unexported.qualified: kindname.class, qapi1.QApi1, api",
+            "Api.java:6:16: compiler.warn.leaks.not.accessible.unexported: kindname.class, impl.Impl, api",
+            "- compiler.err.warnings.and.werror",
+            "1 error",
+            "3 warnings"
+        );
+
+        if (!log.equals(expected))
+            throw new Exception("expected output not found");
+    }
+
+    @Test
+    public void testNestedClasses(Path base) throws Exception {
+        Path src = base.resolve("src");
+        Path src_api = src.resolve("api");
+        tb.writeJavaFiles(src_api,
+                          "module api {\n" +
+                          "    exports api;\n" +
+                          "}\n",
+                          "package api;\n" +
+                          "import impl.Impl.Nested;\n" +
+                          "public class Api {\n" +
+                          "    public impl.Impl impl1;\n" +
+                          "    public impl.Impl.Nested impl2;\n" +
+                          "    public Nested impl3;\n" +
+                          "}",
+                          "package impl;\n" +
+                          "public class Impl {\n" +
+                          "    public static class Nested {\n" +
+                          "    }\n" +
+                          "}");
+        Path classes = base.resolve("classes");
+        tb.createDirectories(classes);
+
+        List<String> log = new JavacTask(tb)
+                .options("-XDrawDiagnostics",
+                         "-Werror",
+                         "--module-source-path", src.toString(),
+                         "-Xlint:exports")
+                .outdir(classes)
+                .files(findJavaFiles(src))
+                .run(Task.Expect.FAIL)
+                .writeAll()
+                .getOutputLines(Task.OutputKind.DIRECT);
+
+        List<String> expected = Arrays.asList(
+            "Api.java:4:16: compiler.warn.leaks.not.accessible.unexported: kindname.class, impl.Impl, api",
+            "Api.java:5:16: compiler.warn.leaks.not.accessible.unexported: kindname.class, impl.Impl, api",
+            "Api.java:6:12: compiler.warn.leaks.not.accessible.unexported: kindname.class, impl.Impl.Nested, api",
+            "- compiler.err.warnings.and.werror",
+            "1 error",
+            "3 warnings"
+        );
+
+        if (!log.equals(expected))
+            throw new Exception("expected output not found");
+    }
+
+    @Test
+    public void testProtectedAndInaccessible(Path base) throws Exception {
+        Path src = base.resolve("src");
+        Path src_api = src.resolve("api");
+        tb.writeJavaFiles(src_api,
+                          "module api {\n" +
+                          "    exports api;\n" +
+                          "}\n",
+                          "package api;\n" +
+                          "public class Api extends PackagePrivateClass<PackagePrivateInterface> implements PackagePrivateInterface<PackagePrivateClass> {\n" +
+                          "    protected PackagePrivateClass<?> f1;\n" +
+                          "    protected PackagePrivateInterface<?> f2;\n" +
+                          "    protected Inner f3;\n" +
+                          "    protected PrivateInner f4;\n" +
+                          "    protected impl.Impl f5;\n" +
+                          "    public static class InnerClass extends PrivateInner {}\n" +
+                          "    protected static class Inner {}\n" +
+                          "    private static class PrivateInner {}\n" +
+                          "}\n" +
+                          "class PackagePrivateClass<T> {}\n" +
+                          "interface PackagePrivateInterface<T> {}",
+                          "package impl;\n" +
+                          "public class Impl {\n" +
+                          "}");
+        Path classes = base.resolve("classes");
+        tb.createDirectories(classes);
+
+        List<String> log = new JavacTask(tb)
+                .options("-XDrawDiagnostics",
+                         "-Werror",
+                         "--module-source-path", src.toString(),
+                         "-Xlint:exports")
+                .outdir(classes)
+                .files(findJavaFiles(src))
+                .run(Task.Expect.FAIL)
+                .writeAll()
+                .getOutputLines(Task.OutputKind.DIRECT);
+
+        List<String> expected = Arrays.asList(
+            "Api.java:2:46: compiler.warn.leaks.not.accessible: kindname.interface, api.PackagePrivateInterface, api",
+            "Api.java:2:106: compiler.warn.leaks.not.accessible: kindname.class, api.PackagePrivateClass, api",
+            "Api.java:3:15: compiler.warn.leaks.not.accessible: kindname.class, api.PackagePrivateClass, api",
+            "Api.java:4:15: compiler.warn.leaks.not.accessible: kindname.interface, api.PackagePrivateInterface, api",
+            "Api.java:6:15: compiler.warn.leaks.not.accessible: kindname.class, api.Api.PrivateInner, api",
+            "Api.java:7:19: compiler.warn.leaks.not.accessible.unexported: kindname.class, impl.Impl, api",
+            "- compiler.err.warnings.and.werror",
+            "1 error",
+            "6 warnings"
+        );
+
+        if (!log.equals(expected))
+            throw new Exception("expected output not found");
+    }
+
+    @Test
+    public void testSuppressResetProperly(Path base) throws Exception {
+        Path src = base.resolve("src");
+        Path src_api = src.resolve("api");
+        tb.writeJavaFiles(src_api,
+                          "module api {\n" +
+                          "    exports api;\n" +
+                          "}\n",
+                          "package api;\n" +
+                          "public class Api {\n" +
+                          "    @SuppressWarnings(\"exports\")\n" +
+                          "    public PackagePrivateClass f1;\n" +
+                          "    public PackagePrivateClass f2;\n" +
+                          "    @SuppressWarnings(\"exports\")\n" +
+                          "    public void t() {}\n" +
+                          "    public PackagePrivateClass f3;\n" +
+                          "    @SuppressWarnings(\"exports\")\n" +
+                          "    public static class C {\n" +
+                          "        public PackagePrivateClass f4;\n" +
+                          "    }\n" +
+                          "    public PackagePrivateClass f5;\n" +
+                          "}\n" +
+                          "class PackagePrivateClass<T> {}\n");
+        Path classes = base.resolve("classes");
+        tb.createDirectories(classes);
+
+        List<String> log = new JavacTask(tb)
+                .options("-XDrawDiagnostics",
+                         "-Werror",
+                         "--module-source-path", src.toString(),
+                         "-Xlint:exports")
+                .outdir(classes)
+                .files(findJavaFiles(src))
+                .run(Task.Expect.FAIL)
+                .writeAll()
+                .getOutputLines(Task.OutputKind.DIRECT);
+
+        List<String> expected = Arrays.asList(
+            "Api.java:5:12: compiler.warn.leaks.not.accessible: kindname.class, api.PackagePrivateClass, api",
+            "Api.java:8:12: compiler.warn.leaks.not.accessible: kindname.class, api.PackagePrivateClass, api",
+            "Api.java:13:12: compiler.warn.leaks.not.accessible: kindname.class, api.PackagePrivateClass, api",
+            "- compiler.err.warnings.and.werror",
+            "1 error",
+            "3 warnings"
+        );
+
+        if (!log.equals(expected))
+            throw new Exception("expected output not found");
+    }
+
+}
--- a/langtools/test/tools/jdeprscan/tests/jdk/jdeprscan/TestScan.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/tools/jdeprscan/tests/jdk/jdeprscan/TestScan.java	Wed Jul 05 22:19:40 2017 +0200
@@ -74,7 +74,7 @@
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         try (PrintStream out = new PrintStream(baos, false, "UTF-8")) {
             boolean r = Main.call(out, System.err,
-                "-cp", deprcases, "--Xload-dir", deprcases, deprusage);
+                "--class-path", deprcases, "--Xload-dir", deprcases, deprusage);
             assertTrue(r);
         }
         byte[] bytes = baos.toByteArray();
--- a/langtools/test/tools/jdeps/jdkinternals/RemovedJDKInternals.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/tools/jdeps/jdkinternals/RemovedJDKInternals.java	Wed Jul 05 22:19:40 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 8153042
  * @summary Tests JDK internal APIs that have been removed.
  * @library ../lib
- * @build CompilerUtils JdepsUtil ModuleMetaData
+ * @build CompilerUtils JdepsRunner JdepsUtil ModuleMetaData
  * @modules jdk.jdeps/com.sun.tools.jdeps
  * @run testng RemovedJDKInternals
  */
@@ -123,7 +123,8 @@
 
     @Test
     public void checkReplacement() {
-        String[] output = JdepsUtil.jdeps("-jdkinternals", CLASSES_DIR.toString());
+        JdepsRunner jdeps = JdepsRunner.run("-jdkinternals", CLASSES_DIR.toString());
+        String[] output = jdeps.output();
         int i = 0;
         while (!output[i].contains("Suggested Replacement")) {
             i++;
--- a/langtools/test/tools/jdeps/jdkinternals/ShowReplacement.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/tools/jdeps/jdkinternals/ShowReplacement.java	Wed Jul 05 22:19:40 2017 +0200
@@ -70,7 +70,8 @@
     @Test
     public void withReplacement() {
         Path file = Paths.get("q", "WithRepl.class");
-        String[] output = JdepsUtil.jdeps("-jdkinternals", CLASSES_DIR.resolve(file).toString());
+        JdepsRunner jdeps = JdepsRunner.run("-jdkinternals", CLASSES_DIR.resolve(file).toString());
+        String[] output = jdeps.output();
         int i = 0;
         while (!output[i].contains("Suggested Replacement")) {
             i++;
@@ -99,7 +100,8 @@
     @Test
     public void noReplacement() {
         Path file = Paths.get("q", "NoRepl.class");
-        String[] output = JdepsUtil.jdeps("-jdkinternals", CLASSES_DIR.resolve(file).toString());
+        JdepsRunner jdeps = JdepsRunner.run("-jdkinternals", CLASSES_DIR.resolve(file).toString());
+        String[] output = jdeps.output();
         int i = 0;
         // expect no replacement
         while (i < output.length && !output[i].contains("Suggested Replacement")) {
@@ -116,7 +118,8 @@
     @Test
     public void removedPackage() {
         Path file = Paths.get("q", "RemovedPackage.class");
-        String[] output = JdepsUtil.jdeps("--jdk-internals", CLASSES_DIR.resolve(file).toString());
+        JdepsRunner jdeps = JdepsRunner.run("--jdk-internals", CLASSES_DIR.resolve(file).toString());
+        String[] output = jdeps.output();
         int i = 0;
         // expect no replacement
         while (i < output.length && !output[i].contains("Suggested Replacement")) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/jdeps/lib/JdepsRunner.java	Wed Jul 05 22:19:40 2017 +0200
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * JdepsRunner class to invoke jdeps with the given command line argument
+ */
+public class JdepsRunner {
+    public static JdepsRunner run(String... args) {
+        JdepsRunner jdeps = new JdepsRunner(args);
+        int rc = jdeps.run();
+        jdeps.printStdout(System.err);
+        if (rc != 0)
+           throw new Error("jdeps failed: rc=" + rc);
+        return jdeps;
+    }
+
+    final StringWriter stdout = new StringWriter();
+    final StringWriter stderr = new StringWriter();
+    final String[] args;
+    public JdepsRunner(String... args) {
+        System.err.println("jdeps " + Arrays.stream(args)
+                                            .collect(Collectors.joining(" ")));
+        this.args = args;
+    }
+
+    public JdepsRunner(List<String> args) {
+        this(args.toArray(new String[0]));
+    }
+
+    public int run() {
+        return run(false);
+    }
+
+    public int run(boolean showOutput) {
+        try (PrintWriter pw = new PrintWriter(stdout)) {
+            int rc = com.sun.tools.jdeps.Main.run(args, pw);
+            if (showOutput) {
+                System.err.println(stdout.toString());
+            }
+            return rc;
+        }
+    }
+
+    public boolean outputContains(String s) {
+        return stdout.toString().contains(s);
+    }
+
+    public void printStdout(PrintStream stream) {
+        stream.println(stdout.toString());
+    }
+
+    public void printStderr(PrintStream stream) {
+        stream.println(stderr.toString());
+    }
+
+    public String[] output() {
+        String lineSep = System.getProperty("line.separator");
+        return stdout.toString().split(lineSep);
+    }
+}
--- a/langtools/test/tools/jdeps/lib/JdepsUtil.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/tools/jdeps/lib/JdepsUtil.java	Wed Jul 05 22:19:40 2017 +0200
@@ -39,37 +39,17 @@
 import java.lang.module.ModuleDescriptor;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Set;
 import java.util.jar.JarEntry;
 import java.util.jar.JarOutputStream;
 import java.util.regex.Pattern;
-import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 /**
  * Utilities to run jdeps command
  */
 public final class JdepsUtil {
-    /*
-     * Runs jdeps with the given arguments
-     */
-    public static String[] jdeps(String... args) {
-        String lineSep =     System.getProperty("line.separator");
-        StringWriter sw = new StringWriter();
-        PrintWriter pw = new PrintWriter(sw);
-        System.err.println("jdeps " + Arrays.stream(args).collect(Collectors.joining(" ")));
-        int rc = com.sun.tools.jdeps.Main.run(args, pw);
-        pw.close();
-        String out = sw.toString();
-        if (!out.isEmpty())
-            System.err.println(out);
-        if (rc != 0)
-            throw new Error("jdeps failed: rc=" + rc);
-        return out.split(lineSep);
-    }
-
     public static Command newCommand(String cmd) {
         return new Command(cmd);
     }
--- a/langtools/test/tools/jdeps/modules/GenModuleInfo.java	Wed Jul 05 22:19:30 2017 +0200
+++ b/langtools/test/tools/jdeps/modules/GenModuleInfo.java	Wed Jul 05 22:19:40 2017 +0200
@@ -25,7 +25,7 @@
  * @test
  * @summary Tests jdeps --generate-module-info option
  * @library ../lib
- * @build CompilerUtils JdepsUtil
+ * @build CompilerUtils JdepsUtil JdepsRunner
  * @modules jdk.jdeps/com.sun.tools.jdeps
  * @run testng GenModuleInfo
  */
@@ -97,7 +97,7 @@
         Stream<String> files = Arrays.stream(modules)
                 .map(mn -> LIBS_DIR.resolve(mn + ".jar"))
                 .map(Path::toString);
-        JdepsUtil.jdeps(Stream.concat(Stream.of("-cp"), files).toArray(String[]::new));
+        JdepsRunner.run(Stream.concat(Stream.of("-cp"), files).toArray(String[]::new));
     }
 
     @Test
@@ -106,7 +106,7 @@
                 .map(mn -> LIBS_DIR.resolve(mn + ".jar"))
                 .map(Path::toString);
 
-        JdepsUtil.jdeps(Stream.concat(Stream.of("--generate-module-info", DEST_DIR.toString()),
+        JdepsRunner.run(Stream.concat(Stream.of("--generate-module-info", DEST_DIR.toString()),
                                       files).toArray(String[]::new));
 
         // check file exists
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/jdeps/modules/UnnamedPackage.java	Wed Jul 05 22:19:40 2017 +0200
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8166846
+ * @summary Tests --generate-module-info on invalid JAR file
+ * @modules jdk.jdeps/com.sun.tools.jdeps
+ * @library ../lib
+ * @build JdepsRunner JdepsUtil
+ * @run main UnnamedPackage
+ */
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.stream.Stream;
+
+public class UnnamedPackage {
+    private static final Path TEST_CLASSES = Paths.get(System.getProperty("test.classes"));
+    private static final Path FOO_JAR_FILE = Paths.get("foo.jar");
+
+    public static void main(String... args) throws Exception {
+        // create foo.jar with unnamed package
+        Path name = TEST_CLASSES.resolve("UnnamedPackage.class");
+        JdepsUtil.createJar(FOO_JAR_FILE, TEST_CLASSES, Stream.of(name));
+
+        // run jdeps --generate-module-info
+        JdepsRunner jdeps = new JdepsRunner("--generate-module-info",
+                                            "tmp", FOO_JAR_FILE.toString());
+        // should fail to generate module-info.java
+        int exitValue = jdeps.run();
+        if (exitValue == 0) {
+            throw new RuntimeException("expected non-zero exitValue");
+        }
+        if (!jdeps.outputContains("foo.jar contains an unnamed package")) {
+            jdeps.printStdout(System.out);
+            throw new RuntimeException("expected error message not found");
+        }
+    }
+}