Merge
authorjwilhelm
Thu, 30 Mar 2017 19:55:04 +0200
changeset 44428 e8db842f5496
parent 44427 a053dcc2d986 (current diff)
parent 44420 ae0000fbbb2c (diff)
child 44429 80c86e1a6c1b
Merge
--- a/jdk/.hgtags	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/.hgtags	Thu Mar 30 19:55:04 2017 +0200
@@ -405,3 +405,4 @@
 cac788454598b95d8b0153c021a7fae3cd7e6fda jdk-9+160
 09b92d3067a38ee07bc14efa336b14790c93f7e7 jdk-9+161
 f6bf027e88e9a4dd19f721001a7af00157af42c4 jdk-9+162
+50171f8c47961710cbf87aead6f03fa431d8d240 jdk-9+163
--- a/jdk/make/GenerateModuleSummary.gmk	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/make/GenerateModuleSummary.gmk	Thu Mar 30 19:55:04 2017 +0200
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -31,7 +31,7 @@
 include ModuleTools.gmk
 
 GENGRAPHS_DIR := $(IMAGES_OUTPUTDIR)/gengraphs
-SPEC_DOTFILES_DIR := $(IMAGES_OUTPUTDIR)/spec-dotfiles
+SPEC_DOTFILES_DIR := $(GENGRAPHS_DIR)/spec-dotfiles
 TOOLS_MODULE_SRCDIR := $(JDK_TOPDIR)/make/src/classes/build/tools/jigsaw
 
 $(GENGRAPHS_DIR)/jdk.dot: $(BUILD_JIGSAW_TOOLS)
--- a/jdk/make/ModuleTools.gmk	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/make/ModuleTools.gmk	Thu Mar 30 19:55:04 2017 +0200
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -23,8 +23,9 @@
 # questions.
 #
 
-include $(SPEC)
-include MakeBase.gmk
+ifndef _MODULE_TOOLS_GMK
+_MODULE_TOOLS_GMK := 1
+
 include JavaCompilation.gmk
 
 TOOLS_CLASSES_DIR := $(BUILDTOOLS_OUTPUTDIR)/tools_jigsaw_classes
@@ -32,7 +33,7 @@
 # To avoid reevaluating the compilation setup for the tools each time this file
 # is included, the actual compilation is handled by CompileModuleTools.gmk. The
 # following trick is used to be able to declare a dependency on the built tools.
-BUILD_TOOLS_JDK := $(call SetupJavaCompilationCompileTarget, \
+BUILD_JIGSAW_TOOLS := $(call SetupJavaCompilationCompileTarget, \
     BUILD_JIGSAW_TOOLS, $(TOOLS_CLASSES_DIR))
 
 TOOL_GENGRAPHS := $(BUILD_JAVA) -esa -ea -cp $(TOOLS_CLASSES_DIR) \
@@ -47,3 +48,5 @@
     -cp $(TOOLS_CLASSES_DIR) \
     --add-exports java.base/jdk.internal.module=ALL-UNNAMED \
     build.tools.jigsaw.AddPackagesAttribute
+
+endif # _MODULE_TOOLS_GMK
--- a/jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java	Thu Mar 30 19:55:04 2017 +0200
@@ -26,7 +26,6 @@
 package build.tools.jigsaw;
 
 import com.sun.tools.jdeps.ModuleDotGraph;
-import com.sun.tools.jdeps.ModuleDotGraph.DotGraphBuilder;
 
 import java.io.IOException;
 import java.lang.module.Configuration;
@@ -36,10 +35,15 @@
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
+import java.util.Properties;
 import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 
 /**
  * Generate the DOT file for a module graph for each module in the JDK
@@ -50,13 +54,19 @@
     public static void main(String[] args) throws Exception {
         Path dir = null;
         boolean spec = false;
+        Properties props = null;
         for (int i=0; i < args.length; i++) {
             String arg = args[i];
             if (arg.equals("--spec")) {
                 spec = true;
+            } else if (arg.equals("--dot-attributes")) {
+                if (i++ == args.length) {
+                    throw new IllegalArgumentException("Missing argument: --dot-attributes option");
+                }
+                props = new Properties();
+                props.load(Files.newInputStream(Paths.get(args[i])));
             } else if (arg.equals("--output")) {
-                i++;
-                dir = i < args.length ? Paths.get(args[i]) : null;
+                dir = ++i < args.length ? Paths.get(args[i]) : null;
             } else if (arg.startsWith("-")) {
                 throw new IllegalArgumentException("Invalid option: " + arg);
             }
@@ -67,11 +77,14 @@
             System.exit(1);
         }
 
-        // setup and configure the dot graph attributes
-        initDotGraphAttributes();
         Files.createDirectories(dir);
-
-        GenGraphs genGraphs = new GenGraphs(dir, spec);
+        ModuleGraphAttributes attributes;
+        if (props != null) {
+            attributes = new ModuleGraphAttributes(props);
+        } else {
+            attributes = new ModuleGraphAttributes();
+        }
+        GenGraphs genGraphs = new GenGraphs(dir, spec, attributes);
 
         // print dot file for each module
         Map<String, Configuration> configurations = new HashMap<>();
@@ -99,49 +112,149 @@
         genGraphs.genDotFiles(configurations);
     }
 
-    static void initDotGraphAttributes() {
-        int h = 1000;
-        DotGraphBuilder.weight("java.se", "java.sql.rowset", h * 10);
-        DotGraphBuilder.weight("java.sql.rowset", "java.sql", h * 10);
-        DotGraphBuilder.weight("java.sql", "java.xml", h * 10);
-        DotGraphBuilder.weight("java.xml", "java.base", h * 10);
+    /**
+     * Custom dot file attributes.
+     */
+    static class ModuleGraphAttributes implements ModuleDotGraph.Attributes {
+        static Map<String, String> DEFAULT_ATTRIBUTES = Map.of(
+            "ranksep", "0.6",
+            "fontsize", "12",
+            "fontcolor", BLACK,
+            "fontname", "DejaVuSans",
+            "arrowsize", "1",
+            "arrowwidth", "2",
+            "arrowcolor", DARK_GRAY,
+            // custom
+            "requiresMandatedColor", LIGHT_GRAY,
+            "javaSubgraphColor", ORANGE,
+            "jdkSubgraphColor", BLUE
+        );
+
+        final Map<String, Integer> weights = new HashMap<>();
+        final List<Set<String>> ranks = new ArrayList<>();
+        final Map<String, String> attrs;
+        ModuleGraphAttributes(Map<String, String> attrs) {
+            int h = 1000;
+            weight("java.se", "java.sql.rowset", h * 10);
+            weight("java.sql.rowset", "java.sql", h * 10);
+            weight("java.sql", "java.xml", h * 10);
+            weight("java.xml", "java.base", h * 10);
+
+            ranks.add(Set.of("java.logging", "java.scripting", "java.xml"));
+            ranks.add(Set.of("java.sql"));
+            ranks.add(Set.of("java.compiler", "java.instrument"));
+            ranks.add(Set.of("java.desktop", "java.management"));
+            ranks.add(Set.of("java.corba", "java.xml.ws"));
+            ranks.add(Set.of("java.xml.bind", "java.xml.ws.annotation"));
+
+            this.attrs = attrs;
+        }
+
+        ModuleGraphAttributes() {
+            this(DEFAULT_ATTRIBUTES);
+        }
+        ModuleGraphAttributes(Properties props) {
+            this(toAttributes(props));
+        }
+
+        @Override
+        public double rankSep() {
+            return Double.valueOf(attrs.get("ranksep"));
+        }
+
+        @Override
+        public int fontSize() {
+            return Integer.valueOf(attrs.get("fontsize"));
+        }
+
+        @Override
+        public String fontName() {
+            return attrs.get("fontname");
+        }
 
-        DotGraphBuilder.sameRankNodes(Set.of("java.logging", "java.scripting", "java.xml"));
-        DotGraphBuilder.sameRankNodes(Set.of("java.sql"));
-        DotGraphBuilder.sameRankNodes(Set.of("java.compiler", "java.instrument"));
-        DotGraphBuilder.sameRankNodes(Set.of("java.desktop", "java.management"));
-        DotGraphBuilder.sameRankNodes(Set.of("java.corba", "java.xml.ws"));
-        DotGraphBuilder.sameRankNodes(Set.of("java.xml.bind", "java.xml.ws.annotation"));
-        DotGraphBuilder.setRankSep(0.7);
-        DotGraphBuilder.setFontSize(12);
-        DotGraphBuilder.setArrowSize(1);
-        DotGraphBuilder.setArrowWidth(2);
+        @Override
+        public String fontColor() {
+            return attrs.get("fontcolor");
+        }
+
+        @Override
+        public int arrowSize() {
+            return Integer.valueOf(attrs.get("arrowsize"));
+        }
+
+        @Override
+        public int arrowWidth() {
+            return Integer.valueOf(attrs.get("arrowwidth"));
+        }
+
+        @Override
+        public String arrowColor() {
+            return attrs.get("arrowcolor");
+        }
+
+        @Override
+        public List<Set<String>> ranks() {
+            return ranks;
+        }
+
+        @Override
+        public String requiresMandatedColor() {
+            return attrs.get("requiresMandatedColor");
+        }
+
+        @Override
+        public String javaSubgraphColor() {
+            return attrs.get("javaSubgraphColor");
+        }
+
+        @Override
+        public String jdkSubgraphColor() {
+            return attrs.get("jdkSubgraphColor");
+        }
+
+        @Override
+        public int weightOf(String s, String t) {
+            int w = weights.getOrDefault(s + ":" + t, 1);
+            if (w != 1)
+                return w;
+            if (s.startsWith("java.") && t.startsWith("java."))
+                return 10;
+            return 1;
+        }
+
+        public void weight(String s, String t, int w) {
+            weights.put(s + ":" + t, w);
+        }
+
+        static Map<String, String> toAttributes(Properties props) {
+            return DEFAULT_ATTRIBUTES.keySet().stream()
+                .collect(Collectors.toMap(Function.identity(),
+                    k -> props.getProperty(k, DEFAULT_ATTRIBUTES.get(k))));
+        }
     }
 
     private final Path dir;
     private final boolean spec;
-    GenGraphs(Path dir, boolean spec) {
+    private final ModuleGraphAttributes attributes;
+    GenGraphs(Path dir, boolean spec, ModuleGraphAttributes attributes) {
         this.dir = dir;
         this.spec = spec;
+        this.attributes = attributes;
     }
 
     void genDotFiles(Map<String, Configuration> configurations) throws IOException {
         ModuleDotGraph dotGraph = new ModuleDotGraph(configurations, spec);
-        dotGraph.genDotFiles(dir);
+        dotGraph.genDotFiles(dir, attributes);
     }
 
+    /**
+     * Returns true for any name if generating graph for non-spec;
+     * otherwise, returns true except "jdk" and name with "jdk.internal." prefix
+     */
     boolean accept(String name, ModuleDescriptor descriptor) {
-        if (!spec) return true;
-
-        if (name.equals("jdk"))
-            return false;
-
-        if (name.equals("java.se") || name.equals("java.se.ee"))
+        if (!spec)
             return true;
 
-        // only the module that has exported API
-        return descriptor.exports().stream()
-                         .filter(e -> !e.isQualified())
-                         .findAny().isPresent();
+        return !name.equals("jdk") && !name.startsWith("jdk.internal.");
     }
-}
\ No newline at end of file
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/src/classes/build/tools/jigsaw/javadoc-graphs.properties	Thu Mar 30 19:55:04 2017 +0200
@@ -0,0 +1,2 @@
+arrowcolor=#999999
+requiresMandatedColor=#999999
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/src/classes/build/tools/taglet/ModuleGraph.java	Thu Mar 30 19:55:04 2017 +0200
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 build.tools.taglet;
+
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Set;
+import javax.lang.model.element.Element;
+import com.sun.source.doctree.DocTree;
+import jdk.javadoc.doclet.Taglet;
+import static jdk.javadoc.doclet.Taglet.Location.*;
+
+/**
+ * A block tag to optionally insert a reference to a module graph.
+ */
+public class ModuleGraph implements Taglet {
+    private static final boolean enableModuleGraph =
+        Boolean.getBoolean("enableModuleGraph");
+
+    /** Returns the set of locations in which a taglet may be used. */
+    @Override
+    public Set<Location> getAllowedLocations() {
+        return EnumSet.of(MODULE);
+    }
+
+    @Override
+    public boolean isInlineTag() {
+        return false;
+    }
+
+    @Override
+    public String getName() {
+        return "moduleGraph";
+    }
+
+    @Override
+    public String toString(List<? extends DocTree> tags, Element element) {
+        if (!enableModuleGraph) {
+            return "";
+        }
+
+        String moduleName = element.getSimpleName().toString();
+        String imageFile = moduleName + "-graph.png";
+        int thumbnailHeight = -1;
+        String hoverImage = "";
+        if (!moduleName.equals("java.base")) {
+            thumbnailHeight = 100; // also appears in the stylesheet
+            hoverImage = "<span>"
+                + getImage(moduleName, imageFile, -1, true)
+                + "</span>";
+        }
+        return "<dt>"
+            + "<span class=\"simpleTagLabel\">Module Graph:</span>\n"
+            + "</dt>"
+            + "<dd>"
+            + "<a class=moduleGraph href=\"" + imageFile + "\">"
+            + getImage(moduleName, imageFile, thumbnailHeight, false)
+            + hoverImage
+            + "</a>"
+            + "</dd>";
+    }
+
+    private static final String VERTICAL_ALIGN = "vertical-align:top";
+    private static final String BORDER = "border: solid lightgray 1px;";
+
+    private String getImage(String moduleName, String file, int height, boolean useBorder) {
+        return String.format("<img style=\"%s\" alt=\"Module graph for %s\" src=\"%s\"%s>",
+                             useBorder ? BORDER + " " + VERTICAL_ALIGN : VERTICAL_ALIGN,
+                             moduleName,
+                             file,
+                             (height <= 0 ? "" : " height=\"" + height + "\""));
+    }
+}
--- a/jdk/src/java.base/share/classes/java/lang/String.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/String.java	Thu Mar 30 19:55:04 2017 +0200
@@ -2672,7 +2672,6 @@
      * point</a> is passed through uninterpreted.
      *
      * @return an IntStream of char values from this sequence
-     * @since 9
      */
     @Override
     public IntStream chars() {
@@ -2692,7 +2691,6 @@
      * {@code int} values which are then passed to the stream.
      *
      * @return an IntStream of Unicode code points from this sequence
-     * @since 9
      */
     @Override
     public IntStream codePoints() {
--- a/jdk/src/java.base/share/classes/java/lang/System.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/System.java	Thu Mar 30 19:55:04 2017 +0200
@@ -1568,6 +1568,14 @@
      * obtained by calling {@link LoggerFinder#getLogger(java.lang.String,
      * java.lang.reflect.Module) LoggerFinder.getLogger(name, module)}, where
      * {@code module} is the caller's module.
+     * In cases where {@code System.getLogger} is called from a context where
+     * there is no caller frame on the stack (e.g when called directly
+     * from a JNI attached thread), {@code IllegalCallerException} is thrown.
+     * To obtain a logger in such a context, use an auxiliary class that will
+     * implicitly be identified as the caller, or use the system {@link
+     * LoggerFinder#getLoggerFinder() LoggerFinder} to obtain a logger instead.
+     * Note that doing the latter may eagerly initialize the underlying
+     * logging system.
      *
      * @apiNote
      * This method may defer calling the {@link
@@ -1580,6 +1588,8 @@
      * @return an instance of {@link Logger} that can be used by the calling
      *         class.
      * @throws NullPointerException if {@code name} is {@code null}.
+     * @throws IllegalCallerException if there is no Java caller frame on the
+     *         stack.
      *
      * @since 9
      */
@@ -1587,6 +1597,9 @@
     public static Logger getLogger(String name) {
         Objects.requireNonNull(name);
         final Class<?> caller = Reflection.getCallerClass();
+        if (caller == null) {
+            throw new IllegalCallerException("no caller frame");
+        }
         return LazyLoggers.getLogger(name, caller.getModule());
     }
 
@@ -1600,8 +1613,16 @@
      * The returned logger will perform message localization as specified
      * by {@link LoggerFinder#getLocalizedLogger(java.lang.String,
      * java.util.ResourceBundle, java.lang.reflect.Module)
-     * LoggerFinder.getLocalizedLogger(name, bundle, module}, where
+     * LoggerFinder.getLocalizedLogger(name, bundle, module)}, where
      * {@code module} is the caller's module.
+     * In cases where {@code System.getLogger} is called from a context where
+     * there is no caller frame on the stack (e.g when called directly
+     * from a JNI attached thread), {@code IllegalCallerException} is thrown.
+     * To obtain a logger in such a context, use an auxiliary class that
+     * will implicitly be identified as the caller, or use the system {@link
+     * LoggerFinder#getLoggerFinder() LoggerFinder} to obtain a logger instead.
+     * Note that doing the latter may eagerly initialize the underlying
+     * logging system.
      *
      * @apiNote
      * This method is intended to be used after the system is fully initialized.
@@ -1620,6 +1641,8 @@
      * resource bundle for message localization.
      * @throws NullPointerException if {@code name} is {@code null} or
      *         {@code bundle} is {@code null}.
+     * @throws IllegalCallerException if there is no Java caller frame on the
+     *         stack.
      *
      * @since 9
      */
@@ -1628,6 +1651,9 @@
         final ResourceBundle rb = Objects.requireNonNull(bundle);
         Objects.requireNonNull(name);
         final Class<?> caller = Reflection.getCallerClass();
+        if (caller == null) {
+            throw new IllegalCallerException("no caller frame");
+        }
         final SecurityManager sm = System.getSecurityManager();
         // We don't use LazyLoggers if a resource bundle is specified.
         // Bootstrap sensitive classes in the JDK do not use resource bundles
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Constructor.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/Constructor.java	Thu Mar 30 19:55:04 2017 +0200
@@ -174,7 +174,6 @@
      * @throws SecurityException if the request is denied by the security manager
      *         or this is a constructor for {@code java.lang.Class}
      *
-     * @since 9
      * @spec JPMS
      */
     @Override
--- a/jdk/src/java.base/share/classes/java/nio/MappedByteBuffer.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/java.base/share/classes/java/nio/MappedByteBuffer.java	Thu Mar 30 19:55:04 2017 +0200
@@ -213,7 +213,6 @@
 
     /**
      * {@inheritDoc}
-     * @since 9
      */
     @Override
     public final MappedByteBuffer position(int newPosition) {
@@ -223,7 +222,6 @@
 
     /**
      * {@inheritDoc}
-     * @since 9
      */
     @Override
     public final MappedByteBuffer limit(int newLimit) {
@@ -233,7 +231,6 @@
 
     /**
      * {@inheritDoc}
-     * @since 9
      */
     @Override
     public final MappedByteBuffer mark() {
@@ -243,7 +240,6 @@
 
     /**
      * {@inheritDoc}
-     * @since 9
      */
     @Override
     public final MappedByteBuffer reset() {
@@ -253,7 +249,6 @@
 
     /**
      * {@inheritDoc}
-     * @since 9
      */
     @Override
     public final MappedByteBuffer clear() {
@@ -263,7 +258,6 @@
 
     /**
      * {@inheritDoc}
-     * @since 9
      */
     @Override
     public final MappedByteBuffer flip() {
@@ -273,7 +267,6 @@
 
     /**
      * {@inheritDoc}
-     * @since 9
      */
     @Override
     public final MappedByteBuffer rewind() {
--- a/jdk/src/java.base/share/classes/java/nio/X-Buffer.java.template	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/java.base/share/classes/java/nio/X-Buffer.java.template	Thu Mar 30 19:55:04 2017 +0200
@@ -1069,7 +1069,6 @@
 
     /**
      * {@inheritDoc}
-     * @since 9
      */
     @Override
     public
@@ -1083,7 +1082,6 @@
     
     /**
      * {@inheritDoc}
-     * @since 9
      */
     @Override
     public
@@ -1097,7 +1095,6 @@
     
     /**
      * {@inheritDoc}
-     * @since 9
      */
     @Override
     public 
@@ -1111,7 +1108,6 @@
 
     /**
      * {@inheritDoc}
-     * @since 9
      */
     @Override
     public 
@@ -1125,7 +1121,6 @@
 
     /**
      * {@inheritDoc}
-     * @since 9
      */
     @Override
     public 
@@ -1139,7 +1134,6 @@
 
     /**
      * {@inheritDoc}
-     * @since 9
      */
     @Override
     public 
@@ -1153,7 +1147,6 @@
 
     /**
      * {@inheritDoc}
-     * @since 9
      */
     @Override
     public 
--- a/jdk/src/java.base/share/classes/java/security/SecureRandom.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/java.base/share/classes/java/security/SecureRandom.java	Thu Mar 30 19:55:04 2017 +0200
@@ -651,8 +651,6 @@
      * {@code SecureRandom}.
      *
      * @return the string representation
-     *
-     * @since 9
      */
     @Override
     public String toString() {
--- a/jdk/src/java.base/share/classes/java/security/SecureRandomSpi.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/java.base/share/classes/java/security/SecureRandomSpi.java	Thu Mar 30 19:55:04 2017 +0200
@@ -211,8 +211,6 @@
      * {@code SecureRandom}.
      *
      * @return the string representation
-     *
-     * @since 9
      */
     @Override
     public String toString() {
--- a/jdk/src/java.base/share/classes/java/time/chrono/Era.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/java.base/share/classes/java/time/chrono/Era.java	Thu Mar 30 19:55:04 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -310,8 +310,8 @@
      * The parameters control the style of the returned text and the locale.
      * <p>
      * If no textual mapping is found then the {@link #getValue() numeric value} is returned.
-     * <p>
-     * This default implementation is suitable for all implementations.
+     *
+     * @apiNote This default implementation is suitable for most implementations.
      *
      * @param style  the style of the text required, not null
      * @param locale  the locale to use, not null
--- a/jdk/src/java.base/share/classes/java/time/chrono/JapaneseEra.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/java.base/share/classes/java/time/chrono/JapaneseEra.java	Thu Mar 30 19:55:04 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -240,19 +240,10 @@
     }
 
     /**
-     * Gets the textual representation of this era.
-     * <p>
-     * This returns the textual name used to identify the era,
-     * suitable for presentation to the user.
-     * The parameters control the style of the returned text and the locale.
-     * <p>
-     * If no textual mapping is found then the {@link #getValue() numeric value}
-     * is returned.
+     * {@inheritDoc}
      *
-     * @param style  the style of the text required, not null
-     * @param locale  the locale to use, not null
-     * @return the text value of the era, not null
-     * @since 9
+     * @param style {@inheritDoc}
+     * @param locale {@inheritDoc}
      */
     @Override
     public String getDisplayName(TextStyle style, Locale locale) {
--- a/jdk/src/java.base/share/classes/java/util/jar/Pack200.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/java.base/share/classes/java/util/jar/Pack200.java	Thu Mar 30 19:55:04 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -452,13 +452,13 @@
         String CODE_ATTRIBUTE_PFX       = "pack.code.attribute.";
 
         /**
-         * The unpacker's progress as a percentage, as periodically
-         * updated by the unpacker.
+         * The packer's progress as a percentage, as periodically
+         * updated by the packer.
          * Values of 0 - 100 are normal, and -1 indicates a stall.
          * Progress can be monitored by polling the value of this
          * property.
          * <p>
-         * At a minimum, the unpacker must set progress to 0
+         * At a minimum, the packer must set progress to 0
          * at the beginning of a packing operation, and to 100
          * at the end.
          */
@@ -623,7 +623,7 @@
          * property.
          * <p>
          * At a minimum, the unpacker must set progress to 0
-         * at the beginning of a packing operation, and to 100
+         * at the beginning of an unpacking operation, and to 100
          * at the end.
          */
         String PROGRESS         = "unpack.progress";
@@ -631,7 +631,7 @@
         /**
          * Get the set of this engine's properties. This set is
          * a "live view", so that changing its
-         * contents immediately affects the Packer engine, and
+         * contents immediately affects the Unpacker engine, and
          * changes from the engine (such as progress indications)
          * are immediately visible in the map.
          *
--- a/jdk/src/java.base/share/classes/jdk/internal/module/IllegalAccessLogger.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/IllegalAccessLogger.java	Thu Mar 30 19:55:04 2017 +0200
@@ -25,6 +25,7 @@
 
 package jdk.internal.module;
 
+import java.io.PrintStream;
 import java.lang.invoke.MethodHandles;
 import java.lang.reflect.Module;
 import java.net.URL;
@@ -42,6 +43,9 @@
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
 
+import jdk.internal.loader.BootLoader;
+import sun.security.action.GetPropertyAction;
+
 /**
  * Supports logging of access to members of API packages that are exported or
  * opened via backdoor mechanisms to code in unnamed modules.
@@ -49,16 +53,25 @@
 
 public final class IllegalAccessLogger {
 
-    // true to print stack trace
-    private static final boolean PRINT_STACK_TRACE;
-    static {
-        String s = System.getProperty("sun.reflect.debugModuleAccessChecks");
-        PRINT_STACK_TRACE = "access".equals(s);
+    /**
+     * Holder class to lazily create the StackWalker object and determine
+     * if the stack trace should be printed
+     */
+    static class Holder {
+        static final StackWalker STACK_WALKER;
+        static final boolean PRINT_STACK_TRACE;
+
+        static {
+            PrivilegedAction<StackWalker> pa = () ->
+                StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
+            STACK_WALKER = AccessController.doPrivileged(pa);
+
+            String name = "sun.reflect.debugModuleAccessChecks";
+            String value = GetPropertyAction.privilegedGetProperty(name, null);
+            PRINT_STACK_TRACE = "access" .equals(value);
+        }
     }
 
-    private static final StackWalker STACK_WALKER
-        = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
-
     // the maximum number of frames to capture
     private static final int MAX_STACK_FRAMES = 32;
 
@@ -72,10 +85,15 @@
     private final Map<Module, Map<String, String>> exported;
     private final Map<Module, Map<String, String>> opened;
 
+    // the print stream to send the warnings
+    private final PrintStream warningStream;
+
     private IllegalAccessLogger(Map<Module, Map<String, String>> exported,
-                                Map<Module, Map<String, String>> opened) {
+                                Map<Module, Map<String, String>> opened,
+                                PrintStream warningStream) {
         this.exported = deepCopy(exported);
         this.opened = deepCopy(opened);
+        this.warningStream = warningStream;
     }
 
     /**
@@ -168,7 +186,7 @@
      */
     private void log(Class<?> caller, String what, Supplier<String> msgSupplier) {
         // stack trace without the top-most frames in java.base
-        List<StackWalker.StackFrame> stack = STACK_WALKER.walk(s ->
+        List<StackWalker.StackFrame> stack = Holder.STACK_WALKER.walk(s ->
             s.dropWhile(this::isJavaBase)
              .limit(MAX_STACK_FRAMES)
              .collect(Collectors.toList())
@@ -184,13 +202,13 @@
         // log message if first usage
         if (firstUsage) {
             String msg = msgSupplier.get();
-            if (PRINT_STACK_TRACE) {
+            if (Holder.PRINT_STACK_TRACE) {
                 synchronized (OUTPUT_LOCK) {
-                    System.err.println(msg);
-                    stack.forEach(f -> System.err.println("\tat " + f));
+                    warningStream.println(msg);
+                    stack.forEach(f -> warningStream.println("\tat " + f));
                 }
             } else {
-                System.err.println(msg);
+                warningStream.println(msg);
             }
         }
     }
@@ -265,8 +283,10 @@
      * A builder for IllegalAccessLogger objects.
      */
     public static class Builder {
+        private final Module UNNAMED = BootLoader.getUnnamedModule();
         private Map<Module, Map<String, String>> exported;
         private Map<Module, Map<String, String>> opened;
+        private PrintStream warningStream = System.err;
 
         public Builder() { }
 
@@ -276,30 +296,37 @@
             this.opened = deepCopy(opened);
         }
 
-        public void logAccessToExportedPackage(Module m, String pn, String how) {
-            if (!m.isExported(pn)) {
+        public Builder logAccessToExportedPackage(Module m, String pn, String how) {
+            if (!m.isExported(pn, UNNAMED)) {
                 if (exported == null)
                     exported = new HashMap<>();
                 exported.computeIfAbsent(m, k -> new HashMap<>()).putIfAbsent(pn, how);
             }
+            return this;
         }
 
-        public void logAccessToOpenPackage(Module m, String pn, String how) {
+        public Builder logAccessToOpenPackage(Module m, String pn, String how) {
             // opens implies exported at run-time.
             logAccessToExportedPackage(m, pn, how);
 
-            if (!m.isOpen(pn)) {
+            if (!m.isOpen(pn, UNNAMED)) {
                 if (opened == null)
                     opened = new HashMap<>();
                 opened.computeIfAbsent(m, k -> new HashMap<>()).putIfAbsent(pn, how);
             }
+            return this;
+        }
+
+        public Builder warningStream(PrintStream warningStream) {
+            this.warningStream = Objects.requireNonNull(warningStream);
+            return this;
         }
 
         /**
          * Builds the logger.
          */
         public IllegalAccessLogger build() {
-            return new IllegalAccessLogger(exported, opened);
+            return new IllegalAccessLogger(exported, opened, warningStream);
         }
     }
 
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java	Thu Mar 30 19:55:04 2017 +0200
@@ -515,44 +515,42 @@
      * additional packages specified on the command-line.
      */
     private static void addExtraExportsAndOpens(Layer bootLayer) {
-        IllegalAccessLogger.Builder builder = new IllegalAccessLogger.Builder();
-
         // --add-exports
         String prefix = "jdk.module.addexports.";
         Map<String, List<String>> extraExports = decode(prefix);
         if (!extraExports.isEmpty()) {
-            addExtraExportsOrOpens(bootLayer, extraExports, false, builder);
+            addExtraExportsOrOpens(bootLayer, extraExports, false);
         }
 
         // --add-opens
         prefix = "jdk.module.addopens.";
         Map<String, List<String>> extraOpens = decode(prefix);
         if (!extraOpens.isEmpty()) {
-            addExtraExportsOrOpens(bootLayer, extraOpens, true, builder);
+            addExtraExportsOrOpens(bootLayer, extraOpens, true);
         }
 
         // --permit-illegal-access
         if (getAndRemoveProperty("jdk.module.permitIllegalAccess") != null) {
             warn("--permit-illegal-access will be removed in the next major release");
+            IllegalAccessLogger.Builder builder = new IllegalAccessLogger.Builder();
+            Module unnamed = BootLoader.getUnnamedModule();
             bootLayer.modules().stream().forEach(m -> {
                 m.getDescriptor()
                  .packages()
                  .stream()
-                 .filter(pn -> !m.isOpen(pn))
+                 .filter(pn -> !m.isOpen(pn, unnamed))  // skip if opened by --add-opens
                  .forEach(pn -> {
                      builder.logAccessToOpenPackage(m, pn, "--permit-illegal-access");
                      Modules.addOpensToAllUnnamed(m, pn);
                  });
             });
+            IllegalAccessLogger.setIllegalAccessLogger(builder.build());
         }
-
-        IllegalAccessLogger.setIllegalAccessLogger(builder.build());
     }
 
     private static void addExtraExportsOrOpens(Layer bootLayer,
                                                Map<String, List<String>> map,
-                                               boolean opens,
-                                               IllegalAccessLogger.Builder builder)
+                                               boolean opens)
     {
         String option = opens ? ADD_OPENS : ADD_EXPORTS;
         for (Map.Entry<String, List<String>> e : map.entrySet()) {
@@ -600,10 +598,8 @@
                 }
                 if (allUnnamed) {
                     if (opens) {
-                        builder.logAccessToOpenPackage(m, pn, option);
                         Modules.addOpensToAllUnnamed(m, pn);
                     } else {
-                        builder.logAccessToExportedPackage(m, pn, option);
                         Modules.addExportsToAllUnnamed(m, pn);
                     }
                 } else {
--- a/jdk/src/java.base/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/java.base/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -26,6 +26,7 @@
 /**
  * Defines the foundational APIs of the Java SE Platform.
  *
+ * @moduleGraph
  * @since 9
  */
 module java.base {
--- a/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java	Thu Mar 30 19:55:04 2017 +0200
@@ -85,7 +85,6 @@
 import java.util.stream.Stream;
 
 import jdk.internal.misc.VM;
-import jdk.internal.module.IllegalAccessLogger;
 import jdk.internal.module.Modules;
 
 
@@ -429,20 +428,14 @@
                 abort(null, "java.launcher.jar.error3", jarname);
             }
 
-            // Add-Exports and Add-Opens to allow illegal access
+            // Add-Exports and Add-Opens
             String exports = mainAttrs.getValue(ADD_EXPORTS);
             if (exports != null) {
-                String warn = getLocalizedMessage("java.launcher.permitaccess.warning",
-                                                  jarname, ADD_EXPORTS);
-                System.err.println(warn);
-                addExportsOrOpens(exports, false, ADD_EXPORTS);
+                addExportsOrOpens(exports, false);
             }
             String opens = mainAttrs.getValue(ADD_OPENS);
             if (opens != null) {
-                String warn = getLocalizedMessage("java.launcher.permitaccess.warning",
-                                                   jarname, ADD_OPENS);
-                System.err.println(warn);
-                addExportsOrOpens(opens, true, ADD_OPENS);
+                addExportsOrOpens(opens, true);
             }
 
             /*
@@ -467,15 +460,7 @@
      * Process the Add-Exports or Add-Opens value. The value is
      * {@code <module>/<package> ( <module>/<package>)*}.
      */
-    static void addExportsOrOpens(String value, boolean open, String how) {
-        IllegalAccessLogger.Builder builder;
-        IllegalAccessLogger logger = IllegalAccessLogger.illegalAccessLogger();
-        if (logger == null) {
-            builder = new IllegalAccessLogger.Builder();
-        } else {
-            builder = logger.toBuilder();
-        }
-
+    static void addExportsOrOpens(String value, boolean open) {
         for (String moduleAndPackage : value.split(" ")) {
             String[] s = moduleAndPackage.trim().split("/");
             if (s.length == 2) {
@@ -485,18 +470,14 @@
                 Layer.boot().findModule(mn).ifPresent(m -> {
                     if (m.getDescriptor().packages().contains(pn)) {
                         if (open) {
-                            builder.logAccessToOpenPackage(m, pn, how);
                             Modules.addOpensToAllUnnamed(m, pn);
                         } else {
-                            builder.logAccessToExportedPackage(m, pn, how);
                             Modules.addExportsToAllUnnamed(m, pn);
                         }
                     }
                 });
             }
         }
-
-        IllegalAccessLogger.setIllegalAccessLogger(builder.build());
     }
 
     // From src/share/bin/java.c:
--- a/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties	Thu Mar 30 19:55:04 2017 +0200
@@ -211,6 +211,4 @@
 java.launcher.module.error3=\
     Error: Unable to load main class {0} from module {1}\n\
     \t{2}
-java.launcher.permitaccess.warning=\
-    WARNING: Main manifest of {0} contains {1} attribute to permit illegal access
 
--- a/jdk/src/java.base/share/classes/sun/security/tools/keytool/Main.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/tools/keytool/Main.java	Thu Mar 30 19:55:04 2017 +0200
@@ -1025,6 +1025,13 @@
             cf = CertificateFactory.getInstance("X509");
         }
 
+        // -trustcacerts can only be specified on -importcert.
+        // Reset it so that warnings on CA cert will remain for
+        // -printcert, etc.
+        if (command != IMPORTCERT) {
+            trustcacerts = false;
+        }
+
         if (trustcacerts) {
             caks = KeyStoreUtil.getCacertsKeyStore();
         }
@@ -1758,9 +1765,8 @@
         if (keyPass == null) {
             keyPass = promptForKeyPass(alias, null, storePass);
         }
+        checkWeak(rb.getString("the.generated.certificate"), chain[0]);
         keyStore.setKeyEntry(alias, privKey, keyPass, chain);
-
-        checkWeak(rb.getString("the.generated.certificate"), chain[0]);
     }
 
     /**
@@ -2118,6 +2124,10 @@
         }
 
         try {
+            Certificate c = srckeystore.getCertificate(alias);
+            if (c != null) {
+                checkWeak("<" + newAlias + ">", c);
+            }
             keyStore.setEntry(newAlias, entry, pp);
             // Place the check so that only successful imports are blocked.
             // For example, we don't block a failed SecretEntry import.
@@ -2127,10 +2137,6 @@
                             "The.destination.pkcs12.keystore.has.different.storepass.and.keypass.Please.retry.with.destkeypass.specified."));
                 }
             }
-            Certificate c = srckeystore.getCertificate(alias);
-            if (c != null) {
-                checkWeak("<" + newAlias + ">", c);
-            }
             return 1;
         } catch (KeyStoreException kse) {
             Object[] source2 = {alias, kse.toString()};
@@ -2814,8 +2820,8 @@
         }
 
         if (noprompt) {
+            checkWeak(rb.getString("the.input"), cert);
             keyStore.setCertificateEntry(alias, cert);
-            checkWeak(rb.getString("the.input"), cert);
             return true;
         }
 
@@ -3049,6 +3055,11 @@
         MessageFormat form = new MessageFormat
                 (rb.getString(".PATTERN.printX509Cert.with.weak"));
         PublicKey pkey = cert.getPublicKey();
+        String sigName = cert.getSigAlgName();
+        // No need to warn about sigalg of a trust anchor
+        if (!isTrustedCert(cert)) {
+            sigName = withWeak(sigName);
+        }
         Object[] source = {cert.getSubjectDN().toString(),
                         cert.getIssuerDN().toString(),
                         cert.getSerialNumber().toString(16),
@@ -3056,7 +3067,7 @@
                         cert.getNotAfter().toString(),
                         getCertFingerPrint("SHA-1", cert),
                         getCertFingerPrint("SHA-256", cert),
-                        withWeak(cert.getSigAlgName()),
+                        sigName,
                         withWeak(pkey),
                         cert.getVersion()
                         };
@@ -3111,7 +3122,7 @@
      * or null otherwise. A label is added.
      */
     private static Pair<String,Certificate>
-            getTrustedSigner(Certificate cert, KeyStore ks) throws Exception {
+            getSigner(Certificate cert, KeyStore ks) throws Exception {
         if (ks.getCertificateAlias(cert) != null) {
             return new Pair<>("", cert);
         }
@@ -3467,9 +3478,9 @@
         // do we trust the cert at the top?
         Certificate topCert = replyCerts[replyCerts.length-1];
         boolean fromKeyStore = true;
-        Pair<String,Certificate> root = getTrustedSigner(topCert, keyStore);
+        Pair<String,Certificate> root = getSigner(topCert, keyStore);
         if (root == null && trustcacerts && caks != null) {
-            root = getTrustedSigner(topCert, caks);
+            root = getSigner(topCert, caks);
             fromKeyStore = false;
         }
         if (root == null) {
@@ -4301,9 +4312,19 @@
         return result;
     }
 
+    private boolean isTrustedCert(Certificate cert) throws KeyStoreException {
+        if (caks != null && caks.getCertificateAlias(cert) != null) {
+            return true;
+        } else {
+            String inKS = keyStore.getCertificateAlias(cert);
+            return inKS != null && keyStore.isCertificateEntry(inKS);
+        }
+    }
+
     private void checkWeak(String label, String sigAlg, Key key) {
 
-        if (!DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, sigAlg, null)) {
+        if (sigAlg != null && !DISABLED_CHECK.permits(
+                SIG_PRIMITIVE_SET, sigAlg, null)) {
             weakWarnings.add(String.format(
                     rb.getString("whose.sigalg.risk"), label, sigAlg));
         }
@@ -4316,7 +4337,8 @@
         }
     }
 
-    private void checkWeak(String label, Certificate[] certs) {
+    private void checkWeak(String label, Certificate[] certs)
+            throws KeyStoreException {
         for (int i = 0; i < certs.length; i++) {
             Certificate cert = certs[i];
             if (cert instanceof X509Certificate) {
@@ -4325,15 +4347,18 @@
                 if (certs.length > 1) {
                     fullLabel = oneInMany(label, i, certs.length);
                 }
-                checkWeak(fullLabel, xc.getSigAlgName(), xc.getPublicKey());
+                checkWeak(fullLabel, xc);
             }
         }
     }
 
-    private void checkWeak(String label, Certificate cert) {
+    private void checkWeak(String label, Certificate cert)
+            throws KeyStoreException {
         if (cert instanceof X509Certificate) {
             X509Certificate xc = (X509Certificate)cert;
-            checkWeak(label, xc.getSigAlgName(), xc.getPublicKey());
+            // No need to check the sigalg of a trust anchor
+            String sigAlg = isTrustedCert(cert) ? null : xc.getSigAlgName();
+            checkWeak(label, sigAlg, xc.getPublicKey());
         }
     }
 
--- a/jdk/src/java.datatransfer/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/java.datatransfer/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -24,8 +24,9 @@
  */
 
 /**
- * Defines an API for transferring data between and within applications.
+ * Defines the API for transferring data between and within applications.
  *
+ * @moduleGraph
  * @since 9
  */
 module java.datatransfer {
--- a/jdk/src/java.desktop/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/java.desktop/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -27,6 +27,7 @@
  * Defines the AWT and Swing user interface toolkits, plus APIs for
  * accessibility, audio, imaging, printing, and JavaBeans.
  *
+ * @moduleGraph
  * @since 9
  */
 module java.desktop {
--- a/jdk/src/java.instrument/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/java.instrument/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -27,6 +27,7 @@
  * Defines services that allow agents to
  * instrument programs running on the JVM.
  *
+ * @moduleGraph
  * @since 9
  */
 module java.instrument {
--- a/jdk/src/java.logging/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/java.logging/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -26,6 +26,7 @@
 /**
  * Defines the Java Logging API.
  *
+ * @moduleGraph
  * @since 9
  */
 module java.logging {
--- a/jdk/src/java.management.rmi/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/java.management.rmi/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -46,6 +46,7 @@
  *           and load the appropriate {@code JMXConnectorServerProvider} service
  *           implementation for the given protocol.
  *
+ * @moduleGraph
  * @since 9
  */
 module java.management.rmi {
--- a/jdk/src/java.management/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/java.management/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -29,6 +29,7 @@
  * The JMX API consists of interfaces for monitoring and management of the
  * JVM and other components in the Java runtime.
  *
+ * @moduleGraph
  * @since 9
  */
 module java.management {
--- a/jdk/src/java.naming/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/java.naming/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -26,6 +26,7 @@
 /**
  * Defines the Java Naming and Directory Interface (JNDI) API.
  *
+ * @moduleGraph
  * @since 9
  */
 module java.naming {
--- a/jdk/src/java.prefs/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/java.prefs/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -26,6 +26,7 @@
 /**
  * Defines the Preferences API.
  *
+ * @moduleGraph
  * @since 9
  */
 module java.prefs {
--- a/jdk/src/java.rmi/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/java.rmi/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -26,6 +26,7 @@
 /**
  * Defines the Remote Method Invocation (RMI) API.
  *
+ * @moduleGraph
  * @since 9
  */
 module java.rmi {
--- a/jdk/src/java.scripting/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/java.scripting/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -26,6 +26,7 @@
 /**
  * Defines the Scripting API.
  *
+ * @moduleGraph
  * @since 9
  */
 module java.scripting {
--- a/jdk/src/java.se.ee/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/java.se.ee/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -29,6 +29,7 @@
  * This module requires {@code java.se} and supplements it with modules
  * that define CORBA and Java EE APIs. These modules are upgradeable.
  *
+ * @moduleGraph
  * @since 9
  */
 @SuppressWarnings("deprecation")
--- a/jdk/src/java.se/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/java.se/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -29,6 +29,7 @@
  * The modules defining CORBA and Java EE APIs are not required by
  * this module, but they are required by {@code java.se.ee}.
  *
+ * @moduleGraph
  * @since 9
  */
 module java.se {
--- a/jdk/src/java.security.jgss/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/java.security.jgss/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -28,6 +28,7 @@
  * <P>
  * This module also contains GSS-API mechanisms including Kerberos v5 and SPNEGO.
  *
+ * @moduleGraph
  * @since 9
  */
 module java.security.jgss {
--- a/jdk/src/java.security.sasl/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/java.security.sasl/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -30,6 +30,7 @@
  * This module also contains SASL mechanisms including DIGEST-MD5,
  * CRAM-MD5, and NTLM.
  *
+ * @moduleGraph
  * @since 9
  */
 module java.security.sasl {
--- a/jdk/src/java.smartcardio/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/java.smartcardio/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -26,6 +26,7 @@
 /**
  * Defines the Java Smart Card I/O API.
  *
+ * @moduleGraph
  * @since 9
  */
 module java.smartcardio {
--- a/jdk/src/java.sql.rowset/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/java.sql.rowset/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -26,6 +26,7 @@
 /**
  * Defines the JDBC RowSet API.
  *
+ * @moduleGraph
  * @since 9
  */
 module java.sql.rowset {
--- a/jdk/src/java.sql/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/java.sql/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -26,6 +26,7 @@
 /**
  * Defines the JDBC API.
  *
+ * @moduleGraph
  * @since 9
  */
 module java.sql {
--- a/jdk/src/java.transaction/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/java.transaction/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -29,6 +29,7 @@
  * The subset consists of RMI exception types which are mapped to CORBA system
  * exceptions by the 'Java Language to IDL Mapping Specification'.
  *
+ * @moduleGraph
  * @since 9
  */
 @Deprecated(since="9", forRemoval=true)
--- a/jdk/src/java.xml.crypto/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/java.xml.crypto/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -24,8 +24,9 @@
  */
 
 /**
- * Defines an API for XML cryptography.
+ * Defines the API for XML cryptography.
  *
+ * @moduleGraph
  * @since 9
  */
 module java.xml.crypto {
--- a/jdk/src/jdk.attach/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/jdk.attach/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -26,6 +26,7 @@
 /**
  * Defines the attach API.
  *
+ * @moduleGraph
  * @since 9
  */
 module jdk.attach {
--- a/jdk/src/jdk.charsets/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/jdk.charsets/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -23,6 +23,13 @@
  * questions.
  */
 
+/**
+ * {@link java.nio.charset.Charset Charset} provider for the charsets that
+ * are not in {@code java.base} (mostly double byte and IBM charsets).
+ *
+ * @moduleGraph
+ * @since 9
+ */
 module jdk.charsets {
     provides java.nio.charset.spi.CharsetProvider
         with sun.nio.cs.ext.ExtendedCharsets;
--- a/jdk/src/jdk.crypto.cryptoki/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/jdk.crypto.cryptoki/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -26,6 +26,7 @@
 /**
  * The SunPKCS11 security provider.
  *
+ * @moduleGraph
  * @since 9
  */
 module jdk.crypto.cryptoki {
--- a/jdk/src/jdk.crypto.ec/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/jdk.crypto.ec/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -26,6 +26,7 @@
 /**
  * The SunEC security provider.
  *
+ * @moduleGraph
  * @since 9
  */
 module jdk.crypto.ec {
--- a/jdk/src/jdk.crypto.mscapi/windows/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/jdk.crypto.mscapi/windows/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -26,6 +26,7 @@
 /**
  * The SunMSCAPI security provider.
  *
+ * @moduleGraph
  * @since 9
  */
 module jdk.crypto.mscapi {
--- a/jdk/src/jdk.crypto.ucrypto/solaris/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/jdk.crypto.ucrypto/solaris/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -26,6 +26,7 @@
 /**
  * The OracleUCrypto security provider.
  *
+ * @moduleGraph
  * @since 9
  */
 module jdk.crypto.ucrypto {
--- a/jdk/src/jdk.httpserver/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/jdk.httpserver/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -23,6 +23,12 @@
  * questions.
  */
 
+/**
+ * Defines the JDK-specific API for HTTP server.
+ *
+ * @moduleGraph
+ * @since 9
+ */
 module jdk.httpserver {
 
     exports com.sun.net.httpserver;
--- a/jdk/src/jdk.jartool/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/jdk.jartool/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -23,6 +23,13 @@
  * questions.
  */
 
+/**
+ * Defines tools for manipulating Java Archive (JAR) files,
+ * including the jar and jarsigner tools.
+ *
+ * @moduleGraph
+ * @since 9
+ */
 module jdk.jartool {
     exports com.sun.jarsigner;
     exports jdk.security.jarsigner;
--- a/jdk/src/jdk.jcmd/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/jdk.jcmd/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -23,6 +23,13 @@
  * questions.
  */
 
+/**
+ * Defines tools for diagnostics and troubleshooting a JVM,
+ * including the jcmd, jps, jstat and other diagnostics tools.
+ *
+ * @moduleGraph
+ * @since 9
+ */
 module jdk.jcmd {
     requires jdk.attach;
     requires jdk.internal.jvmstat;
--- a/jdk/src/jdk.jconsole/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/jdk.jconsole/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -23,6 +23,13 @@
  * questions.
  */
 
+/**
+ * Defines the JMX graphical tool, jconsole, for monitoring and managing
+ * a running application.
+ *
+ * @moduleGraph
+ * @since 9
+ */
 module jdk.jconsole {
     requires transitive java.desktop;
     requires transitive java.management;
--- a/jdk/src/jdk.jdi/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/jdk.jdi/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -26,6 +26,7 @@
 /**
  * Defines the Java Debugger Interface.
  *
+ * @moduleGraph
  * @since 9
  */
 module jdk.jdi {
--- a/jdk/src/jdk.jdwp.agent/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/jdk.jdwp.agent/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -26,6 +26,7 @@
 /**
  * Java Debug Wire Protocol.
  *
+ * @moduleGraph
  * @since 9
  */
 module jdk.jdwp.agent {
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/JImageTask.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/JImageTask.java	Thu Mar 30 19:55:04 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,8 +35,12 @@
 import java.util.Arrays;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Locale;
 import java.util.MissingResourceException;
 import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
 import jdk.internal.jimage.BasicImageReader;
 import jdk.internal.jimage.ImageHeader;
 import jdk.internal.jimage.ImageLocation;
@@ -99,7 +103,7 @@
     }
 
     static class OptionsValues {
-        Task task = Task.LIST;
+        Task task = null;
         String directory = ".";
         String include = "";
         boolean fullVersion;
@@ -172,24 +176,31 @@
         }
 
         try {
-            List<String> unhandled = OPTION_HELPER.handleOptions(this, args);
+            String command;
+            String[] remaining = args;
+            try {
+                command = args[0];
+                options.task = Enum.valueOf(Task.class, args[0].toUpperCase(Locale.ENGLISH));
+                remaining = args.length > 1 ? Arrays.copyOfRange(args, 1, args.length)
+                                            : new String[0];
+            } catch (IllegalArgumentException ex) {
+                command = null;
+                options.task = null;
+            }
 
-            if(!unhandled.isEmpty()) {
-                try {
-                    options.task = Enum.valueOf(Task.class, unhandled.get(0).toUpperCase());
-                } catch (IllegalArgumentException ex) {
-                    throw TASK_HELPER.newBadArgs("err.not.a.task", unhandled.get(0));
-                }
+            // process arguments
+            List<String> unhandled = OPTION_HELPER.handleOptions(this, remaining);
+            for (String f : unhandled) {
+                options.jimages.add(new File(f));
+            }
 
-                for(int i = 1; i < unhandled.size(); i++) {
-                    options.jimages.add(new File(unhandled.get(i)));
-                }
-            } else if (!options.help && !options.version && !options.fullVersion) {
-                throw TASK_HELPER.newBadArgs("err.invalid.task", "<unspecified>");
+            if (options.task == null && !options.help && !options.version && !options.fullVersion) {
+                throw TASK_HELPER.newBadArgs("err.not.a.task",
+                    command != null ? command : "<unspecified>");
             }
 
             if (options.help) {
-                if (unhandled.isEmpty()) {
+                if (options.task == null) {
                     log.println(TASK_HELPER.getMessage("main.usage", PROGNAME));
                     Arrays.asList(RECOGNIZED_OPTIONS).stream()
                         .filter(option -> !option.isHidden())
@@ -203,15 +214,19 @@
                         log.println(TASK_HELPER.getMessage("main.usage." +
                                 options.task.toString().toLowerCase()));
                     } catch (MissingResourceException ex) {
-                        throw TASK_HELPER.newBadArgs("err.not.a.task", unhandled.get(0));
+                        throw TASK_HELPER.newBadArgs("err.not.a.task", command);
                     }
                 }
                 return EXIT_OK;
             }
 
             if (options.version || options.fullVersion) {
+                if (options.task == null && !unhandled.isEmpty()) {
+                    throw TASK_HELPER.newBadArgs("err.not.a.task",
+                        Stream.of(args).collect(Collectors.joining(" ")));
+                }
+
                 TASK_HELPER.showVersion(options.fullVersion);
-
                 if (unhandled.isEmpty()) {
                     return EXIT_OK;
                 }
@@ -435,7 +450,7 @@
                 iterate(this::listTitle, null, this::verify);
                 break;
             default:
-                throw TASK_HELPER.newBadArgs("err.invalid.task",
+                throw TASK_HELPER.newBadArgs("err.not.a.task",
                         options.task.name()).showUsage(true);
         }
         return true;
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Jlink.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Jlink.java	Thu Mar 30 19:55:04 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,6 +24,8 @@
  */
 package jdk.tools.jlink.internal;
 
+import java.lang.module.Configuration;
+import java.lang.module.ModuleFinder;
 import java.lang.reflect.Layer;
 import java.nio.ByteOrder;
 import java.nio.file.Path;
@@ -33,6 +35,8 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+
+import jdk.internal.module.ModulePath;
 import jdk.tools.jlink.plugin.Plugin;
 import jdk.tools.jlink.plugin.PluginException;
 import jdk.tools.jlink.builder.ImageBuilder;
@@ -147,8 +151,8 @@
         private final Path output;
         private final Set<String> modules;
         private final Set<String> limitmods;
-
         private final ByteOrder endian;
+        private final ModuleFinder finder;
 
         /**
          * jlink configuration,
@@ -160,31 +164,23 @@
          * @param endian Jimage byte order. Native order by default
          */
         public JlinkConfiguration(Path output,
-                List<Path> modulepaths,
-                Set<String> modules,
-                Set<String> limitmods,
-                ByteOrder endian) {
-            this.output = output;
-            this.modulepaths = modulepaths == null ? Collections.emptyList() : modulepaths;
-            this.modules = modules == null ? Collections.emptySet() : modules;
-            this.limitmods = limitmods == null ? Collections.emptySet() : limitmods;
-            this.endian = endian == null ? ByteOrder.nativeOrder() : endian;
-        }
+                                  List<Path> modulepaths,
+                                  Set<String> modules,
+                                  Set<String> limitmods,
+                                  ByteOrder endian) {
+            if (Objects.requireNonNull(modulepaths).isEmpty()) {
+                throw new IllegalArgumentException("Empty module path");
+            }
+            if (Objects.requireNonNull(modules).isEmpty()) {
+                throw new IllegalArgumentException("Empty modules");
+            }
 
-        /**
-         * jlink configuration,
-         *
-         * @param output Output directory, must not exist.
-         * @param modulepaths Modules paths
-         * @param modules Root modules to resolve
-         * @param limitmods Limit the universe of observable modules
-         */
-        public JlinkConfiguration(Path output,
-                List<Path> modulepaths,
-                Set<String> modules,
-                Set<String> limitmods) {
-            this(output, modulepaths, modules, limitmods,
-                    ByteOrder.nativeOrder());
+            this.output = output;
+            this.modulepaths = modulepaths;
+            this.modules = modules;
+            this.limitmods = Objects.requireNonNull(limitmods);
+            this.endian = Objects.requireNonNull(endian);
+            this.finder = moduleFinder();
         }
 
         /**
@@ -222,6 +218,45 @@
             return limitmods;
         }
 
+        /**
+         * Returns {@link ModuleFinder} that finds all observable modules
+         * for this jlink configuration.
+         */
+        public ModuleFinder finder() {
+            return finder;
+        }
+
+        /**
+         * Returns a {@link Configuration} of the given module path,
+         * root modules with full service binding.
+         */
+        public Configuration resolveAndBind()
+        {
+            return Configuration.empty().resolveAndBind(finder,
+                                                        ModuleFinder.of(),
+                                                        modules);
+        }
+
+        /**
+         * Returns a {@link Configuration} of the given module path,
+         * root modules with no service binding.
+         */
+        public Configuration resolve()
+        {
+            return Configuration.empty().resolve(finder,
+                                                 ModuleFinder.of(),
+                                                 modules);
+        }
+
+        private ModuleFinder moduleFinder() {
+            Path[] entries = modulepaths.toArray(new Path[0]);
+            ModuleFinder finder = ModulePath.of(Runtime.version(), true, entries);
+            if (!limitmods.isEmpty()) {
+                finder = JlinkTask.limitFinder(finder, limitmods, modules);
+            }
+            return finder;
+        }
+
         @Override
         public String toString() {
             StringBuilder builder = new StringBuilder();
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java	Thu Mar 30 19:55:04 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -110,6 +110,12 @@
             Path path = Paths.get(arg);
             task.options.output = path;
         }, "--output"),
+        new Option<JlinkTask>(false, (task, opt, arg) -> {
+            task.options.bindServices = true;
+        }, "--bind-services"),
+        new Option<JlinkTask>(false, (task, opt, arg) -> {
+            task.options.suggestProviders = true;
+        }, "--suggest-providers", "", true),
         new Option<JlinkTask>(true, (task, opt, arg) -> {
             String[] values = arg.split("=");
             // check values
@@ -141,6 +147,9 @@
             }
         }, "--endian"),
         new Option<JlinkTask>(false, (task, opt, arg) -> {
+            task.options.verbose = true;
+        }, "--verbose", "-v"),
+        new Option<JlinkTask>(false, (task, opt, arg) -> {
             task.options.version = true;
         }, "--version"),
         new Option<JlinkTask>(true, (task, opt, arg) -> {
@@ -185,6 +194,7 @@
     static class OptionsValues {
         boolean help;
         String  saveoptsfile;
+        boolean verbose;
         boolean version;
         boolean fullVersion;
         final List<Path> modulePath = new ArrayList<>();
@@ -195,6 +205,8 @@
         Path packagedModulesPath;
         ByteOrder endian = ByteOrder.nativeOrder();
         boolean ignoreSigning = false;
+        boolean bindServices = false;
+        boolean suggestProviders = false;
     }
 
     int run(String[] args) {
@@ -203,7 +215,11 @@
                    new PrintWriter(System.err, true));
         }
         try {
-            optionsHelper.handleOptionsNoUnhandled(this, args);
+            List<String> remaining = optionsHelper.handleOptions(this, args);
+            if (remaining.size() > 0 && !options.suggestProviders) {
+                throw taskHelper.newBadArgs("err.orphan.arguments", toString(remaining))
+                                .showUsage(true);
+            }
             if (options.help) {
                 optionsHelper.showHelp(PROGNAME);
                 return EXIT_OK;
@@ -217,17 +233,24 @@
                 return EXIT_OK;
             }
 
-            if (taskHelper.getExistingImage() == null) {
-                if (options.modulePath.isEmpty()) {
-                    throw taskHelper.newBadArgs("err.modulepath.must.be.specified").showUsage(true);
-                }
-                createImage();
-            } else {
+            if (taskHelper.getExistingImage() != null) {
                 postProcessOnly(taskHelper.getExistingImage());
+                return EXIT_OK;
             }
 
-            if (options.saveoptsfile != null) {
-                Files.write(Paths.get(options.saveoptsfile), getSaveOpts().getBytes());
+            if (options.modulePath.isEmpty()) {
+                throw taskHelper.newBadArgs("err.modulepath.must.be.specified")
+                                .showUsage(true);
+            }
+
+            JlinkConfiguration config = initJlinkConfig();
+            if (options.suggestProviders) {
+                suggestProviders(config, remaining);
+            } else {
+                createImage(config);
+                if (options.saveoptsfile != null) {
+                    Files.write(Paths.get(options.saveoptsfile), getSaveOpts().getBytes());
+                }
             }
 
             return EXIT_OK;
@@ -266,25 +289,13 @@
         Objects.requireNonNull(config.getOutput());
         plugins = plugins == null ? new PluginsConfiguration() : plugins;
 
-        if (config.getModulepaths().isEmpty()) {
-            throw new IllegalArgumentException("Empty module paths");
-        }
-
-        ModuleFinder finder = newModuleFinder(config.getModulepaths(),
-                                              config.getLimitmods(),
-                                              config.getModules());
-
-        if (config.getModules().isEmpty()) {
-            throw new IllegalArgumentException("No modules to add");
-        }
-
         // First create the image provider
         ImageProvider imageProvider =
-                createImageProvider(finder,
-                                    config.getModules(),
-                                    config.getByteOrder(),
+                createImageProvider(config,
                                     null,
                                     IGNORE_SIGNING_DEFAULT,
+                                    false,
+                                    false,
                                     null);
 
         // Then create the Plugin Stack
@@ -319,20 +330,24 @@
 
     // the token for "all modules on the module path"
     private static final String ALL_MODULE_PATH = "ALL-MODULE-PATH";
-    private void createImage() throws Exception {
-        if (options.output == null) {
-            throw taskHelper.newBadArgs("err.output.must.be.specified").showUsage(true);
-        }
-
+    private JlinkConfiguration initJlinkConfig() throws BadArgs {
         if (options.addMods.isEmpty()) {
             throw taskHelper.newBadArgs("err.mods.must.be.specified", "--add-modules")
-                    .showUsage(true);
+                .showUsage(true);
         }
 
         Set<String> roots = new HashSet<>();
         for (String mod : options.addMods) {
             if (mod.equals(ALL_MODULE_PATH)) {
-                ModuleFinder finder = modulePathFinder();
+                Path[] entries = options.modulePath.toArray(new Path[0]);
+                ModuleFinder finder = ModulePath.of(Runtime.version(), true, entries);
+                if (!options.limitMods.isEmpty()) {
+                    // finder for the observable modules specified in
+                    // the --module-path and --limit-modules options
+                    finder = limitFinder(finder, options.limitMods, Collections.emptySet());
+                }
+
+                // all observable modules are roots
                 finder.findAll()
                       .stream()
                       .map(ModuleReference::descriptor)
@@ -343,40 +358,34 @@
             }
         }
 
-        ModuleFinder finder = newModuleFinder(options.modulePath,
-                                              options.limitMods,
-                                              roots);
+        return new JlinkConfiguration(options.output,
+                                      options.modulePath,
+                                      roots,
+                                      options.limitMods,
+                                      options.endian);
+    }
 
+    private void createImage(JlinkConfiguration config) throws Exception {
+        if (options.output == null) {
+            throw taskHelper.newBadArgs("err.output.must.be.specified").showUsage(true);
+        }
 
         // First create the image provider
-        ImageProvider imageProvider = createImageProvider(finder,
-                                                          roots,
-                                                          options.endian,
+        ImageProvider imageProvider = createImageProvider(config,
                                                           options.packagedModulesPath,
                                                           options.ignoreSigning,
+                                                          options.bindServices,
+                                                          options.verbose,
                                                           log);
 
         // Then create the Plugin Stack
-        ImagePluginStack stack = ImagePluginConfiguration.
-                parseConfiguration(taskHelper.getPluginsConfig(options.output, options.launchers));
+        ImagePluginStack stack = ImagePluginConfiguration.parseConfiguration(
+            taskHelper.getPluginsConfig(options.output, options.launchers));
 
         //Ask the stack to proceed
         stack.operate(imageProvider);
     }
 
-    /**
-     * Returns a module finder to find the observable modules specified in
-     * the --module-path and --limit-modules options
-     */
-    private ModuleFinder modulePathFinder() {
-        Path[] entries = options.modulePath.toArray(new Path[0]);
-        ModuleFinder finder = ModulePath.of(Runtime.version(), true, entries);
-        if (!options.limitMods.isEmpty()) {
-            finder = limitFinder(finder, options.limitMods, Collections.emptySet());
-        }
-        return finder;
-    }
-
     /*
      * Returns a module finder of the given module path that limits
      * the observable modules to those in the transitive closure of
@@ -405,22 +414,32 @@
         return Paths.get(uri);
     }
 
-    private static ImageProvider createImageProvider(ModuleFinder finder,
-                                                     Set<String> roots,
-                                                     ByteOrder order,
+
+    private static ImageProvider createImageProvider(JlinkConfiguration config,
                                                      Path retainModulesPath,
                                                      boolean ignoreSigning,
+                                                     boolean bindService,
+                                                     boolean verbose,
                                                      PrintWriter log)
             throws IOException
     {
-        if (roots.isEmpty()) {
-            throw new IllegalArgumentException("empty modules and limitmods");
-        }
+        Configuration cf = bindService ? config.resolveAndBind()
+                                       : config.resolve();
 
-        Configuration cf = Configuration.empty()
-                .resolve(finder,
-                         ModuleFinder.of(),
-                         roots);
+        if (verbose && log != null) {
+            // print modules to be linked in
+            cf.modules().stream()
+              .sorted(Comparator.comparing(ResolvedModule::name))
+              .forEach(rm -> log.format("module %s (%s)%n",
+                                        rm.name(), rm.reference().location().get()));
+
+            // print provider info
+            Set<ModuleReference> references = cf.modules().stream()
+                .map(ResolvedModule::reference).collect(Collectors.toSet());
+
+            String msg = String.format("%n%s:", taskHelper.getMessage("providers.header"));
+            printProviders(log, msg, references);
+        }
 
         // emit a warning for any incubating modules in the configuration
         if (log != null) {
@@ -438,16 +457,16 @@
 
         Map<String, Path> mods = cf.modules().stream()
             .collect(Collectors.toMap(ResolvedModule::name, JlinkTask::toPathLocation));
-        return new ImageHelper(cf, mods, order, retainModulesPath, ignoreSigning);
+        return new ImageHelper(cf, mods, config.getByteOrder(), retainModulesPath, ignoreSigning);
     }
 
     /*
      * Returns a ModuleFinder that limits observability to the given root
      * modules, their transitive dependences, plus a set of other modules.
      */
-    private static ModuleFinder limitFinder(ModuleFinder finder,
-                                            Set<String> roots,
-                                            Set<String> otherMods) {
+    public static ModuleFinder limitFinder(ModuleFinder finder,
+                                           Set<String> roots,
+                                           Set<String> otherMods) {
 
         // resolve all root modules
         Configuration cf = Configuration.empty()
@@ -484,6 +503,147 @@
         };
     }
 
+    /*
+     * Returns a map of each service type to the modules that use it
+     */
+    private static Map<String, Set<String>> uses(Set<ModuleReference> modules) {
+        // collects the services used by the modules and print uses
+        Map<String, Set<String>> uses = new HashMap<>();
+        modules.stream()
+               .map(ModuleReference::descriptor)
+               .forEach(md -> md.uses().forEach(s ->
+                   uses.computeIfAbsent(s, _k -> new HashSet<>()).add(md.name()))
+               );
+        return uses;
+    }
+
+    private static void printProviders(PrintWriter log,
+                                       String header,
+                                       Set<ModuleReference> modules) {
+        printProviders(log, header, modules, uses(modules));
+    }
+
+    /*
+     * Prints the providers that are used by the services specified in
+     * the given modules.
+     *
+     * The specified uses maps a service type name to the modules
+     * using the service type and that may or may not be present
+     * the given modules.
+     */
+    private static void printProviders(PrintWriter log,
+                                       String header,
+                                       Set<ModuleReference> modules,
+                                       Map<String, Set<String>> uses) {
+        if (modules.isEmpty())
+            return;
+
+        // Build a map of a service type to the provider modules
+        Map<String, Set<ModuleDescriptor>> providers = new HashMap<>();
+        modules.stream()
+            .map(ModuleReference::descriptor)
+            .forEach(md -> {
+                md.provides().stream()
+                  .filter(p -> uses.containsKey(p.service()))
+                  .forEach(p -> providers.computeIfAbsent(p.service(), _k -> new HashSet<>())
+                                         .add(md));
+            });
+
+        if (!providers.isEmpty()) {
+            log.println(header);
+        }
+
+        // print the providers of the service types used by the specified modules
+        // sorted by the service type name and then provider's module name
+        providers.entrySet().stream()
+            .sorted(Map.Entry.comparingByKey())
+            .forEach(e -> {
+                String service = e.getKey();
+                e.getValue().stream()
+                 .sorted(Comparator.comparing(ModuleDescriptor::name))
+                 .forEach(md ->
+                     md.provides().stream()
+                       .filter(p -> p.service().equals(service))
+                       .forEach(p -> log.format("  module %s provides %s, used by %s%n",
+                                                md.name(), p.service(),
+                                                uses.get(p.service()).stream()
+                                                    .sorted()
+                                                    .collect(Collectors.joining(","))))
+                 );
+            });
+    }
+
+    private void suggestProviders(JlinkConfiguration config, List<String> args)
+        throws BadArgs
+    {
+        if (args.size() > 1) {
+            throw taskHelper.newBadArgs("err.orphan.argument",
+                                        toString(args.subList(1, args.size())))
+                            .showUsage(true);
+        }
+
+        if (options.bindServices) {
+            log.println(taskHelper.getMessage("no.suggested.providers"));
+            return;
+        }
+
+        ModuleFinder finder = config.finder();
+        if (args.isEmpty()) {
+            // print providers used by the modules resolved without service binding
+            Configuration cf = config.resolve();
+            Set<ModuleReference> mrefs = cf.modules().stream()
+                .map(ResolvedModule::reference)
+                .collect(Collectors.toSet());
+
+            // print uses of the modules that would be linked into the image
+            mrefs.stream()
+                 .sorted(Comparator.comparing(mref -> mref.descriptor().name()))
+                 .forEach(mref -> {
+                     ModuleDescriptor md = mref.descriptor();
+                     log.format("module %s located (%s)%n", md.name(),
+                                mref.location().get());
+                     md.uses().stream().sorted()
+                       .forEach(s -> log.format("    uses %s%n", s));
+                 });
+
+            String msg = String.format("%n%s:", taskHelper.getMessage("suggested.providers.header"));
+            printProviders(log, msg, finder.findAll(), uses(mrefs));
+
+        } else {
+            // comma-separated service types, if specified
+            Set<String> names = Stream.of(args.get(0).split(","))
+                .collect(Collectors.toSet());
+            // find the modules that provide the specified service
+            Set<ModuleReference> mrefs = finder.findAll().stream()
+                .filter(mref -> mref.descriptor().provides().stream()
+                                    .map(ModuleDescriptor.Provides::service)
+                                    .anyMatch(names::contains))
+                .collect(Collectors.toSet());
+
+            // the specified services may or may not be in the modules that
+            // would be linked in.  So find uses declared in all observable modules
+            Map<String, Set<String>> uses = uses(finder.findAll());
+
+            // check if any name given on the command line are unused service
+            mrefs.stream()
+                 .flatMap(mref -> mref.descriptor().provides().stream()
+                                      .map(ModuleDescriptor.Provides::service))
+                 .forEach(names::remove);
+            if (!names.isEmpty()) {
+                log.println(taskHelper.getMessage("warn.unused.services",
+                                                  toString(names)));
+            }
+
+            String msg = String.format("%n%s:", taskHelper.getMessage("suggested.providers.header"));
+            printProviders(log, msg, mrefs, uses);
+        }
+    }
+
+    private static String toString(Collection<String> collection) {
+        return collection.stream().sorted()
+                         .collect(Collectors.joining(","));
+    }
+
     private String getSaveOpts() {
         StringBuilder sb = new StringBuilder();
         sb.append('#').append(new Date()).append("\n");
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java	Thu Mar 30 19:55:04 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -46,6 +46,7 @@
 import java.util.MissingResourceException;
 import java.util.ResourceBundle;
 import java.util.Set;
+import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import jdk.tools.jlink.internal.plugins.ExcludeJmodSectionPlugin;
@@ -101,8 +102,15 @@
         final boolean hidden;
         final String name;
         final String shortname;
+        final boolean terminalOption;
 
-        public Option(boolean hasArg, Processing<T> processing, boolean hidden, String name, String shortname) {
+        public Option(boolean hasArg,
+                      Processing<T> processing,
+                      boolean hidden,
+                      String name,
+                      String shortname,
+                      boolean isTerminal)
+        {
             if (!name.startsWith("--")) {
                 throw new RuntimeException("option name missing --, " + name);
             }
@@ -115,24 +123,33 @@
             this.hidden = hidden;
             this.name = name;
             this.shortname = shortname;
+            this.terminalOption = isTerminal;
+        }
+
+        public Option(boolean hasArg, Processing<T> processing, String name, String shortname, boolean isTerminal) {
+            this(hasArg, processing, false, name, shortname, isTerminal);
         }
 
         public Option(boolean hasArg, Processing<T> processing, String name, String shortname) {
-            this(hasArg, processing, false, name, shortname);
+            this(hasArg, processing, false, name, shortname, false);
         }
 
         public Option(boolean hasArg, Processing<T> processing, boolean hidden, String name) {
-            this(hasArg, processing, hidden, name, "");
+            this(hasArg, processing, hidden, name, "", false);
         }
 
         public Option(boolean hasArg, Processing<T> processing, String name) {
-            this(hasArg, processing, false, name, "");
+            this(hasArg, processing, false, name, "", false);
         }
 
         public boolean isHidden() {
             return hidden;
         }
 
+        public boolean isTerminal() {
+            return terminalOption;
+        }
+
         public boolean matches(String opt) {
             return opt.equals(name) ||
                    opt.equals(shortname) ||
@@ -179,12 +196,12 @@
     private static class PluginOption extends Option<PluginsHelper> {
         public PluginOption(boolean hasArg,
                 Processing<PluginsHelper> processing, boolean hidden, String name, String shortname) {
-            super(hasArg, processing, hidden, name, shortname);
+            super(hasArg, processing, hidden, name, shortname, false);
         }
 
         public PluginOption(boolean hasArg,
                 Processing<PluginsHelper> processing, boolean hidden, String name) {
-            super(hasArg, processing, hidden, name, "");
+            super(hasArg, processing, hidden, name, "", false);
         }
 
         public String resourcePrefix() {
@@ -498,21 +515,13 @@
             return null;
         }
 
-        // used by jimage. Return unhandled arguments like "create", "describe".
+        /**
+         * Handles all options.  This method stops processing the argument
+         * at the first non-option argument i.e. not starts with `-`, or
+         * at the first terminal option and returns the remaining arguments,
+         * if any.
+         */
         public List<String> handleOptions(T task, String[] args) throws BadArgs {
-            return handleOptions(task, args, true);
-        }
-
-        // used by jlink. No unhandled arguments like "create", "describe".
-        void handleOptionsNoUnhandled(T task, String[] args) throws BadArgs {
-            handleOptions(task, args, false);
-        }
-
-        // shared code that handles options for both jlink and jimage. jimage uses arguments like
-        // "create", "describe" etc. as "task names". Those arguments are unhandled here and returned
-        // as "unhandled arguments list". jlink does not want such arguments. "collectUnhandled" flag
-        // tells whether to allow for unhandled arguments or not.
-        private List<String> handleOptions(T task, String[] args, boolean collectUnhandled) throws BadArgs {
             // findbugs warning, copy instead of keeping a reference.
             command = Arrays.copyOf(args, args.length);
 
@@ -521,7 +530,6 @@
             // Unit tests can call Task multiple time in same JVM.
             pluginOptions = new PluginsHelper(null);
 
-            List<String> rest = collectUnhandled? new ArrayList<>() : null;
             // process options
             for (int i = 0; i < args.length; i++) {
                 if (args[i].startsWith("-")) {
@@ -531,7 +539,6 @@
                     if (option == null) {
                         pluginOption = pluginOptions.getOption(name);
                         if (pluginOption == null) {
-
                             throw new BadArgs("err.unknown.option", name).
                                     showUsage(true);
                         }
@@ -556,20 +563,23 @@
                         pluginOption.process(pluginOptions, name, param);
                     } else {
                         option.process(task, name, param);
+                        if (option.isTerminal()) {
+                            return ++i < args.length
+                                        ? Stream.of(Arrays.copyOfRange(args, i, args.length))
+                                                .collect(Collectors.toList())
+                                        : Collections.emptyList();
+
+                        }
                     }
                     if (opt.ignoreRest()) {
                         i = args.length;
                     }
                 } else {
-                    if (collectUnhandled) {
-                        rest.add(args[i]);
-                    } else {
-                        throw new BadArgs("err.orphan.argument", args[i]).
-                            showUsage(true);
-                    }
+                    return Stream.of(Arrays.copyOfRange(args, i, args.length))
+                                 .collect(Collectors.toList());
                 }
             }
-            return rest;
+            return Collections.emptyList();
         }
 
         private Option<T> getOption(String name) {
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/packager/AppRuntimeImageBuilder.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/packager/AppRuntimeImageBuilder.java	Thu Mar 30 19:55:04 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,6 +34,7 @@
 import java.io.File;
 import java.io.IOException;
 import java.lang.module.ModuleFinder;
+import java.nio.ByteOrder;
 import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -93,9 +94,12 @@
 
     public void build() throws IOException {
         // jlink main arguments
-        Jlink.JlinkConfiguration jlinkConfig = new Jlink.JlinkConfiguration(
-            new File("").toPath(), // Unused
-            modulePath, addModules, limitModules);
+        Jlink.JlinkConfiguration jlinkConfig =
+            new Jlink.JlinkConfiguration(new File("").toPath(), // Unused
+                                         modulePath,
+                                         addModules,
+                                         limitModules,
+                                         ByteOrder.nativeOrder());
 
         // plugin configuration
         List<Plugin> plugins = new ArrayList<Plugin>();
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties	Thu Mar 30 19:55:04 2017 +0200
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -24,15 +24,12 @@
 #
 
 main.usage.summary=\
-Usage: {0} <options> --module-path <modulepath> --add-modules <mods> --output\n\
-\<path> use --help for a list of possible options
+Usage: {0} <options> --module-path <modulepath> --add-modules <module>[,<module>...]\n\
+\Use --help for a list of possible options
 
 main.usage=\
-Usage: {0} <options> --module-path <modulepath> --add-modules <mods> --output\n\
-\<path> Possible options include:
-
-error.prefix=Error:
-warn.prefix=Warning:
+Usage: {0} <options> --module-path <modulepath> --add-modules <module>[,<module>...]\n\
+\Possible options include:
 
 main.opt.help=\
 \  -h, --help                            Print this help message
@@ -54,9 +51,18 @@
 \      --output <path>                   Location of output path
 
 main.opt.launcher=\
-\      --launcher <command>=<module>     Launcher command name for the module\n\
-\      --launcher <command>=<module>/<main>\n\
-\                                        Launcher command name for the module and the main class
+\      --launcher <name>=<module>[/<mainclass>]\n\
+\                                        Add a launcher command of the given\n\
+\                                        name for the module and the main class\n\
+\                                        if specified  
+
+main.opt.bind-services=\
+\      --bind-services                   Do full service binding
+
+main.opt.suggest-providers=\
+\      --suggest-providers [<name>,...]  Suggest providers of services used by\n\
+\                                        the modules that would be linked, or\n\
+\                                        of the given service types
 
 main.command.files=\
 \      @<filename>                       Read options from file
@@ -75,6 +81,9 @@
 \                                        signed modular JARs are not copied to\n\
 \                                        the runtime image.
 
+main.opt.verbose=\
+\  -v, --verbose                         Enable verbose tracing
+
 main.msg.bug=\
 An exception has occurred in jlink. \
 Please file a bug at the Java Bug Database (http://bugreport.java.com/bugreport/) \
@@ -95,6 +104,9 @@
 \n\
 
 
+error.prefix=Error:
+warn.prefix=Warning:
+
 err.unknown.byte.order:unknown byte order {0}
 err.launcher.main.class.empty:launcher main class name cannot be empty: {0}
 err.launcher.module.name.empty:launcher module name cannot be empty: {0}
@@ -111,12 +123,12 @@
 err.dir.exists={0} already exists
 err.badpattern=bad pattern {0}
 err.unknown.option=unknown option: {0}
-err.orphan.argument=orphan argument: {0}
 err.missing.arg=no value given for {0}
 err.internal.error=internal error: {0} {1} {2}
 err.invalid.arg.for.option=invalid argument for option: {0}
 err.option.after.class=option must be specified before classes: {0}
 err.option.unsupported={0} not supported: {1}
+err.orphan.arguments=invalid argument: {0}
 err.config.defaults=property {0} is missing from configuration
 err.config.defaults.value=wrong value in defaults property: {0}
 err.bom.generation=bom file generation failed: {0}
@@ -126,3 +138,7 @@
 warn.signing=WARNING: signed modular JAR {0} is currently not supported
 warn.invalid.arg=invalid classname or pathname not exist: {0}
 warn.split.package=package {0} defined in {1} {2}
+warn.unused.services=Services specified in --suggest-providers not used: {0}
+no.suggested.providers=--bind-services option is specified. No additional providers suggested.
+suggested.providers.header=Suggested providers
+providers.header=Providers
--- a/jdk/src/jdk.jlink/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/jdk.jlink/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -23,6 +23,12 @@
  * questions.
  */
 
+/**
+ * Defines the Java linker tool, jlink.
+ *
+ * @moduleGraph
+ * @since 9
+ */
 module jdk.jlink {
     requires jdk.internal.opt;
     requires jdk.jdeps;
--- a/jdk/src/jdk.jsobject/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/jdk.jsobject/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -23,6 +23,12 @@
  * questions.
  */
 
+/**
+ * Defines the API for the JavaScript Object.
+ *
+ * @moduleGraph
+ * @since 9
+ */
 module jdk.jsobject {
     requires java.desktop;
     exports netscape.javascript;
--- a/jdk/src/jdk.jstatd/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/jdk.jstatd/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -23,6 +23,13 @@
  * questions.
  */
 
+/**
+ * Defines the tool for starting a daemon for the jstat tool to monitor
+ * JVM statistics remotely.
+ *
+ * @moduleGraph
+ * @since 9
+ */
 module jdk.jstatd {
     requires java.rmi;
     requires jdk.internal.jvmstat;
@@ -32,4 +39,3 @@
 
     provides sun.jvmstat.monitor.MonitoredHostService with sun.jvmstat.perfdata.monitor.protocol.rmi.MonitoredHostRmiService;
 }
-
--- a/jdk/src/jdk.localedata/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/jdk.localedata/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -23,6 +23,12 @@
  * questions.
  */
 
+/**
+ * Locale data provider for locales other than {@linkplain java.util.Locale#US US locale}.
+ *
+ * @moduleGraph
+ * @since 9
+ */
 module jdk.localedata {
     provides sun.util.locale.provider.LocaleDataMetaInfo with
         sun.util.resources.cldr.provider.CLDRLocaleDataMetaInfo,
--- a/jdk/src/jdk.management.agent/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/jdk.management.agent/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -23,6 +23,12 @@
  * questions.
  */
 
+/**
+ * Define the JMX management agent.
+ *
+ * @moduleGraph
+ * @since 9
+ */
 module jdk.management.agent {
     requires java.management;
     requires java.management.rmi;
--- a/jdk/src/jdk.management/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/jdk.management/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -23,6 +23,12 @@
  * questions.
  */
 
+/**
+ * Defines the JDK-specific Management Interfaces for JVM.
+ *
+ * @moduleGraph
+ * @since 9
+ */
 module jdk.management {
     requires transitive java.management;
 
--- a/jdk/src/jdk.naming.dns/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/jdk.naming.dns/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -23,6 +23,12 @@
  * questions.
  */
 
+/**
+ * DNS Java Naming provider.
+ *
+ * @moduleGraph
+ * @since 9
+ */
 module jdk.naming.dns {
     requires java.naming;
 
--- a/jdk/src/jdk.naming.rmi/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/jdk.naming.rmi/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -23,6 +23,12 @@
  * questions.
  */
 
+/**
+ * RMI Java Naming provider.
+ *
+ * @moduleGraph
+ * @since 9
+ */
 module jdk.naming.rmi {
     requires java.naming;
     requires java.rmi;
--- a/jdk/src/jdk.net/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/jdk.net/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -23,6 +23,12 @@
  * questions.
  */
 
+/**
+ * Defines the JDK-specific Networking API.
+ *
+ * @moduleGraph
+ * @since 9
+ */
 module jdk.net {
     exports jdk.net;
 }
--- a/jdk/src/jdk.sctp/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/jdk.sctp/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -23,6 +23,12 @@
  * questions.
  */
 
+/**
+ * Defines the JDK-specific API for SCTP.
+ *
+ * @moduleGraph
+ * @since 9
+ */
 module jdk.sctp {
     exports com.sun.nio.sctp;
 }
--- a/jdk/src/jdk.security.auth/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/jdk.security.auth/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -27,6 +27,7 @@
  * Contains the implementation of the javax.security.auth.* interfaces and
  * various authentication modules.
  *
+ * @moduleGraph
  * @since 9
  */
 module jdk.security.auth {
--- a/jdk/src/jdk.security.jgss/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/jdk.security.jgss/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -27,6 +27,7 @@
  * Defines Java extensions to the GSS-API and an implementation of the SASL
  * GSSAPI mechanism.
  *
+ * @moduleGraph
  * @since 9
  */
 module jdk.security.jgss {
--- a/jdk/src/jdk.zipfs/share/classes/module-info.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/src/jdk.zipfs/share/classes/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -23,6 +23,12 @@
  * questions.
  */
 
+/**
+ * Zip file system provider.
+ *
+ * @moduleGraph
+ * @since 9
+ */
 module jdk.zipfs {
     provides java.nio.file.spi.FileSystemProvider with jdk.nio.zipfs.ZipFileSystemProvider;
 }
--- a/jdk/test/ProblemList.txt	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/test/ProblemList.txt	Thu Mar 30 19:55:04 2017 +0200
@@ -180,8 +180,6 @@
 
 java/nio/channels/DatagramChannel/ChangingAddress.java          7141822 macosx-all
 
-java/nio/channels/Selector/OutOfBand.java                       7132677 macosx-all
-
 java/nio/file/WatchService/Basic.java                           7158947 solaris-all Solaris 11
 java/nio/file/WatchService/MayFlies.java                        7158947 solaris-all Solaris 11
 java/nio/file/WatchService/LotsOfEvents.java                    7158947 solaris-all Solaris 11
--- a/jdk/test/TEST.groups	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/test/TEST.groups	Thu Mar 30 19:55:04 2017 +0200
@@ -73,6 +73,7 @@
     jdk/internal/misc \
     jdk/internal/ref \
     jdk/internal/jimage \
+    jdk/internal/math \
     jdk/modules \
     vm
 
@@ -141,8 +142,7 @@
     java/util/stream
 
 jdk_math = \
-    java/math \
-    jdk/internal/math
+    java/math
 
 jdk_io = \
     java/io
--- a/jdk/test/java/nio/channels/DatagramChannel/NetworkConfiguration.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/test/java/nio/channels/DatagramChannel/NetworkConfiguration.java	Thu Mar 30 19:55:04 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -57,22 +57,11 @@
         return ip6Interfaces.get(nif);
     }
 
-    // IPv6 not supported for Windows XP/Server 2003
-    static boolean isIPv6Supported() {
-        if (System.getProperty("os.name").startsWith("Windows")) {
-            String ver = System.getProperty("os.version");
-            int major = Integer.parseInt(ver.split("\\.")[0]);
-            return (major >= 6);
-        }
-        return true;
-    }
-
     static NetworkConfiguration probe() throws IOException {
         Map<NetworkInterface,List<InetAddress>> ip4Interfaces =
             new HashMap<NetworkInterface,List<InetAddress>>();
         Map<NetworkInterface,List<InetAddress>> ip6Interfaces =
             new HashMap<NetworkInterface,List<InetAddress>>();
-        boolean isIPv6Supported = isIPv6Supported();
 
         // find the interfaces that support IPv4 and IPv6
         List<NetworkInterface> nifs = Collections
@@ -92,7 +81,7 @@
                         }
                         list.add(addr);
                         ip4Interfaces.put(nif, list);
-                    } else if (isIPv6Supported && (addr instanceof Inet6Address)) {
+                    } else if (addr instanceof Inet6Address) {
                         List<InetAddress> list = ip6Interfaces.get(nif);
                         if (list == null) {
                             list = new LinkedList<InetAddress>();
--- a/jdk/test/java/nio/channels/FileChannel/Transfer4GBFile.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/test/java/nio/channels/FileChannel/Transfer4GBFile.java	Thu Mar 30 19:55:04 2017 +0200
@@ -52,11 +52,6 @@
     // Test transferTo with large file
     @Test
     public void xferTest04() throws Exception { // for bug 4638365
-        // Windows and Linux can't handle the really large file sizes for a
-        // truncate or a positional write required by the test for 4563125
-        String osName = System.getProperty("os.name");
-        if (!(osName.startsWith("SunOS") || osName.contains("OS X")))
-            return;
         File source = File.createTempFile("blah", null);
         source.deleteOnExit();
         long testSize = ((long)Integer.MAX_VALUE) * 2;
--- a/jdk/test/java/nio/channels/FileChannel/TransferTo6GBFile.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/test/java/nio/channels/FileChannel/TransferTo6GBFile.java	Thu Mar 30 19:55:04 2017 +0200
@@ -50,11 +50,6 @@
     // Test transferTo with file positions larger than 2 and 4GB
     @Test
     public void xferTest08() throws Exception { // for bug 6253145
-        // Creating a sparse 6GB file on Windows takes too long
-        String osName = System.getProperty("os.name");
-        if (osName.startsWith("Windows"))
-            return;
-
         final long G = 1024L * 1024L * 1024L;
 
         // Create 6GB file
--- a/jdk/test/java/nio/channels/Selector/OutOfBand.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/test/java/nio/channels/Selector/OutOfBand.java	Thu Mar 30 19:55:04 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,9 @@
 
 /* @test
  * @bug 6213702
+ * @requires (os.family != "mac") | (os.version == "10.10.5")
+ *    | (os.simpleVersion != "10.8" & os.simpleVersion != "10.9"
+ *        & os.simpleVersion != "10.10")
  * @summary OOB data causes a SocketChannel, with OOBINLINE disabled, to be
  *    selected
  */
--- a/jdk/test/java/nio/channels/Selector/SelectorLimit.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/test/java/nio/channels/Selector/SelectorLimit.java	Thu Mar 30 19:55:04 2017 +0200
@@ -66,15 +66,6 @@
     static final int MIN_KEYS = 100;
 
     public static void main(String[] args) throws Exception {
-        // win9X can't handle many connections at once
-        String osName = System.getProperty("os.name");
-        if (osName.toLowerCase().startsWith("win")) {
-            if (!(osName.equals("Windows NT")
-                  || osName.equals("Windows 2000")
-                  || osName.equals("Windows XP")))
-                return;
-        }
-
         ServerSocketChannel ssc = ServerSocketChannel.open();
         TestUtil.bind(ssc);
         Listener lth = new Listener(ssc);
--- a/jdk/test/sun/security/tools/keytool/WeakAlg.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/test/sun/security/tools/keytool/WeakAlg.java	Thu Mar 30 19:55:04 2017 +0200
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8171319
+ * @bug 8171319 8177569
  * @summary keytool should print out warnings when reading or generating
   *         cert/cert req using weak algorithms
  * @library /test/lib
@@ -78,7 +78,8 @@
                 .shouldMatch("<b>.*512-bit RSA key.*risk")
                 .shouldContain("512-bit RSA key (weak)");
 
-        // Multiple warnings for multiple cert in -printcert or -list or -exportcert
+        // Multiple warnings for multiple cert in -printcert
+        // or -list or -exportcert
 
         // -certreq, -printcertreq, -gencert
         checkCertReq("a", "", null);
@@ -184,7 +185,7 @@
                 .shouldMatch("The input.*MD5withRSA.*risk")
                 .shouldNotContain("[no]");
 
-        // cert is self-signed cacerts
+        // JDK-8177569: no warning for sigalg of trusted cert
         String weakSigAlgCA = null;
         KeyStore ks = KeyStoreUtil.getCacertsKeyStore();
         if (ks != null) {
@@ -208,12 +209,40 @@
             }
         }
         if (weakSigAlgCA != null) {
+            // The following 2 commands still have a warning on why not using
+            // the -cacerts option directly.
+            kt("-list -keystore " + KeyStoreUtil.getCacerts())
+                    .shouldNotContain("risk");
+            kt("-list -v -keystore " + KeyStoreUtil.getCacerts())
+                    .shouldNotContain("risk");
+
+            // -printcert will always show warnings
+            kt("-printcert -file ca.cert")
+                    .shouldContain("name: " + weakSigAlgCA + " (weak)")
+                    .shouldContain("Warning")
+                    .shouldMatch("The certificate.*" + weakSigAlgCA + ".*risk");
+            kt("-printcert -file ca.cert -trustcacerts") // -trustcacerts useless
+                    .shouldContain("name: " + weakSigAlgCA + " (weak)")
+                    .shouldContain("Warning")
+                    .shouldMatch("The certificate.*" + weakSigAlgCA + ".*risk");
+
+            // Importing with -trustcacerts ignore CA cert's sig alg
             kt("-delete -alias d");
             kt("-importcert -alias d -trustcacerts -file ca.cert", "no")
                     .shouldContain("Certificate already exists in system-wide CA")
+                    .shouldNotContain("risk")
+                    .shouldContain("Do you still want to add it to your own keystore?");
+            kt("-importcert -alias d -trustcacerts -file ca.cert -noprompt")
+                    .shouldNotContain("risk")
+                    .shouldNotContain("[no]");
+
+            // but not without -trustcacerts
+            kt("-delete -alias d");
+            kt("-importcert -alias d -file ca.cert", "no")
+                    .shouldContain("name: " + weakSigAlgCA + " (weak)")
                     .shouldContain("Warning")
                     .shouldMatch("The input.*" + weakSigAlgCA + ".*risk")
-                    .shouldContain("Do you still want to add it to your own keystore?");
+                    .shouldContain("Trust this certificate?");
             kt("-importcert -alias d -file ca.cert -noprompt")
                     .shouldContain("Warning")
                     .shouldMatch("The input.*" + weakSigAlgCA + ".*risk")
@@ -266,6 +295,26 @@
         // install reply
 
         reStore();
+        certreq("c", "");
+        gencert("a-c", "");
+        kt("-importcert -alias c -file a-c.cert")
+                .shouldContain("Warning")
+                .shouldMatch("Issuer <a>.*MD5withRSA.*risk");
+
+        // JDK-8177569: no warning for sigalg of trusted cert
+        reStore();
+        // Change a into a TrustedCertEntry
+        kt("-exportcert -alias a -file a.cert");
+        kt("-delete -alias a");
+        kt("-importcert -alias a -file a.cert -noprompt");
+        kt("-list -alias a -v")
+                .shouldNotContain("weak")
+                .shouldNotContain("Warning");
+        // This time a is trusted and no warning on its weak sig alg
+        kt("-importcert -alias c -file a-c.cert")
+                .shouldNotContain("Warning");
+
+        reStore();
 
         gencert("a-b", "");
         gencert("b-c", "");
--- a/jdk/test/tools/jlink/IntegrationTest.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/test/tools/jlink/IntegrationTest.java	Thu Mar 30 19:55:04 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,7 @@
 import java.io.FileReader;
 import java.io.IOException;
 import java.io.UncheckedIOException;
+import java.nio.ByteOrder;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
@@ -135,11 +136,6 @@
         }
         System.out.println(jl);
 
-        JlinkConfiguration config
-                = new JlinkConfiguration(null, null, null, null);
-
-        System.out.println(config);
-
         Plugin p = Jlink.newPlugin("toto", Collections.emptyMap(), null);
         if (p != null) {
             throw new Exception("Plugin should be null");
@@ -163,7 +159,7 @@
         Set<String> limits = new HashSet<>();
         limits.add("java.management");
         JlinkConfiguration config = new Jlink.JlinkConfiguration(output,
-                modulePaths, mods, limits, null);
+                modulePaths, mods, limits, ByteOrder.nativeOrder());
 
         List<Plugin> lst = new ArrayList<>();
 
--- a/jdk/test/tools/jlink/JLinkTest.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/test/tools/jlink/JLinkTest.java	Thu Mar 30 19:55:04 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -274,7 +274,7 @@
             String[] userOptions = {"--compress", "2", "foo" };
             String moduleName = "orphanarg1";
             helper.generateDefaultJModule(moduleName, "composite2");
-            helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: orphan argument: foo");
+            helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: invalid argument: foo");
         }
 
         // orphan argument - JDK-8166810
@@ -282,7 +282,7 @@
             String[] userOptions = {"--output", "foo", "bar" };
             String moduleName = "orphanarg2";
             helper.generateDefaultJModule(moduleName, "composite2");
-            helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: orphan argument: bar");
+            helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: invalid argument: bar");
         }
 
         // basic check for --help - JDK-8173717
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jlink/bindservices/BindServices.java	Thu Mar 30 19:55:04 2017 +0200
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.File;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.spi.ToolProvider;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static jdk.testlibrary.Asserts.assertTrue;
+import static jdk.testlibrary.ProcessTools.*;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/**
+ * @test
+ * @bug 8174826
+ * @library /lib/testlibrary
+ * @modules jdk.compiler jdk.jlink
+ * @build BindServices CompilerUtils jdk.testlibrary.ProcessTools
+ * @run testng BindServices
+ */
+
+public class BindServices {
+    private static final String JAVA_HOME = System.getProperty("java.home");
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path MODS_DIR = Paths.get("mods");
+
+    private static final String MODULE_PATH =
+        Paths.get(JAVA_HOME, "jmods").toString() +
+            File.pathSeparator + MODS_DIR.toString();
+
+    // the names of the modules in this test
+    private static String[] modules = new String[] {"m1", "m2", "m3"};
+
+
+    private static boolean hasJmods() {
+        if (!Files.exists(Paths.get(JAVA_HOME, "jmods"))) {
+            System.err.println("Test skipped. NO jmods directory");
+            return false;
+        }
+        return true;
+    }
+
+    /*
+     * Compiles all modules used by the test
+     */
+    @BeforeTest
+    public void compileAll() throws Throwable {
+        if (!hasJmods()) return;
+
+        for (String mn : modules) {
+            Path msrc = SRC_DIR.resolve(mn);
+            assertTrue(CompilerUtils.compile(msrc, MODS_DIR,
+                "--module-source-path", SRC_DIR.toString()));
+        }
+    }
+
+    @Test
+    public void noServiceBinding() throws Throwable {
+        if (!hasJmods()) return;
+
+        Path dir = Paths.get("noServiceBinding");
+
+        // no service binding and does not link m2,m3 providers.
+        JLink.run("--output", dir.toString(),
+                  "--module-path", MODULE_PATH,
+                  "--add-modules", "m1").output();
+
+        testImage(dir, "m1");
+    }
+
+    @Test
+    public void fullServiceBinding() throws Throwable {
+        if (!hasJmods()) return;
+
+        Path dir = Paths.get("fullServiceBinding");
+
+        // full service binding
+        // m2 is a provider used by m1.  During service binding, when m2 is
+        // resolved, m2 uses p2.T that causes m3 to be linked as it is a
+        // provider to p2.T
+        JLink.run("--output", dir.toString(),
+                  "--module-path", MODULE_PATH,
+                  "--add-modules", "m1",
+                  "--bind-services",
+                  "--limit-modules", "m1,m2,m3,java.base");
+
+        testImage(dir, "m1", "m2", "m3");
+    }
+
+    @Test
+    public void testVerbose() throws Throwable {
+        if (!hasJmods()) return;
+
+        Path dir = Paths.get("verbose");
+
+        List<String> output =
+            JLink.run("--output", dir.toString(),
+                      "--module-path", MODULE_PATH,
+                      "--add-modules", "m1",
+                      "--bind-services",
+                      "--verbose",
+                      "--limit-modules", "m1,m2,m3,java.base").output();
+
+        List<String> expected = List.of(
+            "module m1 (" + MODS_DIR.resolve("m1").toUri().toString() + ")",
+            "module m2 (" + MODS_DIR.resolve("m2").toUri().toString() + ")",
+            "module m3 (" + MODS_DIR.resolve("m3").toUri().toString() + ")",
+            "module m1 provides p1.S, used by m1",
+            "module m2 provides p1.S, used by m1",
+            "module m2 provides p2.T, used by m2",
+            "module m3 provides p2.T, used by m2"
+        );
+
+        assertTrue(output.containsAll(expected));
+
+        testImage(dir, "m1", "m2", "m3");
+    }
+
+    /*
+     * Tests the given ${java.home} to only contain the specified modules
+     */
+    private void testImage(Path javaHome, String... modules) throws Throwable {
+        Path java = javaHome.resolve("bin").resolve("java");
+        String[] cmd = Stream.concat(
+            Stream.of(java.toString(), "-m", "m1/p1.Main"),
+            Stream.of(modules)).toArray(String[]::new);
+
+        assertTrue(executeProcess(cmd).outputTo(System.out)
+                                      .errorTo(System.out)
+                                      .getExitValue() == 0);
+    }
+
+    static class JLink {
+        static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink")
+            .orElseThrow(() ->
+                new RuntimeException("jlink tool not found")
+            );
+
+        static JLink run(String... options) {
+            JLink jlink = new JLink();
+            assertTrue(jlink.execute(options) == 0);
+            return jlink;
+        }
+
+        final List<String> output = new ArrayList<>();
+        private int execute(String... options) {
+            System.out.println("jlink " +
+                Stream.of(options).collect(Collectors.joining(" ")));
+
+            StringWriter writer = new StringWriter();
+            PrintWriter pw = new PrintWriter(writer);
+            int rc = JLINK_TOOL.run(pw, pw, options);
+            System.out.println(writer.toString());
+            Stream.of(writer.toString().split("\\v"))
+                  .map(String::trim)
+                  .forEach(output::add);
+            return rc;
+        }
+
+        boolean contains(String s) {
+            return output.contains(s);
+        }
+
+        List<String> output() {
+            return output;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jlink/bindservices/SuggestProviders.java	Thu Mar 30 19:55:04 2017 +0200
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.File;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.spi.ToolProvider;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static jdk.testlibrary.Asserts.assertTrue;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/**
+ * @test
+ * @bug 8174826
+ * @library /lib/testlibrary
+ * @modules jdk.charsets jdk.compiler jdk.jlink
+ * @build SuggestProviders CompilerUtils
+ * @run testng SuggestProviders
+ */
+
+public class SuggestProviders {
+    private static final String JAVA_HOME = System.getProperty("java.home");
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path MODS_DIR = Paths.get("mods");
+
+    private static final String MODULE_PATH =
+        Paths.get(JAVA_HOME, "jmods").toString() +
+        File.pathSeparator + MODS_DIR.toString();
+
+    // the names of the modules in this test
+    private static String[] modules = new String[] {"m1", "m2", "m3"};
+
+
+    private static boolean hasJmods() {
+        if (!Files.exists(Paths.get(JAVA_HOME, "jmods"))) {
+            System.err.println("Test skipped. NO jmods directory");
+            return false;
+        }
+        return true;
+    }
+
+    /*
+     * Compiles all modules used by the test
+     */
+    @BeforeTest
+    public void compileAll() throws Throwable {
+        if (!hasJmods()) return;
+
+        for (String mn : modules) {
+            Path msrc = SRC_DIR.resolve(mn);
+            assertTrue(CompilerUtils.compile(msrc, MODS_DIR,
+                "--module-source-path", SRC_DIR.toString()));
+        }
+    }
+
+    @Test
+    public void suggestProviders() throws Throwable {
+        if (!hasJmods()) return;
+
+        List<String> output = JLink.run("--module-path", MODULE_PATH,
+                                        "--add-modules", "m1",
+                                        "--suggest-providers").output();
+        // check a subset of services used by java.base
+        List<String> expected = List.of(
+            "uses java.lang.System$LoggerFinder",
+            "uses java.net.ContentHandlerFactory",
+            "uses java.net.spi.URLStreamHandlerProvider",
+            "uses java.nio.channels.spi.AsynchronousChannelProvider",
+            "uses java.nio.channels.spi.SelectorProvider",
+            "uses java.nio.charset.spi.CharsetProvider",
+            "uses java.nio.file.spi.FileSystemProvider",
+            "uses java.nio.file.spi.FileTypeDetector",
+            "uses java.security.Provider",
+            "uses java.util.spi.ToolProvider",
+            "uses p1.S",
+            "module jdk.charsets provides java.nio.charset.spi.CharsetProvider, used by java.base",
+            "module jdk.compiler provides java.util.spi.ToolProvider, used by java.base",
+            "module jdk.jlink provides java.util.spi.ToolProvider, used by java.base",
+            "module m1 provides p1.S, used by m1",
+            "module m2 provides p1.S, used by m1"
+        );
+
+        assertTrue(output.containsAll(expected));
+    }
+
+    @Test
+    public void providersForServices() throws Throwable {
+        if (!hasJmods()) return;
+
+        List<String> output =
+            JLink.run("--module-path", MODULE_PATH,
+                      "--add-modules", "m1",
+                      "--suggest-providers",
+                      "java.nio.charset.spi.CharsetProvider,p1.S,p2.T").output();
+
+        System.out.println(output);
+        List<String> expected = List.of(
+            "module jdk.charsets provides java.nio.charset.spi.CharsetProvider, used by java.base",
+            "module m1 provides p1.S, used by m1",
+            "module m2 provides p1.S, used by m1",
+            "module m2 provides p2.T, used by m2",
+            "module m3 provides p2.T, used by m2"
+        );
+
+        assertTrue(output.containsAll(expected));
+    }
+
+    @Test
+    public void unusedService() throws Throwable {
+        if (!hasJmods()) return;
+
+        List<String> output =
+            JLink.run("--module-path", MODULE_PATH,
+                "--add-modules", "m1",
+                "--suggest-providers",
+                "nonExistentType").output();
+
+        System.out.println(output);
+        List<String> expected = List.of(
+            "Services specified in --suggest-providers not used: nonExistentType"
+        );
+
+        assertTrue(output.containsAll(expected));
+    }
+
+    @Test
+    public void noSuggestProviders() throws Throwable {
+        if (!hasJmods()) return;
+
+        List<String> output =
+            JLink.run("--module-path", MODULE_PATH,
+                      "--add-modules", "m1",
+                      "--bind-services",
+                      "--limit-modules", "m1,m2,m3,java.base",
+                      "--suggest-providers").output();
+
+        String expected = "--bind-services option is specified. No additional providers suggested.";
+        assertTrue(output.contains(expected));
+
+    }
+
+    static class JLink {
+        static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink")
+            .orElseThrow(() ->
+                new RuntimeException("jlink tool not found")
+            );
+
+        static JLink run(String... options) {
+            JLink jlink = new JLink();
+            assertTrue(jlink.execute(options) == 0);
+            return jlink;
+        }
+
+        final List<String> output = new ArrayList<>();
+        private int execute(String... options) {
+            System.out.println("jlink " +
+                Stream.of(options).collect(Collectors.joining(" ")));
+
+            StringWriter writer = new StringWriter();
+            PrintWriter pw = new PrintWriter(writer);
+            int rc = JLINK_TOOL.run(pw, pw, options);
+            System.out.println(writer.toString());
+            Stream.of(writer.toString().split("\\v"))
+                  .map(String::trim)
+                  .forEach(output::add);
+            return rc;
+        }
+
+        boolean contains(String s) {
+            return output.contains(s);
+        }
+
+        List<String> output() {
+            return output;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jlink/bindservices/src/m1/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m1 {
+    exports p1;
+    uses p1.S;
+    provides p1.S with p1.Impl;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jlink/bindservices/src/m1/p1/Impl.java	Thu Mar 30 19:55:04 2017 +0200
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p1;
+
+public class Impl implements S {
+    public String name() {
+        return this.getClass().getName();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jlink/bindservices/src/m1/p1/Main.java	Thu Mar 30 19:55:04 2017 +0200
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package p1;
+
+import java.lang.module.ModuleFinder;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * This tests if JAVA_HOME is linked only with the specified modules.
+ */
+public class Main {
+    public static void main(String... args) {
+        Set<String> modules = ModuleFinder.ofSystem().findAll().stream()
+            .map(mref -> mref.descriptor().name())
+            .filter(mn -> !mn.equals("java.base"))
+            .collect(Collectors.toSet());
+
+        Set<String> notLinked = Stream.of(args).filter(mn -> !modules.contains(mn))
+                                      .collect(Collectors.toSet());
+        if (!notLinked.isEmpty()) {
+            throw new RuntimeException("Expected modules not linked in the image: "
+                + notLinked);
+        }
+        Stream.of(args).forEach(modules::remove);
+
+        if (!modules.isEmpty()) {
+            throw new RuntimeException("Unexpected modules linked in the image: "
+                + modules);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jlink/bindservices/src/m1/p1/S.java	Thu Mar 30 19:55:04 2017 +0200
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p1;
+
+public interface S {
+    String name();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jlink/bindservices/src/m2/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m2 {
+    requires m1;
+    exports p2;
+    uses p2.T;
+    provides p1.S with p2.Impl;
+    provides p2.T with p2.Impl;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jlink/bindservices/src/m2/p2/Impl.java	Thu Mar 30 19:55:04 2017 +0200
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p2;
+
+public class Impl implements p1.S, T {
+    public String name() {
+        return this.getClass().getName();
+    }
+
+    public void run() {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jlink/bindservices/src/m2/p2/T.java	Thu Mar 30 19:55:04 2017 +0200
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p2;
+
+public interface T {
+    void run();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jlink/bindservices/src/m3/module-info.java	Thu Mar 30 19:55:04 2017 +0200
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m3 {
+    requires m2;
+    provides p2.T with p3.Impl;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jlink/bindservices/src/m3/p3/Impl.java	Thu Mar 30 19:55:04 2017 +0200
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p3;
+
+public class Impl implements p2.T {
+    public void run() {
+    }
+}
--- a/jdk/test/tools/launcher/modules/permit/PermitIllegalAccess.java	Sat Mar 25 00:31:29 2017 +0100
+++ b/jdk/test/tools/launcher/modules/permit/PermitIllegalAccess.java	Thu Mar 30 19:55:04 2017 +0200
@@ -29,7 +29,10 @@
  * @summary Basic test for java --permit-illegal-access
  */
 
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
+import java.util.stream.Stream;
 
 import jdk.testlibrary.ProcessTools;
 import jdk.testlibrary.OutputAnalyzer;
@@ -58,10 +61,13 @@
      * Launches AttemptAccess to execute an action, returning the OutputAnalyzer
      * to analyze the output/exitCode.
      */
-    private OutputAnalyzer tryAction(String action, int count) throws Exception {
-        String arg = "" + count;
-        return ProcessTools
-                .executeTestJava("-cp", TEST_CLASSES, TEST_MAIN, action, arg)
+    private OutputAnalyzer tryAction(String action, int count, String... args)
+        throws Exception
+    {
+        Stream<String> s1 = Stream.of(args);
+        Stream<String> s2 = Stream.of("-cp", TEST_CLASSES, TEST_MAIN, action, "" + count);
+        String[] opts = Stream.concat(s1, s2).toArray(String[]::new);
+        return ProcessTools.executeTestJava(opts)
                 .outputTo(System.out)
                 .errorTo(System.out);
     }
@@ -70,16 +76,10 @@
      * Launches AttemptAccess with --permit-illegal-access to execute an action,
      * returning the OutputAnalyzer to analyze the output/exitCode.
      */
-    private OutputAnalyzer tryActionPermittingIllegalAccess(String action,
-                                                            int count)
+    private OutputAnalyzer tryActionPermittingIllegalAccess(String action, int count)
         throws Exception
     {
-        String arg = "" + count;
-        return ProcessTools
-                .executeTestJava("-cp", TEST_CLASSES, "--permit-illegal-access",
-                                 TEST_MAIN, action, arg)
-                .outputTo(System.out)
-                .errorTo(System.out);
+        return tryAction(action, count, "--permit-illegal-access");
     }
 
     /**
@@ -195,6 +195,61 @@
     }
 
     /**
+     * Permit access to succeed with --add-exports. No warning should be printed.
+     */
+    public void testAccessWithAddExports() throws Exception {
+        tryAction("access", 1, "--add-exports", "java.base/sun.security.x509=ALL-UNNAMED")
+                .stdoutShouldNotContain(WARNING)
+                .stdoutShouldNotContain("IllegalAccessException")
+                .stderrShouldNotContain(WARNING)
+                .stderrShouldNotContain("IllegalAccessException")
+                .shouldHaveExitValue(0);
+    }
+
+    /**
+     * Permit access to succeed with --add-exports and --permit-illegal-access.
+     * The only warning emitted should be the startup warning.
+     */
+    public void testAccessWithePermittedAddExports() throws Exception {
+        tryAction("access", 1, "--permit-illegal-access",
+                    "--add-exports", "java.base/sun.security.x509=ALL-UNNAMED")
+                .stdoutShouldNotContain(WARNING)
+                .stdoutShouldNotContain("IllegalAccessException")
+                .stderrShouldContain(STARTUP_WARNING)
+                .stderrShouldNotContain("IllegalAccessException")
+                .stderrShouldNotContain(ILLEGAL_ACCESS_WARNING)
+                .shouldHaveExitValue(0);
+    }
+
+    /**
+     * Permit setAccessible to succeed with --add-opens. No warning should be printed.
+     */
+    public void testSetAccessibleWithAddOpens() throws Exception {
+        tryAction("setAccessible", 1, "--add-opens", "java.base/java.lang=ALL-UNNAMED")
+                .stdoutShouldNotContain(WARNING)
+                .stdoutShouldNotContain("InaccessibleObjectException")
+                .stderrShouldNotContain(WARNING)
+                .stderrShouldNotContain("InaccessibleObjectException")
+                .shouldHaveExitValue(0);
+    }
+
+    /**
+     * Permit setAccessible to succeed with both --add-opens and --permit-illegal-access.
+     * The only warning emitted should be the startup warning.
+     */
+    public void testSetAccessiblePermittedWithAddOpens() throws Exception {
+        tryAction("setAccessible", 1, "--permit-illegal-access",
+                    "--add-opens", "java.base/java.lang=ALL-UNNAMED")
+                .stdoutShouldNotContain(WARNING)
+                .stdoutShouldNotContain("InaccessibleObjectException")
+                .stderrShouldContain(STARTUP_WARNING)
+                .stderrShouldNotContain("InaccessibleObjectException")
+                .stderrShouldNotContain(ILLEGAL_ACCESS_WARNING)
+                .shouldHaveExitValue(0);
+    }
+
+
+    /**
      * Returns the number of lines in the given input that contain the
      * given char sequence.
      */