diff --git a/jdk/make/data/docs-resources/specs/resources/jdk-default.css b/jdk/make/data/docs-resources/specs/resources/jdk-default.css
new file mode 100644
index 00000000000..eea78ea539d
--- /dev/null
+++ b/jdk/make/data/docs-resources/specs/resources/jdk-default.css
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+
+body {
+ margin: 2em 2em;
+ font-family: DejaVu Sans, Bitstream Vera Sans, Luxi Sans, Verdana, Arial, Helvetica;
+ font-size: 10pt;
+ line-height: 1.4;
+}
+
+pre, code, tt {
+ font-family: DejaVu Sans Mono, Bitstream Vera Sans Mono, Luxi Mono,
+ Courier New, monospace;
+}
+
+blockquote {
+ margin: 1.5ex 0em 1.5ex 2em;
+}
+
+p {
+ padding: 0pt;
+ margin: 1ex 0em;
+}
+
+p:first-child, pre:first-child { margin-top: 0pt; }
+
+h1 {
+ font-weight: bold;
+ padding: 0pt;
+ margin: 2ex .5ex 1ex 0pt;
+}
+
+h1:first-child, h2:first-child {
+ margin-top: 0ex;
+}
+
+h2 {
+ font-weight: bold;
+ padding: 0pt;
+ margin: 2ex 0pt 1ex 0pt;
+}
+
+h3 {
+ font-weight: bold;
+ padding: 0pt;
+ margin: 1.5ex 0pt 1ex 0pt;
+}
+
+h4 {
+ font-weight: bold;
+ padding: 0pt;
+ margin: 1.5ex 0pt 1ex 0pt;
+}
+
+a:link {
+ color: #437291;
+}
+
+a:visited {
+ color: #666666;
+}
+
+a[href]:hover {
+ color: #e76f00;
+}
+
+a img {
+ border-width: 0px;
+}
+
+img {
+ background: white;
+}
+
+table {
+ border-collapse: collapse;
+ margin-left: 15px;
+ margin-right: 15px;
+}
+
+th, td {
+ padding: 3px;
+ vertical-align: top;
+}
+
+table, th, td {
+ border: 1px solid black;
+}
+
+caption {
+ text-align: left;
+ font-style: italic;
+ text-indent: 15px;
+ margin-bottom:10px;
+}
+
+tr:nth-child(even) {
+ background: #DDD;
+}
+
+tr:nth-child(odd) {
+ background: #FFF;
+}
+
+th {
+ background: #DDF;
+}
diff --git a/jdk/make/mapfiles/libinstrument/mapfile-vers b/jdk/make/mapfiles/libinstrument/mapfile-vers
index 748670139bd..c51a8af2dc7 100644
--- a/jdk/make/mapfiles/libinstrument/mapfile-vers
+++ b/jdk/make/mapfiles/libinstrument/mapfile-vers
@@ -39,6 +39,7 @@ SUNWprivate_1.1 {
Java_sun_instrument_InstrumentationImpl_getObjectSize0;
Java_sun_instrument_InstrumentationImpl_appendToClassLoaderSearch0;
Java_sun_instrument_InstrumentationImpl_setNativeMethodPrefixes;
+ Java_sun_instrument_InstrumentationImpl_loadAgent0;
local:
*;
};
diff --git a/jdk/src/java.base/share/classes/java/lang/ClassLoader.java b/jdk/src/java.base/share/classes/java/lang/ClassLoader.java
index 2f6af4de922..fb9660f6072 100644
--- a/jdk/src/java.base/share/classes/java/lang/ClassLoader.java
+++ b/jdk/src/java.base/share/classes/java/lang/ClassLoader.java
@@ -119,18 +119,24 @@ import sun.security.util.SecurityConstants;
* The Java run-time has the following built-in class loaders:
*
*
- * - Bootstrap class loader.
+ *
Bootstrap class loader.
* It is the virtual machine's built-in class loader, typically represented
* as {@code null}, and does not have a parent.
- * - {@linkplain #getPlatformClassLoader() Platform class loader}.
+ *
{@linkplain #getPlatformClassLoader() Platform class loader}.
* All platform classes are visible to the platform class loader
* that can be used as the parent of a {@code ClassLoader} instance.
* Platform classes include Java SE platform APIs, their implementation
* classes and JDK-specific run-time classes that are defined by the
- * platform class loader or its ancestors.
- * - {@linkplain #getSystemClassLoader() System class loader}.
- * It is also known as application class
- * loader and is distinct from the platform class loader.
+ * platform class loader or its ancestors.
+ *
To allow for upgrading/overriding of modules defined to the platform
+ * class loader, and where classes in the upgraded version link to
+ * classes in modules defined to the application class loader, the
+ * platform class loader may delegate to the application class loader.
+ * In other words, classes in named modules defined to the application
+ * class loader may be visible to the platform class loader.
+ * {@linkplain #getSystemClassLoader() System class loader}.
+ * It is also known as application class loader and is distinct
+ * from the platform class loader.
* The system class loader is typically used to define classes on the
* application class path, module path, and JDK-specific tools.
* The platform class loader is a parent or an ancestor of the system class
@@ -368,6 +374,10 @@ public abstract class ClassLoader {
* Creates a new class loader of the specified name and using the
* specified parent class loader for delegation.
*
+ * @apiNote If the parent is specified as {@code null} (for the
+ * bootstrap class loader) then there is no guarantee that all platform
+ * classes are visible.
+ *
* @param name class loader name; or {@code null} if not named
* @param parent the parent class loader
*
@@ -390,9 +400,12 @@ public abstract class ClassLoader {
* delegation.
*
*
If there is a security manager, its {@link
- * SecurityManager#checkCreateClassLoader()
- * checkCreateClassLoader} method is invoked. This may result in
- * a security exception.
+ * SecurityManager#checkCreateClassLoader() checkCreateClassLoader} method
+ * is invoked. This may result in a security exception.
+ *
+ * @apiNote If the parent is specified as {@code null} (for the
+ * bootstrap class loader) then there is no guarantee that all platform
+ * classes are visible.
*
* @param parent
* The parent class loader
@@ -2206,6 +2219,12 @@ public abstract class ClassLoader {
* this class loader are searched recursively (parent by parent)
* for a {@code Package} of the given name.
*
+ * @apiNote The {@link #getPlatformClassLoader() platform class loader}
+ * may delegate to the application class loader but the application class
+ * loader is not its ancestor. When invoked on the platform class loader,
+ * this method will not find packages defined to the application
+ * class loader.
+ *
* @param name
* The package name
*
@@ -2251,6 +2270,14 @@ public abstract class ClassLoader {
* {@code Package} object of the same package name, each defined by
* a different class loader in the class loader hierarchy.
*
+ * @apiNote The {@link #getPlatformClassLoader() platform class loader}
+ * may delegate to the application class loader. In other words,
+ * packages in modules defined to the application class loader may be
+ * visible to the platform class loader. On the other hand,
+ * the application class loader is not its ancestor and hence
+ * when invoked on the platform class loader, this method will not
+ * return any packages defined to the application class loader.
+ *
* @return The array of {@code Package} objects defined by this
* class loader and its ancestors
*
diff --git a/jdk/src/java.base/share/classes/java/lang/Module.java b/jdk/src/java.base/share/classes/java/lang/Module.java
index 26337d86beb..f6ab49b4519 100644
--- a/jdk/src/java.base/share/classes/java/lang/Module.java
+++ b/jdk/src/java.base/share/classes/java/lang/Module.java
@@ -57,6 +57,7 @@ import jdk.internal.loader.BuiltinClassLoader;
import jdk.internal.loader.BootLoader;
import jdk.internal.misc.JavaLangAccess;
import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.ModuleLoaderMap;
import jdk.internal.module.ServicesCatalog;
import jdk.internal.module.Resources;
import jdk.internal.org.objectweb.asm.AnnotationVisitor;
@@ -215,8 +216,8 @@ public final class Module implements AnnotatedElement {
}
/**
- * Returns the layer that contains this module or {@code null} if this
- * module is not in a layer.
+ * Returns the module layer that contains this module or {@code null} if
+ * this module is not in a module layer.
*
* A module layer contains named modules and therefore this method always
* returns {@code null} when invoked on an unnamed module.
@@ -691,6 +692,13 @@ public final class Module implements AnnotatedElement {
* This method has no effect if the package is already open
* to the given module.
*
+ * @apiNote This method can be used for cases where a consumer
+ * module uses a qualified opens to open a package to an API
+ * module but where the reflective access to the members of classes in
+ * the consumer module is delegated to code in another module. Code in the
+ * API module can use this method to open the package in the consumer module
+ * to the other module.
+ *
* @param pn
* The package name
* @param other
@@ -1077,7 +1085,7 @@ public final class Module implements AnnotatedElement {
if (loader != null) {
moduleToLoader.put(name, loader);
loaders.add(loader);
- } else if (!isBootLayer) {
+ } else if (!(clf instanceof ModuleLoaderMap.Mapper)) {
throw new IllegalArgumentException("loader can't be 'null'");
}
}
@@ -1458,11 +1466,11 @@ public final class Module implements AnnotatedElement {
* encapsulated.
*
* - A package name is derived from the resource name. If
- * the package name is a {@link #getPackages() package} in the module
- * then the resource can only be located by the caller of this method
- * when the package is {@link #isOpen(String,Module) open} to at least
- * the caller's module. If the resource is not in a package in the module
- * then the resource is not encapsulated.
+ * the package name is a {@linkplain #getPackages() package} in the
+ * module then the resource can only be located by the caller of this
+ * method when the package is {@linkplain #isOpen(String,Module) open}
+ * to at least the caller's module. If the resource is not in a
+ * package in the module then the resource is not encapsulated.
*
*
* In the above, the package name for a resource is derived
@@ -1521,8 +1529,7 @@ public final class Module implements AnnotatedElement {
}
// locate resource in module
- JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
- URL url = jla.findResource(loader, mn, name);
+ URL url = loader.findResource(mn, name);
if (url != null) {
try {
return url.openStream();
diff --git a/jdk/src/java.base/share/classes/java/lang/SecurityManager.java b/jdk/src/java.base/share/classes/java/lang/SecurityManager.java
index 098e8626525..b60d63e5f02 100644
--- a/jdk/src/java.base/share/classes/java/lang/SecurityManager.java
+++ b/jdk/src/java.base/share/classes/java/lang/SecurityManager.java
@@ -25,10 +25,10 @@
package java.lang;
-import java.lang.RuntimePermission;
import java.lang.module.ModuleDescriptor;
import java.lang.module.ModuleDescriptor.Exports;
import java.lang.module.ModuleDescriptor.Opens;
+import java.lang.module.ModuleReference;
import java.lang.reflect.Member;
import java.io.FileDescriptor;
import java.io.File;
@@ -42,12 +42,15 @@ import java.security.PrivilegedAction;
import java.security.Security;
import java.security.SecurityPermission;
import java.util.HashSet;
+import java.util.Map;
import java.util.Objects;
import java.util.PropertyPermission;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
-import java.util.stream.Stream;
+import jdk.internal.module.ModuleBootstrap;
+import jdk.internal.module.ModuleLoaderMap;
import jdk.internal.reflect.CallerSensitive;
import sun.security.util.SecurityConstants;
@@ -1431,30 +1434,30 @@ class SecurityManager {
return packages;
}
- // The non-exported packages of the modules in the boot layer that are
- // loaded by the platform class loader or its ancestors. A non-exported
- // package is a package that either is not exported at all by its containing
- // module or is exported in a qualified fashion by its containing module.
- private static final Set nonExportedPkgs;
-
+ // The non-exported packages in modules defined to the boot or platform
+ // class loaders. A non-exported package is a package that is not exported
+ // or is only exported to specific modules.
+ private static final Map nonExportedPkgs = new ConcurrentHashMap<>();
static {
- // Get the modules in the boot layer
- Stream bootLayerModules = ModuleLayer.boot().modules().stream();
-
- // Filter out the modules loaded by the boot or platform loader
- PrivilegedAction> pa = () ->
- bootLayerModules.filter(SecurityManager::isBootOrPlatformModule)
- .collect(Collectors.toSet());
- Set modules = AccessController.doPrivileged(pa);
-
- // Filter out the non-exported packages
- nonExportedPkgs = modules.stream()
- .map(Module::getDescriptor)
- .map(SecurityManager::nonExportedPkgs)
- .flatMap(Set::stream)
- .collect(Collectors.toSet());
+ addNonExportedPackages(ModuleLayer.boot());
}
+ /**
+ * Record the non-exported packages of the modules in the given layer
+ */
+ static void addNonExportedPackages(ModuleLayer layer) {
+ Set bootModules = ModuleLoaderMap.bootModules();
+ Set platformModules = ModuleLoaderMap.platformModules();
+ layer.modules().stream()
+ .map(Module::getDescriptor)
+ .filter(md -> bootModules.contains(md.name())
+ || platformModules.contains(md.name()))
+ .map(SecurityManager::nonExportedPkgs)
+ .flatMap(Set::stream)
+ .forEach(pn -> nonExportedPkgs.put(pn, Boolean.TRUE));
+ }
+
+
/**
* Called by java.security.Security
*/
@@ -1467,14 +1470,6 @@ class SecurityManager {
}
}
- /**
- * Returns true if the module's loader is the boot or platform loader.
- */
- private static boolean isBootOrPlatformModule(Module m) {
- return m.getClassLoader() == null ||
- m.getClassLoader() == ClassLoader.getPlatformClassLoader();
- }
-
/**
* Returns the non-exported packages of the specified module.
*/
@@ -1535,7 +1530,7 @@ class SecurityManager {
Objects.requireNonNull(pkg, "package name can't be null");
// check if pkg is not exported to all modules
- if (nonExportedPkgs.contains(pkg)) {
+ if (nonExportedPkgs.containsKey(pkg)) {
checkPermission(
new RuntimePermission("accessClassInPackage." + pkg));
return;
@@ -1634,7 +1629,7 @@ class SecurityManager {
Objects.requireNonNull(pkg, "package name can't be null");
// check if pkg is not exported to all modules
- if (nonExportedPkgs.contains(pkg)) {
+ if (nonExportedPkgs.containsKey(pkg)) {
checkPermission(
new RuntimePermission("defineClassInPackage." + pkg));
return;
diff --git a/jdk/src/java.base/share/classes/java/lang/System.java b/jdk/src/java.base/share/classes/java/lang/System.java
index edd5b553db1..630380e2d4b 100644
--- a/jdk/src/java.base/share/classes/java/lang/System.java
+++ b/jdk/src/java.base/share/classes/java/lang/System.java
@@ -41,7 +41,6 @@ import java.lang.reflect.Executable;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URI;
-import java.net.URL;
import java.security.AccessControlContext;
import java.security.ProtectionDomain;
import java.security.AccessController;
@@ -2111,9 +2110,6 @@ public final class System {
public Class> findBootstrapClassOrNull(ClassLoader cl, String name) {
return cl.findBootstrapClassOrNull(name);
}
- public URL findResource(ClassLoader cl, String mn, String name) throws IOException {
- return cl.findResource(mn, name);
- }
public Stream packages(ClassLoader cl) {
return cl.packages();
}
@@ -2123,6 +2119,9 @@ public final class System {
public String fastUUID(long lsb, long msb) {
return Long.fastUUID(lsb, msb);
}
+ public void addNonExportedPackages(ModuleLayer layer) {
+ SecurityManager.addNonExportedPackages(layer);
+ }
public void invalidatePackageAccessCache() {
SecurityManager.invalidatePackageAccessCache();
}
diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java
index eceba166e24..47e5aeacb65 100644
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java
@@ -876,9 +876,7 @@ public class MethodHandles {
* accessible to the class. The {@code PACKAGE} lookup mode serves to authenticate
* that the lookup object was created by a caller in the runtime package (or derived
* from a lookup originally created by suitably privileged code to a target class in
- * the runtime package). The lookup modes cannot include {@link #PRIVATE PRIVATE}
- * access. A lookup with {@code PRIVATE} access can be downgraded to drop this lookup
- * mode with the {@linkplain #dropLookupMode(int) dropLookupMode} method.
+ * the runtime package).
*
* The {@code bytes} parameter is the class bytes of a valid class file (as defined
* by the The Java Virtual Machine Specification) with a class name in the
@@ -896,7 +894,6 @@ public class MethodHandles {
* @throws IllegalArgumentException the bytes are for a class in a different package
* to the lookup class
* @throws IllegalAccessException if this lookup does not have {@code PACKAGE} access
- * @throws UnsupportedOperationException if the lookup class has {@code PRIVATE} access
* @throws LinkageError if the class is malformed ({@code ClassFormatError}), cannot be
* verified ({@code VerifyError}), is already defined, or another linkage error occurs
* @throws SecurityException if denied by the security manager
@@ -911,8 +908,6 @@ public class MethodHandles {
SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkPermission(new RuntimePermission("defineClass"));
- if (hasPrivateAccess())
- throw new UnsupportedOperationException("PRIVATE access not supported");
if ((lookupModes() & PACKAGE) == 0)
throw new IllegalAccessException("Lookup does not have PACKAGE access");
assert (lookupModes() & (MODULE|PUBLIC)) != 0;
diff --git a/jdk/src/java.base/share/classes/java/lang/module/Configuration.java b/jdk/src/java.base/share/classes/java/lang/module/Configuration.java
index d5fc16c1ef6..ef7e44a114d 100644
--- a/jdk/src/java.base/share/classes/java/lang/module/Configuration.java
+++ b/jdk/src/java.base/share/classes/java/lang/module/Configuration.java
@@ -109,20 +109,17 @@ public final class Configuration {
private final Set modules;
private final Map nameToModule;
- // module constraints on target
- private final String osName;
- private final String osArch;
+ // constraint on target platform
+ private final String targetPlatform;
- String osName() { return osName; }
- String osArch() { return osArch; }
+ String targetPlatform() { return targetPlatform; }
private Configuration() {
this.parents = Collections.emptyList();
this.graph = Collections.emptyMap();
this.modules = Collections.emptySet();
this.nameToModule = Collections.emptyMap();
- this.osName = null;
- this.osArch = null;
+ this.targetPlatform = null;
}
private Configuration(List parents,
@@ -147,8 +144,7 @@ public final class Configuration {
this.modules = Set.of(moduleArray);
this.nameToModule = Map.ofEntries(nameEntries);
- this.osName = resolver.osName();
- this.osArch = resolver.osArch();
+ this.targetPlatform = resolver.targetPlatform();
}
/**
diff --git a/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java b/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java
index 01b4316fa20..20d198b46ee 100644
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java
@@ -99,6 +99,7 @@ public class ModuleDescriptor
*
* @see ModuleDescriptor#modifiers()
* @since 9
+ * @spec JPMS
*/
public static enum Modifier {
/**
diff --git a/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java b/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java
index 0be9d8d9eff..e0e6d883550 100644
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java
@@ -286,8 +286,9 @@ public interface ModuleFinder {
* class names of provider classes.
*
* If the JAR file has a {@code Main-Class} attribute in its
- * main manifest then its value is the module {@link
- * ModuleDescriptor#mainClass() main class}.
+ * main manifest, its value is a legal class name, and its package is
+ * in the set of packages derived for the module, then the value is the
+ * module {@linkplain ModuleDescriptor#mainClass() main class}.
*
*
*
@@ -298,8 +299,7 @@ public interface ModuleFinder {
* file, where the JAR file contains a {@code .class} in the top-level
* directory of the JAR file, where an entry in a service configuration
* file is not a legal class name or its package name is not in the set of
- * packages derived for the module, or where the module main class is not
- * a legal class name or its package is not in the module.
+ * packages derived for the module.
*
* In addition to JAR files, an implementation may also support modules
* that are packaged in other implementation specific module formats. If
diff --git a/jdk/src/java.base/share/classes/java/lang/module/Resolver.java b/jdk/src/java.base/share/classes/java/lang/module/Resolver.java
index 6adf93f8317..a723e638abe 100644
--- a/jdk/src/java.base/share/classes/java/lang/module/Resolver.java
+++ b/jdk/src/java.base/share/classes/java/lang/module/Resolver.java
@@ -28,6 +28,7 @@ package java.lang.module;
import java.io.PrintStream;
import java.lang.module.ModuleDescriptor.Provides;
import java.lang.module.ModuleDescriptor.Requires.Modifier;
+import java.net.URI;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
@@ -38,10 +39,8 @@ import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
import java.util.Optional;
import java.util.Set;
-import java.util.StringJoiner;
import java.util.stream.Collectors;
import jdk.internal.module.ModuleHashes;
@@ -69,12 +68,10 @@ final class Resolver {
// true if all automatic modules have been found
private boolean haveAllAutomaticModules;
- // module constraints on target platform
- private String osName;
- private String osArch;
+ // constraint on target platform
+ private String targetPlatform;
- String osName() { return osName; }
- String osArch() { return osArch; }
+ String targetPlatform() { return targetPlatform; }
/**
* @throws IllegalArgumentException if there are more than one parent and
@@ -89,37 +86,23 @@ final class Resolver {
this.afterFinder = afterFinder;
this.traceOutput = traceOutput;
- // record constraints on target platform, checking that they don't conflict
+ // record constraint on target platform, checking for conflicts
for (Configuration parent : parents) {
- String value = parent.osName();
+ String value = parent.targetPlatform();
if (value != null) {
- if (osName == null) {
- osName = value;
+ if (targetPlatform == null) {
+ targetPlatform = value;
} else {
- if (!value.equals(osName)) {
- failParentConflict("Operating System", osName, value);
- }
- }
- }
- value = parent.osArch();
- if (value != null) {
- if (osArch == null) {
- osArch = value;
- } else {
- if (!value.equals(osArch)) {
- failParentConflict("OS architecture", osArch, value);
+ if (!value.equals(targetPlatform)) {
+ String msg = "Parents have conflicting constraints on target" +
+ " platform: " + targetPlatform + ", " + value;
+ throw new IllegalArgumentException(msg);
}
}
}
}
}
- private void failParentConflict(String constraint, String s1, String s2) {
- String msg = "Parents have conflicting constraints on target "
- + constraint + ": " + s1 + ", " + s2;
- throw new IllegalArgumentException(msg);
- }
-
/**
* Resolves the given named modules.
*
@@ -147,8 +130,7 @@ final class Resolver {
}
if (isTracing()) {
- trace("Root module %s located", root);
- mref.location().ifPresent(uri -> trace(" (%s)", uri));
+ trace("root %s", nameAndInfo(mref));
}
addFoundModule(mref);
@@ -180,9 +162,7 @@ final class Resolver {
ModuleDescriptor other = mref.descriptor();
q.offer(other);
if (isTracing()) {
- trace("Automatic module %s located, required by %s",
- other.name(), descriptor.name());
- mref.location().ifPresent(uri -> trace(" (%s)", uri));
+ trace("%s requires %s", descriptor.name(), nameAndInfo(mref));
}
});
haveAllAutomaticModules = true;
@@ -213,21 +193,13 @@ final class Resolver {
}
}
+ if (isTracing() && !dn.equals("java.base")) {
+ trace("%s requires %s", descriptor.name(), nameAndInfo(mref));
+ }
+
if (!nameToReference.containsKey(dn)) {
addFoundModule(mref);
q.offer(mref.descriptor());
-
- if (isTracing()) {
- String prefix;
- if (mref.descriptor().isAutomatic()) {
- prefix = "Automatic module";
- } else {
- prefix = "Module";
- }
- trace(prefix + " %s located, required by %s",
- dn, descriptor.name());
- mref.location().ifPresent(uri -> trace(" (%s)", uri));
- }
}
}
@@ -291,6 +263,13 @@ final class Resolver {
do {
for (ModuleDescriptor descriptor : candidateConsumers) {
if (!descriptor.uses().isEmpty()) {
+
+ // the modules that provide at least one service
+ Set modulesToBind = null;
+ if (isTracing()) {
+ modulesToBind = new HashSet<>();
+ }
+
for (String service : descriptor.uses()) {
Set mrefs = availableProviders.get(service);
if (mrefs != null) {
@@ -298,15 +277,13 @@ final class Resolver {
ModuleDescriptor provider = mref.descriptor();
if (!provider.equals(descriptor)) {
- trace("Module %s provides %s, used by %s",
- provider.name(), service, descriptor.name());
+ if (isTracing() && modulesToBind.add(provider)) {
+ trace("%s binds %s", descriptor.name(),
+ nameAndInfo(mref));
+ }
String pn = provider.name();
if (!nameToReference.containsKey(pn)) {
- if (isTracing()) {
- mref.location()
- .ifPresent(uri -> trace(" (%s)", uri));
- }
addFoundModule(mref);
q.push(provider);
}
@@ -349,59 +326,31 @@ final class Resolver {
if (mref instanceof ModuleReferenceImpl) {
ModuleTarget target = ((ModuleReferenceImpl)mref).moduleTarget();
if (target != null)
- checkTargetConstraints(mn, target);
+ checkTargetPlatform(mn, target);
}
nameToReference.put(mn, mref);
}
/**
- * Check that the module's constraints on the target platform do not
- * conflict with the constraints of other modules resolved so far or
- * modules in parent configurations.
+ * Check that the module's constraints on the target platform does
+ * conflict with the constraint of other modules resolved so far.
*/
- private void checkTargetConstraints(String mn, ModuleTarget target) {
- String value = target.osName();
+ private void checkTargetPlatform(String mn, ModuleTarget target) {
+ String value = target.targetPlatform();
if (value != null) {
- if (osName == null) {
- osName = value;
+ if (targetPlatform == null) {
+ targetPlatform = value;
} else {
- if (!value.equals(osName)) {
- failTargetConstraint(mn, target);
- }
- }
- }
- value = target.osArch();
- if (value != null) {
- if (osArch == null) {
- osArch = value;
- } else {
- if (!value.equals(osArch)) {
- failTargetConstraint(mn, target);
+ if (!value.equals(targetPlatform)) {
+ findFail("Module %s has constraints on target platform (%s)"
+ + " that conflict with other modules: %s", mn,
+ value, targetPlatform);
}
}
}
}
- private void failTargetConstraint(String mn, ModuleTarget target) {
- String s1 = targetAsString(osName, osArch);
- String s2 = targetAsString(target.osName(), target.osArch());
- findFail("Module %s has constraints on target platform (%s) that"
- + " conflict with other modules: %s", mn, s1, s2);
- }
-
- private String targetAsString(ModuleTarget target) {
- return targetAsString(target.osName(), target.osArch());
- }
-
- private String targetAsString(String osName, String osArch) {
- return new StringJoiner("-")
- .add(Objects.toString(osName, "*"))
- .add(Objects.toString(osArch, "*"))
- .toString();
- }
-
-
/**
* Execute post-resolution checks and returns the module graph of resolved
* modules as {@code Map}. The resolved modules will be in the given
@@ -412,12 +361,6 @@ final class Resolver {
Map> finish(Configuration cf,
boolean check)
{
- if (isTracing()) {
- trace("Result:");
- Set names = nameToReference.keySet();
- names.stream().sorted().forEach(name -> trace(" %s", name));
- }
-
if (check) {
detectCycles();
checkHashes();
@@ -520,9 +463,8 @@ final class Resolver {
findFail("Unable to compute the hash of module %s", dn);
}
- // skip checking the hash if the module has been patched
ModuleReferenceImpl other = (ModuleReferenceImpl)mref2;
- if (other != null && !other.isPatched()) {
+ if (other != null) {
byte[] recordedHash = hashes.hashFor(dn);
byte[] actualHash = other.computeHash(algorithm);
if (actualHash == null)
@@ -965,9 +907,17 @@ final class Resolver {
private void trace(String fmt, Object ... args) {
if (traceOutput != null) {
- traceOutput.format("[Resolver] " + fmt, args);
+ traceOutput.format(fmt, args);
traceOutput.println();
}
}
+ private String nameAndInfo(ModuleReference mref) {
+ ModuleDescriptor descriptor = mref.descriptor();
+ StringBuilder sb = new StringBuilder(descriptor.name());
+ mref.location().ifPresent(uri -> sb.append(" " + uri));
+ if (descriptor.isAutomatic())
+ sb.append(" automatic");
+ return sb.toString();
+ }
}
diff --git a/jdk/src/java.base/share/classes/java/nio/file/FileSystems.java b/jdk/src/java.base/share/classes/java/nio/file/FileSystems.java
index 08ff1f0d740..2754fa39c0a 100644
--- a/jdk/src/java.base/share/classes/java/nio/file/FileSystems.java
+++ b/jdk/src/java.base/share/classes/java/nio/file/FileSystems.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2015, 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
@@ -36,6 +36,8 @@ import java.util.Map;
import java.util.ServiceConfigurationError;
import java.util.ServiceLoader;
+import jdk.internal.misc.VM;
+
/**
* Factory methods for file systems. This class defines the {@link #getDefault
* getDefault} method to get the default file system and factory methods to
@@ -120,8 +122,8 @@ public final class FileSystems {
// if the property java.nio.file.spi.DefaultFileSystemProvider is
// set then its value is the name of the default provider (or a list)
- String propValue = System
- .getProperty("java.nio.file.spi.DefaultFileSystemProvider");
+ String prop = "java.nio.file.spi.DefaultFileSystemProvider";
+ String propValue = System.getProperty(prop);
if (propValue != null) {
for (String cn: propValue.split(",")) {
try {
@@ -184,7 +186,7 @@ public final class FileSystems {
* @return the default file system
*/
public static FileSystem getDefault() {
- if (jdk.internal.misc.VM.isBooted()) {
+ if (VM.isModuleSystemInited()) {
return DefaultFileSystemHolder.defaultFileSystem;
} else {
return BuiltinFileSystemHolder.builtinFileSystem;
diff --git a/jdk/src/java.base/share/classes/javax/crypto/CipherInputStream.java b/jdk/src/java.base/share/classes/javax/crypto/CipherInputStream.java
index 9c8bc81393a..54ad9611e2d 100644
--- a/jdk/src/java.base/share/classes/javax/crypto/CipherInputStream.java
+++ b/jdk/src/java.base/share/classes/javax/crypto/CipherInputStream.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 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
@@ -93,7 +93,7 @@ public class CipherInputStream extends FilterInputStream {
// stream status
private boolean closed = false;
- /**
+ /*
* private convenience function.
*
* Entry condition: ostart = ofinish
diff --git a/jdk/src/java.base/share/classes/javax/crypto/CryptoPermission.java b/jdk/src/java.base/share/classes/javax/crypto/CryptoPermission.java
index 749e31926fe..ddc2648b693 100644
--- a/jdk/src/java.base/share/classes/javax/crypto/CryptoPermission.java
+++ b/jdk/src/java.base/share/classes/javax/crypto/CryptoPermission.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -196,19 +196,19 @@ class CryptoPermission extends java.security.Permission {
* Checks if the specified permission is "implied" by
* this object.
*
- * More specifically, this method returns true if:
+ * More specifically, this method returns true if:
*
- * - p is an instance of CryptoPermission, and
+ *
- p is an instance of CryptoPermission, and
* - p's algorithm name equals or (in the case of wildcards)
- * is implied by this permission's algorithm name, and
+ * is implied by this permission's algorithm name, and
* - p's maximum allowable key size is less or
- * equal to this permission's maximum allowable key size, and
+ * equal to this permission's maximum allowable key size, and
* - p's algorithm parameter spec equals or is
- * implied by this permission's algorithm parameter spec, and
+ * implied by this permission's algorithm parameter spec, and
* - p's exemptionMechanism equals or
* is implied by this permission's
* exemptionMechanism (a
null
exemption mechanism
- * implies any other exemption mechanism).
+ * implies any other exemption mechanism).
*
*
* @param p the permission to check against.
diff --git a/jdk/src/java.base/share/classes/javax/crypto/CryptoPolicyParser.java b/jdk/src/java.base/share/classes/javax/crypto/CryptoPolicyParser.java
index 7f27ea2506a..0093ce65b6d 100644
--- a/jdk/src/java.base/share/classes/javax/crypto/CryptoPolicyParser.java
+++ b/jdk/src/java.base/share/classes/javax/crypto/CryptoPolicyParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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,10 +46,12 @@ import java.lang.reflect.*;
*
* The format of a permission entry in the jurisdiction policy file is:
*
+ * {@code
* permission [,
* [[, ][,
* [, , ]]]];
+ * }
*
* @author Sharon Liu
*
@@ -526,8 +528,7 @@ final class CryptoPolicyParser {
/**
* Each grant entry in the policy configuration file is represented by a
- * GrantEntry object.
- *
+ * GrantEntry object.
*
* For example, the entry
*
@@ -587,8 +588,7 @@ final class CryptoPolicyParser {
/**
* Each crypto permission entry in the policy configuration file is
- * represented by a CryptoPermissionEntry object.
- *
+ * represented by a CryptoPermissionEntry object.
*
* For example, the entry
*
diff --git a/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java b/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java
index ce3bb67e8dd..5d1c97c6d25 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java
@@ -172,12 +172,10 @@ public class BuiltinClassLoader
}
/**
- * Register a module this this class loader. This has the effect of making
- * the types in the module visible.
+ * Register a module this class loader. This has the effect of making the
+ * types in the module visible.
*/
public void loadModule(ModuleReference mref) {
- assert !VM.isModuleSystemInited();
-
String mn = mref.descriptor().name();
if (nameToModule.putIfAbsent(mn, mref) != null) {
throw new InternalError(mn + " already defined to this loader");
@@ -191,6 +189,11 @@ public class BuiltinClassLoader
+ other.mref().descriptor().name());
}
}
+
+ // clear resources cache if VM is already initialized
+ if (VM.isModuleSystemInited() && resourceCache != null) {
+ resourceCache = null;
+ }
}
/**
@@ -355,7 +358,10 @@ public class BuiltinClassLoader
private List findMiscResource(String name) throws IOException {
SoftReference
*/
public static class ModuleTargetAttribute extends Attribute {
- private final String osName;
- private final String osArch;
+ private final String targetPlatform;
- public ModuleTargetAttribute(String osName, String osArch) {
+ public ModuleTargetAttribute(String targetPlatform) {
super(MODULE_TARGET);
- this.osName = osName;
- this.osArch = osArch;
+ this.targetPlatform = targetPlatform;
}
public ModuleTargetAttribute() {
- this(null, null);
+ this(null);
}
- public String osName() {
- return osName;
- }
-
- public String osArch() {
- return osArch;
+ public String targetPlatform() {
+ return targetPlatform;
}
@Override
@@ -588,20 +580,14 @@ public final class ClassFileAttributes {
Label[] labels)
{
- String osName = null;
- String osArch = null;
+ String targetPlatform = null;
- int name_index = cr.readUnsignedShort(off);
- if (name_index != 0)
- osName = cr.readUTF8(off, buf);
+ int target_platform_index = cr.readUnsignedShort(off);
+ if (target_platform_index != 0)
+ targetPlatform = cr.readUTF8(off, buf);
off += 2;
- int arch_index = cr.readUnsignedShort(off);
- if (arch_index != 0)
- osArch = cr.readUTF8(off, buf);
- off += 2;
-
- return new ModuleTargetAttribute(osName, osArch);
+ return new ModuleTargetAttribute(targetPlatform);
}
@Override
@@ -613,15 +599,10 @@ public final class ClassFileAttributes {
{
ByteVector attr = new ByteVector();
- int name_index = 0;
- if (osName != null && osName.length() > 0)
- name_index = cw.newUTF8(osName);
- attr.putShort(name_index);
-
- int arch_index = 0;
- if (osArch != null && osArch.length() > 0)
- arch_index = cw.newUTF8(osArch);
- attr.putShort(arch_index);
+ int target_platform_index = 0;
+ if (targetPlatform != null && targetPlatform.length() > 0)
+ target_platform_index = cw.newUTF8(targetPlatform);
+ attr.putShort(target_platform_index);
return attr;
}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java
index 061b2294158..d083ead7801 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java
@@ -84,8 +84,9 @@ public final class ModuleBootstrap {
// The ModulePatcher for the initial configuration
private static final ModulePatcher patcher = initModulePatcher();
- // ModuleFinder for the initial configuration
- private static ModuleFinder initialFinder;
+ // ModuleFinders for the initial configuration
+ private static ModuleFinder unlimitedFinder;
+ private static ModuleFinder limitedFinder;
/**
* Returns the ModulePatcher for the initial configuration.
@@ -95,11 +96,20 @@ public final class ModuleBootstrap {
}
/**
- * Returns the ModuleFinder for the initial configuration
+ * Returns the ModuleFinder for the initial configuration before observability
+ * is limited by the --limit-modules command line option.
*/
- public static ModuleFinder finder() {
- assert initialFinder != null;
- return initialFinder;
+ public static ModuleFinder unlimitedFinder() {
+ assert unlimitedFinder != null;
+ return unlimitedFinder;
+ }
+
+ /**
+ * Returns the ModuleFinder for the initial configuration.
+ */
+ public static ModuleFinder limitedFinder() {
+ assert limitedFinder != null;
+ return limitedFinder;
}
/**
@@ -134,6 +144,11 @@ public final class ModuleBootstrap {
PerfCounters.defineBaseTime.addElapsedTimeFrom(t1);
+ // special mode to boot with only java.base, ignores other options
+ String propValue = getAndRemoveProperty("jdk.module.minimumBoot");
+ if (propValue != null) {
+ return createMinimalBootLayer();
+ }
long t2 = System.nanoTime();
@@ -180,7 +195,8 @@ public final class ModuleBootstrap {
}
// --limit-modules
- String propValue = getAndRemoveProperty("jdk.module.limitmods");
+ unlimitedFinder = finder;
+ propValue = getAndRemoveProperty("jdk.module.limitmods");
if (propValue != null) {
Set mods = new HashSet<>();
for (String mod: propValue.split(",")) {
@@ -188,6 +204,7 @@ public final class ModuleBootstrap {
}
finder = limitFinder(finder, mods, roots);
}
+ limitedFinder = finder;
// If there is no initial module specified then assume that the initial
// module is the unnamed module of the application class loader. This
@@ -267,7 +284,8 @@ public final class ModuleBootstrap {
}
PrintStream traceOutput = null;
- if (Boolean.getBoolean("jdk.launcher.traceResolver"))
+ propValue = getAndRemoveProperty("jdk.module.showModuleResolution");
+ if (propValue != null && Boolean.parseBoolean(propValue))
traceOutput = System.out;
// run the resolver to create the configuration
@@ -362,12 +380,23 @@ public final class ModuleBootstrap {
// total time to initialize
PerfCounters.bootstrapTime.addElapsedTimeFrom(t0);
- // remember the ModuleFinder
- initialFinder = finder;
-
return bootLayer;
}
+ /**
+ * Create a "minimal" boot module layer that only contains java.base.
+ */
+ private static ModuleLayer createMinimalBootLayer() {
+ Configuration cf = SharedSecrets.getJavaLangModuleAccess()
+ .resolveAndBind(ModuleFinder.ofSystem(),
+ Set.of(JAVA_BASE),
+ false,
+ null);
+
+ Function clf = ModuleLoaderMap.mappingFunction(cf);
+ return ModuleLayer.empty().defineModules(cf, clf);
+ }
+
/**
* Returns a ModuleFinder that limits observability to the given root
* modules, their transitive dependences, plus a set of other modules.
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashesBuilder.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashesBuilder.java
index d808fe1db48..804f5eb4527 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashesBuilder.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashesBuilder.java
@@ -138,7 +138,7 @@ public class ModuleHashesBuilder {
}
/*
- * Utilty class
+ * Utility class
*/
static class Graph {
private final Set nodes;
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java
index b589e2923f0..f6f1bb07e16 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java
@@ -546,21 +546,15 @@ public final class ModuleInfo {
private ModuleTarget readModuleTargetAttribute(DataInput in, ConstantPool cpool)
throws IOException
{
- String osName = null;
- String osArch = null;
+ String targetPlatform = null;
- int name_index = in.readUnsignedShort();
- if (name_index != 0)
- osName = cpool.getUtf8(name_index);
+ int index = in.readUnsignedShort();
+ if (index != 0)
+ targetPlatform = cpool.getUtf8(index);
- int arch_index = in.readUnsignedShort();
- if (arch_index != 0)
- osArch = cpool.getUtf8(arch_index);
-
- return new ModuleTarget(osName, osArch);
+ return new ModuleTarget(targetPlatform);
}
-
/**
* Reads the ModuleHashes attribute
*/
@@ -612,7 +606,6 @@ public final class ModuleInfo {
return new ModuleResolution(flags);
}
-
/**
* Returns true if the given attribute can be present at most once
* in the class file. Returns false otherwise.
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java
index 35f28d35696..270d0a2605f 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java
@@ -62,9 +62,8 @@ public final class ModuleInfoExtender {
// the value of the ModuleMainClass attribute
private String mainClass;
- // the values for the ModuleTarget attribute
- private String osName;
- private String osArch;
+ // the value for the ModuleTarget attribute
+ private String targetPlatform;
// the hashes for the ModuleHashes attribute
private ModuleHashes hashes;
@@ -108,11 +107,10 @@ public final class ModuleInfoExtender {
}
/**
- * Sets the values for the ModuleTarget attribute.
+ * Sets the value for the ModuleTarget attribute.
*/
- public ModuleInfoExtender targetPlatform(String osName, String osArch) {
- this.osName = osName;
- this.osArch = osArch;
+ public ModuleInfoExtender targetPlatform(String targetPlatform) {
+ this.targetPlatform = targetPlatform;
return this;
}
@@ -199,8 +197,8 @@ public final class ModuleInfoExtender {
cv.addAttribute(new ModulePackagesAttribute(packages));
if (mainClass != null)
cv.addAttribute(new ModuleMainClassAttribute(mainClass));
- if (osName != null || osArch != null)
- cv.addAttribute(new ModuleTargetAttribute(osName, osArch));
+ if (targetPlatform != null)
+ cv.addAttribute(new ModuleTargetAttribute(targetPlatform));
if (hashes != null)
cv.addAttribute(new ModuleHashesAttribute(hashes));
if (moduleResolution != null)
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java
index 01bee5041f4..dded95fe93d 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java
@@ -66,10 +66,9 @@ public final class ModuleInfoWriter {
// write ModuleMainClass if the module has a main class
md.mainClass().ifPresent(mc -> cw.visitAttribute(new ModuleMainClassAttribute(mc)));
- // write ModuleTarget if there is a platform OS/arch
+ // write ModuleTarget if there is a target platform
if (target != null) {
- cw.visitAttribute(new ModuleTargetAttribute(target.osName(),
- target.osArch()));
+ cw.visitAttribute(new ModuleTargetAttribute(target.targetPlatform()));
}
cw.visitEnd();
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java
index 15e60d0d611..b0f465d4776 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java
@@ -37,36 +37,66 @@ import jdk.internal.loader.ClassLoaders;
/**
- * The module to class loader map. The list of boot modules and platform modules
- * are generated at build time.
+ * Supports the mapping of modules to class loaders. The set of modules mapped
+ * to the boot and platform class loaders is generated at build time from
+ * this source file.
*/
-final class ModuleLoaderMap {
+public final class ModuleLoaderMap {
+
+ /**
+ * Maps the system modules to the built-in class loaders.
+ */
+ public static final class Mapper implements Function {
+ private final Map map;
+
+ Mapper(Map map) {
+ this.map = map; // defensive copy not needed
+ }
+
+ @Override
+ public ClassLoader apply(String name) {
+ return map.get(name);
+ }
+ }
+
+ /**
+ * Returns the names of the modules defined to the boot loader.
+ */
+ public static Set bootModules() {
+ // The list of boot modules generated at build time.
+ String[] BOOT_MODULES = new String[] { "@@BOOT_MODULE_NAMES@@" };
+ Set bootModules = new HashSet<>(BOOT_MODULES.length);
+ for (String mn : BOOT_MODULES) {
+ bootModules.add(mn);
+ }
+ return bootModules;
+ }
+
+ /**
+ * Returns the names of the modules defined to the platform loader.
+ */
+ public static Set platformModules() {
+ // The list of platform modules generated at build time.
+ String[] PLATFORM_MODULES = new String[] { "@@PLATFORM_MODULE_NAMES@@" };
+ Set platformModules = new HashSet<>(PLATFORM_MODULES.length);
+ for (String mn : PLATFORM_MODULES) {
+ platformModules.add(mn);
+ }
+ return platformModules;
+ }
/**
* Returns the function to map modules in the given configuration to the
* built-in class loaders.
*/
static Function mappingFunction(Configuration cf) {
-
- // The list of boot modules and platform modules are generated at build time.
- final String[] BOOT_MODULES = new String[] { "@@BOOT_MODULE_NAMES@@" };
- final String[] PLATFORM_MODULES = new String[] { "@@PLATFORM_MODULE_NAMES@@" };
-
- Set bootModules = new HashSet<>(BOOT_MODULES.length);
- for (String mn : BOOT_MODULES) {
- bootModules.add(mn);
- }
-
- Set platformModules = new HashSet<>(PLATFORM_MODULES.length);
- for (String mn : PLATFORM_MODULES) {
- platformModules.add(mn);
- }
+ Set bootModules = bootModules();
+ Set platformModules = platformModules();
ClassLoader platformClassLoader = ClassLoaders.platformClassLoader();
ClassLoader appClassLoader = ClassLoaders.appClassLoader();
Map map = new HashMap<>();
-
for (ResolvedModule resolvedModule : cf.modules()) {
String mn = resolvedModule.name();
if (!bootModules.contains(mn)) {
@@ -77,12 +107,6 @@ final class ModuleLoaderMap {
}
}
}
-
- return new Function () {
- @Override
- public ClassLoader apply(String mn) {
- return map.get(mn);
- }
- };
+ return new Mapper(map);
}
}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java
index 3f5827bfc54..c0458e0f34e 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java
@@ -120,7 +120,7 @@ public final class ModulePatcher {
// JAR file - do not open as a multi-release JAR as this
// is not supported by the boot class loader
- try (JarFile jf = new JarFile(file.toFile())) {
+ try (JarFile jf = new JarFile(file.toString())) {
jf.stream()
.filter(e -> !e.isDirectory()
&& (!isAutomatic || e.getName().endsWith(".class")))
@@ -431,7 +431,7 @@ public final class ModulePatcher {
private final URL csURL;
JarResourceFinder(Path path) throws IOException {
- this.jf = new JarFile(path.toFile());
+ this.jf = new JarFile(path.toString());
this.csURL = path.toUri().toURL();
}
@@ -505,7 +505,7 @@ public final class ModulePatcher {
public Resource find(String name) throws IOException {
Path file = Resources.toFilePath(dir, name);
if (file != null) {
- return newResource(name, dir, file);
+ return newResource(name, dir, file);
} else {
return null;
}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePath.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePath.java
index 75a76b0858f..750ac801fe3 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePath.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePath.java
@@ -59,6 +59,7 @@ import java.util.jar.Manifest;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
+import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import jdk.internal.jmod.JmodFile;
@@ -315,26 +316,42 @@ public class ModulePath implements ModuleFinder {
{
try {
+ // exploded module
if (attrs.isDirectory()) {
return readExplodedModule(entry); // may return null
- } else {
+ }
+
+ // JAR or JMOD file
+ if (attrs.isRegularFile()) {
String fn = entry.getFileName().toString();
- if (attrs.isRegularFile()) {
- if (fn.endsWith(".jar")) {
+ boolean isDefaultFileSystem = isDefaultFileSystem(entry);
+
+ // JAR file
+ if (fn.endsWith(".jar")) {
+ if (isDefaultFileSystem) {
return readJar(entry);
- } else if (isLinkPhase && fn.endsWith(".jmod")) {
- return readJMod(entry);
+ } else {
+ // the JAR file is in a custom file system so
+ // need to copy it to the local file system
+ Path tmpdir = Files.createTempDirectory("mlib");
+ Path target = Files.copy(entry, tmpdir.resolve(fn));
+ return readJar(target);
}
}
- return null;
+
+ // JMOD file
+ if (isDefaultFileSystem && isLinkPhase && fn.endsWith(".jmod")) {
+ return readJMod(entry);
+ }
}
+ return null;
+
} catch (InvalidModuleDescriptorException e) {
throw new FindException("Error reading module: " + entry, e);
}
}
-
/**
* Returns a string with the file name of the module if possible.
* If the module location is not a file URI then return the URI
@@ -434,7 +451,7 @@ public class ModulePath implements ModuleFinder {
* 3. The contents of any META-INF/services configuration files are mapped
* to "provides" declarations
* 4. The Main-Class attribute in the main attributes of the JAR manifest
- * is mapped to the module descriptor mainClass
+ * is mapped to the module descriptor mainClass if possible
*/
private ModuleDescriptor deriveModuleDescriptor(JarFile jf)
throws IOException
@@ -530,12 +547,12 @@ public class ModulePath implements ModuleFinder {
String mainClass = attrs.getValue(Attributes.Name.MAIN_CLASS);
if (mainClass != null) {
mainClass = mainClass.replace("/", ".");
- String pn = packageName(mainClass);
- if (!packages.contains(pn)) {
- String msg = "Main-Class " + mainClass + " not in module";
- throw new InvalidModuleDescriptorException(msg);
+ if (Checks.isClassName(mainClass)) {
+ String pn = packageName(mainClass);
+ if (packages.contains(pn)) {
+ builder.mainClass(mainClass);
+ }
}
- builder.mainClass(mainClass);
}
}
@@ -617,6 +634,8 @@ public class ModulePath implements ModuleFinder {
}
return ModuleReferences.newJarModule(attrs, patcher, file);
+ } catch (ZipException e) {
+ throw new FindException("Error reading " + file, e);
}
}
@@ -733,6 +752,16 @@ public class ModulePath implements ModuleFinder {
}
}
+
+ /**
+ * Return true if a path locates a path in the default file system
+ */
+ private boolean isDefaultFileSystem(Path path) {
+ return path.getFileSystem().provider()
+ .getScheme().equalsIgnoreCase("file");
+ }
+
+
private static final PerfCounter scanTime
= PerfCounter.newPerfCounter("jdk.module.finder.modulepath.scanTime");
private static final PerfCounter moduleCount
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java
index 450cc5ce6d2..938c446b6c7 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java
@@ -25,6 +25,7 @@
package jdk.internal.module;
+import java.io.File;
import java.io.IOError;
import java.io.IOException;
import java.io.InputStream;
@@ -226,8 +227,8 @@ class ModuleReferences {
static JarFile newJarFile(Path path) {
try {
- return new JarFile(path.toFile(),
- true, // verify
+ return new JarFile(new File(path.toString()),
+ true, // verify
ZipFile.OPEN_READ,
JarFile.runtimeVersion());
} catch (IOException ioe) {
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleResolution.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleResolution.java
index 76c42368c63..d8b9d9609a1 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleResolution.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleResolution.java
@@ -39,6 +39,10 @@ public final class ModuleResolution {
this.value = value;
}
+ public int value() {
+ return value;
+ }
+
public static ModuleResolution empty() {
return new ModuleResolution(0);
}
@@ -74,35 +78,30 @@ public final class ModuleResolution {
throw new InternalError("cannot add deprecated for removal to " + value);
return new ModuleResolution(value | WARN_DEPRECATED_FOR_REMOVAL);
}
+
public ModuleResolution withIncubating() {
if ((value & (WARN_DEPRECATED | WARN_DEPRECATED_FOR_REMOVAL)) != 0)
throw new InternalError("cannot add incubating to " + value);
return new ModuleResolution(value | WARN_INCUBATING);
}
- public int value() {
- return value;
- }
-
public static boolean doNotResolveByDefault(ModuleReference mref) {
// get the DO_NOT_RESOLVE_BY_DEFAULT flag, if any
- if (!(mref instanceof ModuleReferenceImpl))
- return false;
-
- ModuleResolution mres = ((ModuleReferenceImpl)mref).moduleResolution();
- if (mres != null)
- return mres.doNotResolveByDefault();
+ if (mref instanceof ModuleReferenceImpl) {
+ ModuleResolution mres = ((ModuleReferenceImpl) mref).moduleResolution();
+ if (mres != null)
+ return mres.doNotResolveByDefault();
+ }
return false;
}
public static boolean hasIncubatingWarning(ModuleReference mref) {
- if (!(mref instanceof ModuleReferenceImpl))
- return false;
-
- ModuleResolution mres = ((ModuleReferenceImpl)mref).moduleResolution();
- if (mres != null)
- return mres.hasIncubatingWarning();
+ if (mref instanceof ModuleReferenceImpl) {
+ ModuleResolution mres = ((ModuleReferenceImpl) mref).moduleResolution();
+ if (mres != null)
+ return mres.hasIncubatingWarning();
+ }
return false;
}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleTarget.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleTarget.java
index dcfe8ac8b58..ffd50704f33 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleTarget.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleTarget.java
@@ -25,22 +25,21 @@
package jdk.internal.module;
+/**
+ * Represents the module target.
+ *
+ * For now, this is a single value for the target platform, e.g. "linux-x64".
+ */
public final class ModuleTarget {
- private final String osName;
- private final String osArch;
+ private final String targetPlatform;
- public ModuleTarget(String osName, String osArch) {
- this.osName = osName;
- this.osArch = osArch;
+ public ModuleTarget(String targetPlatform) {
+ this.targetPlatform = targetPlatform;
}
- public String osName() {
- return osName;
- }
-
- public String osArch() {
- return osArch;
+ public String targetPlatform() {
+ return targetPlatform;
}
}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/Modules.java b/jdk/src/java.base/share/classes/jdk/internal/module/Modules.java
index 62288625b76..af784dd944e 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/Modules.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/Modules.java
@@ -25,12 +25,22 @@
package jdk.internal.module;
+import java.lang.module.Configuration;
import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReference;
+import java.lang.module.ResolvedModule;
import java.net.URI;
import java.security.AccessController;
import java.security.PrivilegedAction;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
import jdk.internal.loader.BootLoader;
+import jdk.internal.loader.BuiltinClassLoader;
import jdk.internal.loader.ClassLoaders;
import jdk.internal.misc.JavaLangAccess;
import jdk.internal.misc.SharedSecrets;
@@ -38,8 +48,8 @@ import jdk.internal.misc.SharedSecrets;
/**
* A helper class for creating and updating modules. This class is intended to
* support command-line options, tests, and the instrumentation API. It is also
- * used by the VM to add read edges when agents are instrumenting code that
- * need to link to supporting classes.
+ * used by the VM to load modules or add read edges when agents are instrumenting
+ * code that need to link to supporting classes.
*
* The parameters that are package names in this API are the fully-qualified
* names of the packages as defined in section 6.5.3 of The Java™
@@ -154,4 +164,90 @@ public class Modules {
addReads(m, BootLoader.getUnnamedModule());
addReads(m, ClassLoaders.appClassLoader().getUnnamedModule());
}
+
+ /**
+ * Called by the VM to load a system module, typically "java.instrument" or
+ * "jdk.management.agent". If the module is not loaded then it is resolved
+ * and loaded (along with any dependences that weren't previously loaded)
+ * into a child layer.
+ */
+ public static synchronized Module loadModule(String name) {
+ ModuleLayer top = topLayer;
+ if (top == null)
+ top = ModuleLayer.boot();
+
+ Module module = top.findModule(name).orElse(null);
+ if (module != null) {
+ // module already loaded
+ return module;
+ }
+
+ // resolve the module with the top-most layer as the parent
+ ModuleFinder empty = ModuleFinder.of();
+ ModuleFinder finder = ModuleBootstrap.unlimitedFinder();
+ Set roots = Set.of(name);
+ Configuration cf = top.configuration().resolveAndBind(empty, finder, roots);
+
+ // create the child layer
+ Function clf = ModuleLoaderMap.mappingFunction(cf);
+ ModuleLayer newLayer = top.defineModules(cf, clf);
+
+ // add qualified exports/opens to give access to modules in child layer
+ Map map = newLayer.modules().stream()
+ .collect(Collectors.toMap(Module::getName,
+ Function.identity()));
+ ModuleLayer layer = top;
+ while (layer != null) {
+ for (Module m : layer.modules()) {
+ // qualified exports
+ m.getDescriptor().exports().stream()
+ .filter(ModuleDescriptor.Exports::isQualified)
+ .forEach(e -> e.targets().forEach(target -> {
+ Module other = map.get(target);
+ if (other != null) {
+ addExports(m, e.source(), other);
+ }}));
+
+ // qualified opens
+ m.getDescriptor().opens().stream()
+ .filter(ModuleDescriptor.Opens::isQualified)
+ .forEach(o -> o.targets().forEach(target -> {
+ Module other = map.get(target);
+ if (other != null) {
+ addOpens(m, o.source(), other);
+ }}));
+ }
+
+ List parents = layer.parents();
+ assert parents.size() <= 1;
+ layer = parents.isEmpty() ? null : parents.get(0);
+ }
+
+ // update security manager before making types visible
+ JLA.addNonExportedPackages(newLayer);
+
+ // update the built-in class loaders to make the types visible
+ for (ResolvedModule resolvedModule : cf.modules()) {
+ ModuleReference mref = resolvedModule.reference();
+ String mn = mref.descriptor().name();
+ ClassLoader cl = clf.apply(mn);
+ if (cl == null) {
+ BootLoader.loadModule(mref);
+ } else {
+ ((BuiltinClassLoader) cl).loadModule(mref);
+ }
+ }
+
+ // new top layer
+ topLayer = newLayer;
+
+ // return module
+ return newLayer.findModule(name)
+ .orElseThrow(() -> new InternalError("module not loaded"));
+
+ }
+
+ // the top-most system layer
+ private static ModuleLayer topLayer;
+
}
diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/Resources.java b/jdk/src/java.base/share/classes/jdk/internal/module/Resources.java
index 4498682f0b9..53865742dbe 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/module/Resources.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/Resources.java
@@ -26,10 +26,10 @@ package jdk.internal.module;
import java.io.File;
import java.io.IOException;
+import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
-import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
/**
@@ -94,7 +94,7 @@ public final class Resources {
if (expectDirectory) {
name = name.substring(0, name.length() - 1); // drop trailing "/"
}
- Path path = toSafeFilePath(name);
+ Path path = toSafeFilePath(dir.getFileSystem(), name);
if (path != null) {
Path file = dir.resolve(path);
try {
@@ -116,7 +116,7 @@ public final class Resources {
* are rejected, as are resource names that translates to a file path
* with a root component.
*/
- private static Path toSafeFilePath(String name) {
+ private static Path toSafeFilePath(FileSystem fs, String name) {
// scan elements of resource name
int next;
int off = 0;
@@ -135,12 +135,12 @@ public final class Resources {
// convert to file path
Path path;
if (File.separatorChar == '/') {
- path = Paths.get(name);
+ path = fs.getPath(name);
} else {
// not allowed to embed file separators
if (name.contains(File.separator))
return null;
- path = Paths.get(name.replace('/', File.separatorChar));
+ path = fs.getPath(name.replace('/', File.separatorChar));
}
// file path not allowed to have root component
diff --git a/jdk/src/java.base/share/classes/module-info.java b/jdk/src/java.base/share/classes/module-info.java
index 1c3f76927aa..838f215d888 100644
--- a/jdk/src/java.base/share/classes/module-info.java
+++ b/jdk/src/java.base/share/classes/module-info.java
@@ -161,6 +161,7 @@ module java.base {
java.security.jgss,
java.sql,
java.xml,
+ jdk.attach,
jdk.charsets,
jdk.compiler, // reflective dependency
jdk.incubator.httpclient,
diff --git a/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java b/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java
index d6cc3661d00..5ac605a2092 100644
--- a/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java
+++ b/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java
@@ -43,13 +43,17 @@ import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
-import java.lang.module.ModuleFinder;
-import java.lang.module.ModuleReference;
+import java.lang.module.Configuration;
+import java.lang.module.FindException;
import java.lang.module.ModuleDescriptor;
import java.lang.module.ModuleDescriptor.Requires;
import java.lang.module.ModuleDescriptor.Exports;
import java.lang.module.ModuleDescriptor.Opens;
import java.lang.module.ModuleDescriptor.Provides;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReference;
+import java.lang.module.ResolvedModule;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
@@ -58,14 +62,16 @@ import java.net.URI;
import java.nio.charset.Charset;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.attribute.BasicFileAttributes;
import java.text.Normalizer;
import java.text.MessageFormat;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
-import java.util.HashSet;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
@@ -83,6 +89,7 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import jdk.internal.misc.VM;
+import jdk.internal.module.ModuleBootstrap;
import jdk.internal.module.Modules;
@@ -98,6 +105,7 @@ public final class LauncherHelper {
"javafx.application.Application";
private static final String JAVAFX_FXHELPER_CLASS_NAME_SUFFIX =
"sun.launcher.LauncherHelper$FXHelper";
+ private static final String LAUNCHER_AGENT_CLASS = "Launcher-Agent-Class";
private static final String MAIN_CLASS = "Main-Class";
private static final String ADD_EXPORTS = "Add-Exports";
private static final String ADD_OPENS = "Add-Opens";
@@ -408,8 +416,12 @@ public final class LauncherHelper {
ostream = (printToStderr) ? System.err : System.out;
}
+ static void initOutput(PrintStream ps) {
+ ostream = ps;
+ }
+
static String getMainClassFromJar(String jarname) {
- String mainValue = null;
+ String mainValue;
try (JarFile jarFile = new JarFile(jarname)) {
Manifest manifest = jarFile.getManifest();
if (manifest == null) {
@@ -426,6 +438,22 @@ public final class LauncherHelper {
abort(null, "java.launcher.jar.error3", jarname);
}
+ // Launcher-Agent-Class (only check for this when Main-Class present)
+ String agentClass = mainAttrs.getValue(LAUNCHER_AGENT_CLASS);
+ if (agentClass != null) {
+ ModuleLayer.boot().findModule("java.instrument").ifPresent(m -> {
+ try {
+ String cn = "sun.instrument.InstrumentationImpl";
+ Class> clazz = Class.forName(cn, false, null);
+ Method loadAgent = clazz.getMethod("loadAgent", String.class);
+ loadAgent.invoke(null, jarname);
+ } catch (Throwable e) {
+ if (e instanceof InvocationTargetException) e = e.getCause();
+ abort(e, "java.launcher.jar.error4", jarname);
+ }
+ });
+ }
+
// Add-Exports and Add-Opens
String exports = mainAttrs.getValue(ADD_EXPORTS);
if (exports != null) {
@@ -913,141 +941,350 @@ public final class LauncherHelper {
}
}
- private static void formatCommaList(PrintStream out,
- String prefix,
- Collection> list)
- {
- if (list.isEmpty())
- return;
- out.format("%s", prefix);
- boolean first = true;
- for (Object ob : list) {
- if (first) {
- out.format(" %s", ob);
- first = false;
- } else {
- out.format(", %s", ob);
- }
- }
- out.format("%n");
- }
-
/**
* Called by the launcher to list the observable modules.
- * If called without any sub-options then the output is a simple list of
- * the modules. If called with sub-options then the sub-options are the
- * names of the modules to list (e.g. --list-modules java.base,java.desktop)
*/
- static void listModules(boolean printToStderr, String optionFlag)
- throws IOException, ClassNotFoundException
- {
- initOutput(printToStderr);
+ static void listModules() {
+ initOutput(System.out);
- ModuleFinder finder = jdk.internal.module.ModuleBootstrap.finder();
- int colon = optionFlag.indexOf('=');
- if (colon == -1) {
- finder.findAll().stream()
- .sorted(Comparator.comparing(ModuleReference::descriptor))
- .forEach(mref -> describeModule(finder, mref, false));
- } else {
- String[] names = optionFlag.substring(colon+1).split(",");
- for (String name: names) {
- ModuleReference mref = finder.find(name).orElse(null);
- if (mref == null) {
- System.err.format("%s not found%n", name);
- continue;
- }
- describeModule(finder, mref, true);
- }
- }
+ ModuleBootstrap.limitedFinder().findAll().stream()
+ .sorted(new JrtFirstComparator())
+ .forEach(LauncherHelper::showModule);
}
/**
- * Describes the given module.
+ * Called by the launcher to show the resolved modules
*/
- static void describeModule(ModuleFinder finder,
- ModuleReference mref,
- boolean verbose)
- {
- ModuleDescriptor md = mref.descriptor();
- ostream.print("module " + midAndLocation(md, mref.location()));
- if (md.isAutomatic())
- ostream.print(" automatic");
- ostream.println();
+ static void showResolvedModules() {
+ initOutput(System.out);
- if (!verbose)
- return;
+ ModuleLayer bootLayer = ModuleLayer.boot();
+ Configuration cf = bootLayer.configuration();
+
+ cf.modules().stream()
+ .map(ResolvedModule::reference)
+ .sorted(new JrtFirstComparator())
+ .forEach(LauncherHelper::showModule);
+ }
+
+ /**
+ * Called by the launcher to describe a module
+ */
+ static void describeModule(String moduleName) {
+ initOutput(System.out);
+
+ ModuleFinder finder = ModuleBootstrap.limitedFinder();
+ ModuleReference mref = finder.find(moduleName).orElse(null);
+ if (mref == null) {
+ abort(null, "java.launcher.module.error4", moduleName);
+ }
+ ModuleDescriptor md = mref.descriptor();
+
+ // one-line summary
+ showModule(mref);
// unqualified exports (sorted by package)
- Set exports = new TreeSet<>(Comparator.comparing(Exports::source));
- md.exports().stream().filter(e -> !e.isQualified()).forEach(exports::add);
- for (Exports e : exports) {
- String modsAndSource = Stream.concat(toStringStream(e.modifiers()),
- Stream.of(e.source()))
+ md.exports().stream()
+ .filter(e -> !e.isQualified())
+ .sorted(Comparator.comparing(Exports::source))
+ .map(e -> Stream.concat(Stream.of(e.source()),
+ toStringStream(e.modifiers()))
+ .collect(Collectors.joining(" ")))
+ .forEach(sourceAndMods -> ostream.format("exports %s%n", sourceAndMods));
+
+ // dependences
+ for (Requires r : md.requires()) {
+ String nameAndMods = Stream.concat(Stream.of(r.name()),
+ toStringStream(r.modifiers()))
.collect(Collectors.joining(" "));
- ostream.format(" exports %s%n", modsAndSource);
+ ostream.format("requires %s", nameAndMods);
+ finder.find(r.name())
+ .map(ModuleReference::descriptor)
+ .filter(ModuleDescriptor::isAutomatic)
+ .ifPresent(any -> ostream.print(" automatic"));
+ ostream.println();
}
- for (Requires d : md.requires()) {
- ostream.format(" requires %s", d);
- String suffix = finder.find(d.name())
- .map(ModuleReference::descriptor)
- .map(any -> any.isAutomatic() ? " automatic" : "")
- .orElse(" not found");
- ostream.println(suffix);
- }
+ // service use and provides
for (String s : md.uses()) {
- ostream.format(" uses %s%n", s);
+ ostream.format("uses %s%n", s);
}
-
for (Provides ps : md.provides()) {
- ostream.format(" provides %s with %s%n", ps.service(),
- ps.providers().stream().collect(Collectors.joining(", ")));
+ String names = ps.providers().stream().collect(Collectors.joining(" "));
+ ostream.format("provides %s with %s%n", ps.service(), names);
+
}
// qualified exports
for (Exports e : md.exports()) {
if (e.isQualified()) {
- String modsAndSource = Stream.concat(toStringStream(e.modifiers()),
- Stream.of(e.source()))
- .collect(Collectors.joining(" "));
- ostream.format(" exports %s", modsAndSource);
- formatCommaList(ostream, " to", e.targets());
+ String who = e.targets().stream().collect(Collectors.joining(" "));
+ ostream.format("qualified exports %s to %s%n", e.source(), who);
}
}
// open packages
- for (Opens obj: md.opens()) {
- String modsAndSource = Stream.concat(toStringStream(obj.modifiers()),
- Stream.of(obj.source()))
+ for (Opens opens: md.opens()) {
+ if (opens.isQualified())
+ ostream.print("qualified ");
+ String sourceAndMods = Stream.concat(Stream.of(opens.source()),
+ toStringStream(opens.modifiers()))
.collect(Collectors.joining(" "));
- ostream.format(" opens %s", modsAndSource);
- if (obj.isQualified())
- formatCommaList(ostream, " to", obj.targets());
- else
- ostream.println();
+ ostream.format("opens %s", sourceAndMods);
+ if (opens.isQualified()) {
+ String who = opens.targets().stream().collect(Collectors.joining(" "));
+ ostream.format(" to %s", who);
+ }
+ ostream.println();
}
// non-exported/non-open packages
Set concealed = new TreeSet<>(md.packages());
md.exports().stream().map(Exports::source).forEach(concealed::remove);
md.opens().stream().map(Opens::source).forEach(concealed::remove);
- concealed.forEach(p -> ostream.format(" contains %s%n", p));
+ concealed.forEach(p -> ostream.format("contains %s%n", p));
}
- static String toString(Set s) {
- return toStringStream(s).collect(Collectors.joining(" "));
+ /**
+ * Prints a single line with the module name, version and modifiers
+ */
+ private static void showModule(ModuleReference mref) {
+ ModuleDescriptor md = mref.descriptor();
+ ostream.print(md.toNameAndVersion());
+ mref.location()
+ .filter(uri -> !isJrt(uri))
+ .ifPresent(uri -> ostream.format(" %s", uri));
+ if (md.isOpen())
+ ostream.print(" open");
+ if (md.isAutomatic())
+ ostream.print(" automatic");
+ ostream.println();
}
- static Stream toStringStream(Set s) {
+ /**
+ * A ModuleReference comparator that considers modules in the run-time
+ * image to be less than modules than not in the run-time image.
+ */
+ private static class JrtFirstComparator implements Comparator {
+ private final Comparator real;
+
+ JrtFirstComparator() {
+ this.real = Comparator.comparing(ModuleReference::descriptor);
+ }
+
+ @Override
+ public int compare(ModuleReference a, ModuleReference b) {
+ if (isJrt(a)) {
+ return isJrt(b) ? real.compare(a, b) : -1;
+ } else {
+ return isJrt(b) ? 1 : real.compare(a, b);
+ }
+ }
+ }
+
+ private static Stream toStringStream(Set s) {
return s.stream().map(e -> e.toString().toLowerCase());
}
- static String midAndLocation(ModuleDescriptor md, Optional location ) {
- URI loc = location.orElse(null);
- if (loc == null || loc.getScheme().equalsIgnoreCase("jrt"))
- return md.toNameAndVersion();
- else
- return md.toNameAndVersion() + " (" + loc + ")";
+ private static boolean isJrt(ModuleReference mref) {
+ return isJrt(mref.location().orElse(null));
+ }
+
+ private static boolean isJrt(URI uri) {
+ return (uri != null && uri.getScheme().equalsIgnoreCase("jrt"));
+ }
+
+ /**
+ * Called by the launcher to validate the modules on the upgrade and
+ * application module paths.
+ *
+ * @return {@code true} if no errors are found
+ */
+ private static boolean validateModules() {
+ initOutput(System.out);
+
+ ModuleValidator validator = new ModuleValidator();
+
+ // upgrade module path
+ String value = System.getProperty("jdk.module.upgrade.path");
+ if (value != null) {
+ Stream.of(value.split(File.pathSeparator))
+ .map(Paths::get)
+ .forEach(validator::scan);
+ }
+
+ // system modules
+ ModuleFinder.ofSystem().findAll().stream()
+ .sorted(Comparator.comparing(ModuleReference::descriptor))
+ .forEach(validator::process);
+
+ // application module path
+ value = System.getProperty("jdk.module.path");
+ if (value != null) {
+ Stream.of(value.split(File.pathSeparator))
+ .map(Paths::get)
+ .forEach(validator::scan);
+ }
+
+ return !validator.foundErrors();
+ }
+
+ /**
+ * A simple validator to check for errors and conflicts between modules.
+ */
+ static class ModuleValidator {
+ private static final String MODULE_INFO = "module-info.class";
+
+ private Map nameToModule = new HashMap<>();
+ private Map packageToModule = new HashMap<>();
+ private boolean errorFound;
+
+ /**
+ * Returns true if at least one error was found
+ */
+ boolean foundErrors() {
+ return errorFound;
+ }
+
+ /**
+ * Prints the module location and name.
+ */
+ private void printModule(ModuleReference mref) {
+ mref.location()
+ .filter(uri -> !isJrt(uri))
+ .ifPresent(uri -> ostream.print(uri + " "));
+ ModuleDescriptor descriptor = mref.descriptor();
+ ostream.print(descriptor.name());
+ if (descriptor.isAutomatic())
+ ostream.print(" automatic");
+ ostream.println();
+ }
+
+ /**
+ * Prints the module location and name, checks if the module is
+ * shadowed by a previously seen module, and finally checks for
+ * package conflicts with previously seen modules.
+ */
+ void process(ModuleReference mref) {
+ printModule(mref);
+
+ String name = mref.descriptor().name();
+ ModuleReference previous = nameToModule.putIfAbsent(name, mref);
+ if (previous != null) {
+ ostream.print(INDENT + "shadowed by ");
+ printModule(previous);
+ } else {
+ // check for package conflicts when not shadowed
+ for (String pkg : mref.descriptor().packages()) {
+ previous = packageToModule.putIfAbsent(pkg, mref);
+ if (previous != null) {
+ String mn = previous.descriptor().name();
+ ostream.println(INDENT + "contains " + pkg
+ + " conflicts with module " + mn);
+ errorFound = true;
+ }
+ }
+ }
+ }
+
+ /**
+ * Scan an element on a module path. The element is a directory
+ * of modules, an exploded module, or a JAR file.
+ */
+ void scan(Path entry) {
+ BasicFileAttributes attrs;
+ try {
+ attrs = Files.readAttributes(entry, BasicFileAttributes.class);
+ } catch (NoSuchFileException ignore) {
+ return;
+ } catch (IOException ioe) {
+ ostream.println(entry + " " + ioe);
+ errorFound = true;
+ return;
+ }
+
+ String fn = entry.getFileName().toString();
+ if (attrs.isRegularFile() && fn.endsWith(".jar")) {
+ // JAR file, explicit or automatic module
+ scanModule(entry).ifPresent(this::process);
+ } else if (attrs.isDirectory()) {
+ Path mi = entry.resolve(MODULE_INFO);
+ if (Files.exists(mi)) {
+ // exploded module
+ scanModule(entry).ifPresent(this::process);
+ } else {
+ // directory of modules
+ scanDirectory(entry);
+ }
+ }
+ }
+
+ /**
+ * Scan the JAR files and exploded modules in a directory.
+ */
+ private void scanDirectory(Path dir) {
+ try (DirectoryStream stream = Files.newDirectoryStream(dir)) {
+ Map moduleToEntry = new HashMap<>();
+
+ for (Path entry : stream) {
+ BasicFileAttributes attrs;
+ try {
+ attrs = Files.readAttributes(entry, BasicFileAttributes.class);
+ } catch (IOException ioe) {
+ ostream.println(entry + " " + ioe);
+ errorFound = true;
+ continue;
+ }
+
+ ModuleReference mref = null;
+
+ String fn = entry.getFileName().toString();
+ if (attrs.isRegularFile() && fn.endsWith(".jar")) {
+ mref = scanModule(entry).orElse(null);
+ } else if (attrs.isDirectory()) {
+ Path mi = entry.resolve(MODULE_INFO);
+ if (Files.exists(mi)) {
+ mref = scanModule(entry).orElse(null);
+ }
+ }
+
+ if (mref != null) {
+ String name = mref.descriptor().name();
+ Path previous = moduleToEntry.putIfAbsent(name, entry);
+ if (previous != null) {
+ // same name as other module in the directory
+ printModule(mref);
+ ostream.println(INDENT + "contains same module as "
+ + previous.getFileName());
+ errorFound = true;
+ } else {
+ process(mref);
+ }
+ }
+ }
+ } catch (IOException ioe) {
+ ostream.println(dir + " " + ioe);
+ errorFound = true;
+ }
+ }
+
+ /**
+ * Scan a JAR file or exploded module.
+ */
+ private Optional scanModule(Path entry) {
+ ModuleFinder finder = ModuleFinder.of(entry);
+ try {
+ return finder.findAll().stream().findFirst();
+ } catch (FindException e) {
+ ostream.println(entry);
+ ostream.println(INDENT + e.getMessage());
+ Throwable cause = e.getCause();
+ if (cause != null) {
+ ostream.println(INDENT + cause);
+ }
+ errorFound = true;
+ return Optional.empty();
+ }
+ }
}
}
diff --git a/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties b/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties
index 7816cc058cc..7cf14706afb 100644
--- a/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties
+++ b/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties
@@ -53,26 +53,33 @@ java.launcher.opt.footer = \
\ A {0} separated list of directories, each directory\n\
\ is a directory of modules that replace upgradeable\n\
\ modules in the runtime image\n\
-\ --add-modules [,...]\n\
+\ --add-modules [,...]\n\
\ root modules to resolve in addition to the initial module.\n\
-\ can also be ALL-DEFAULT, ALL-SYSTEM,\n\
+\ can also be ALL-DEFAULT, ALL-SYSTEM,\n\
\ ALL-MODULE-PATH.\n\
-\ --limit-modules [,...]\n\
-\ limit the universe of observable modules\n\
-\ --list-modules [[,...]]\n\
-\ list the observable modules and exit\n\
-\ --dry-run create VM but do not execute main method.\n\
-\ This --dry-run option may be useful for validating the\n\
+\ --list-modules\n\
+\ list observable modules and exit\n\
+\ --d \n\
+\ --describe-module \n\
+\ describe a module and exit\n\
+\ --dry-run create VM and load main class but do not execute main method.\n\
+\ The --dry-run option may be useful for validating the\n\
\ command-line options such as the module system configuration.\n\
+\ --validate-modules\n\
+\ validate all modules and exit\n\
+\ The --validate-modules option may be useful for finding\n\
+\ conflicts and other errors with modules on the module path.\n\
\ -D=\n\
\ set a system property\n\
-\ -verbose:[class|gc|jni]\n\
+\ -verbose:[class|module|gc|jni]\n\
\ enable verbose output\n\
\ -version print product version to the error stream and exit\n\
\ --version print product version to the output stream and exit\n\
\ -showversion print product version to the error stream and continue\n\
\ --show-version\n\
\ print product version to the output stream and continue\n\
+\ --show-module-resolution\n\
+\ show module resolution output during startup\n\
\ -? -h -help\n\
\ print this help message to the error stream\n\
\ --help print this help message to the output stream\n\
@@ -119,7 +126,6 @@ java.launcher.X.usage=\n\
\ -Xcomp forces compilation of methods on first invocation\n\
\ -Xdebug provided for backward compatibility\n\
\ -Xdiag show additional diagnostic messages\n\
-\ -Xdiag:resolver show resolver diagnostic messages\n\
\ -Xfuture enable strictest checks, anticipating future default\n\
\ -Xint interpreted mode execution only\n\
\ -Xinternalversion\n\
@@ -164,10 +170,12 @@ java.launcher.X.usage=\n\
\ permit illegal access to members of types in named modules\n\
\ by code in unnamed modules. This compatibility option will\n\
\ be removed in the next release.\n\
-\ --disable-@files disable further argument file expansion\n\
+\ --limit-modules [,...]\n\
+\ limit the universe of observable modules\n\
\ --patch-module =({0})*\n\
-\ Override or augment a module with classes and resources\n\
-\ in JAR files or directories.\n\n\
+\ override or augment a module with classes and resources\n\
+\ in JAR files or directories.\n\
+\ --disable-@files disable further argument file expansion\n\n\
These extra options are subject to change without notice.\n
# Translators please note do not translate the options themselves
@@ -204,6 +212,7 @@ java.launcher.jar.error1=\
Error: An unexpected error occurred while trying to open file {0}
java.launcher.jar.error2=manifest not found in {0}
java.launcher.jar.error3=no main manifest attribute, in {0}
+java.launcher.jar.error4=error loading java agent in {0}
java.launcher.init.error=initialization error
java.launcher.javafx.error1=\
Error: The JavaFX launchApplication method has the wrong signature, it\n\
@@ -215,4 +224,5 @@ java.launcher.module.error2=\
java.launcher.module.error3=\
Error: Unable to load main class {0} from module {1}\n\
\t{2}
-
+java.launcher.module.error4=\
+ {0} not found
diff --git a/jdk/src/java.base/share/native/libjli/emessages.h b/jdk/src/java.base/share/native/libjli/emessages.h
index 8c3c34199ea..c5ae8d74b5e 100644
--- a/jdk/src/java.base/share/native/libjli/emessages.h
+++ b/jdk/src/java.base/share/native/libjli/emessages.h
@@ -43,13 +43,14 @@
#define ARG_ERROR2 "Error: %s requires jar file specification"
#define ARG_ERROR3 "Error: The -J option should not be followed by a space."
#define ARG_ERROR4 "Error: %s requires module path specification"
-#define ARG_ERROR5 "Error: %s requires module id"
+#define ARG_ERROR5 "Error: %s requires module name"
#define ARG_ERROR6 "Error: %s requires modules to be specified"
#define ARG_ERROR7 "Error: %s can only be specified once"
#define ARG_ERROR8 "Error: Unmatched quote in environment variable %s"
#define ARG_ERROR9 "Error: Option %s is not allowed in environment variable %s"
#define ARG_ERROR10 "Error: Option %s in %s is not allowed in environment variable %s"
#define ARG_ERROR11 "Error: Cannot specify main class in environment variable %s"
+#define ARG_ERROR12 "Error: %s requires module name"
#define JVM_ERROR1 "Error: Could not create the Java Virtual Machine.\n" GEN_ERROR
#define JVM_ERROR2 "Error: Could not detach main thread.\n" JNI_ERROR
diff --git a/jdk/src/java.base/share/native/libjli/java.c b/jdk/src/java.base/share/native/libjli/java.c
index f8265eeb110..927c09f5d14 100644
--- a/jdk/src/java.base/share/native/libjli/java.c
+++ b/jdk/src/java.base/share/native/libjli/java.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 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
@@ -71,7 +71,10 @@ static jboolean printTo = USE_STDERR; /* where to print version/usage */
static jboolean printXUsage = JNI_FALSE; /* print and exit*/
static jboolean dryRun = JNI_FALSE; /* initialize VM and exit */
static char *showSettings = NULL; /* print but continue */
-static char *listModules = NULL;
+static jboolean showResolvedModules = JNI_FALSE;
+static jboolean listModules = JNI_FALSE;
+static char *describeModule = NULL;
+static jboolean validateModules = JNI_FALSE;
static const char *_program_name;
static const char *_launcher_name;
@@ -118,7 +121,10 @@ static void SetApplicationClassPath(const char**);
static void PrintJavaVersion(JNIEnv *env, jboolean extraLF);
static void PrintUsage(JNIEnv* env, jboolean doXUsage);
static void ShowSettings(JNIEnv* env, char *optString);
-static void ListModules(JNIEnv* env, char *optString);
+static void ShowResolvedModules(JNIEnv* env);
+static void ListModules(JNIEnv* env);
+static void DescribeModule(JNIEnv* env, char* optString);
+static jboolean ValidateModules(JNIEnv* env);
static void SetPaths(int argc, char **argv);
@@ -409,9 +415,31 @@ JavaMain(void * _args)
CHECK_EXCEPTION_LEAVE(1);
}
- if (listModules != NULL) {
- ListModules(env, listModules);
+ // show resolved modules and continue
+ if (showResolvedModules) {
+ ShowResolvedModules(env);
CHECK_EXCEPTION_LEAVE(1);
+ }
+
+ // list observable modules, then exit
+ if (listModules) {
+ ListModules(env);
+ CHECK_EXCEPTION_LEAVE(1);
+ LEAVE();
+ }
+
+ // describe a module, then exit
+ if (describeModule != NULL) {
+ DescribeModule(env, describeModule);
+ CHECK_EXCEPTION_LEAVE(1);
+ LEAVE();
+ }
+
+ // validate modules on the module path, then exit
+ if (validateModules) {
+ jboolean okay = ValidateModules(env);
+ CHECK_EXCEPTION_LEAVE(1);
+ if (!okay) ret = 1;
LEAVE();
}
@@ -552,7 +580,8 @@ static jboolean
IsLauncherOption(const char* name) {
return IsClassPathOption(name) ||
IsLauncherMainOption(name) ||
- JLI_StrCmp(name, "--list-modules") == 0;
+ JLI_StrCmp(name, "--describe-module") == 0 ||
+ JLI_StrCmp(name, "-d") == 0;
}
/*
@@ -1199,7 +1228,7 @@ GetOpt(int *pargc, char ***pargv, char **poption, char **pvalue) {
} else if (JLI_StrCCmp(arg, "--") == 0 && (equals = JLI_StrChr(arg, '=')) != NULL) {
value = equals+1;
- if (JLI_StrCCmp(arg, "--list-modules=") == 0 ||
+ if (JLI_StrCCmp(arg, "--describe-module=") == 0 ||
JLI_StrCCmp(arg, "--module=") == 0 ||
JLI_StrCCmp(arg, "--class-path=") == 0) {
kind = LAUNCHER_OPTION_WITH_ARGUMENT;
@@ -1263,18 +1292,18 @@ ParseArguments(int *pargc, char ***pargv,
REPORT_ERROR (has_arg_any_len, ARG_ERROR1, arg);
SetClassPath(value);
mode = LM_CLASS;
- } else if (JLI_StrCmp(arg, "--list-modules") == 0 ||
- JLI_StrCCmp(arg, "--list-modules=") == 0) {
- listModules = arg;
-
- // set listModules to --list-modules= if argument is specified
- if (JLI_StrCmp(arg, "--list-modules") == 0 && has_arg) {
- static const char format[] = "%s=%s";
- size_t buflen = JLI_StrLen(option) + 2 + JLI_StrLen(value);
- listModules = JLI_MemAlloc(buflen);
- JLI_Snprintf(listModules, buflen, format, option, value);
- }
- return JNI_TRUE;
+ } else if (JLI_StrCmp(arg, "--list-modules") == 0) {
+ listModules = JNI_TRUE;
+ } else if (JLI_StrCmp(arg, "--show-resolved-modules") == 0) {
+ showResolvedModules = JNI_TRUE;
+ } else if (JLI_StrCmp(arg, "--validate-modules") == 0) {
+ AddOption("-Djdk.module.minimumBoot=true", NULL);
+ validateModules = JNI_TRUE;
+ } else if (JLI_StrCmp(arg, "--describe-module") == 0 ||
+ JLI_StrCCmp(arg, "--describe-module=") == 0 ||
+ JLI_StrCmp(arg, "-d") == 0) {
+ REPORT_ERROR (has_arg_any_len, ARG_ERROR12, arg);
+ describeModule = value;
/*
* Parse white-space options
*/
@@ -1336,9 +1365,8 @@ ParseArguments(int *pargc, char ***pargv,
showSettings = arg;
} else if (JLI_StrCmp(arg, "-Xdiag") == 0) {
AddOption("-Dsun.java.launcher.diag=true", NULL);
- AddOption("-Djdk.launcher.traceResolver=true", NULL);
- } else if (JLI_StrCmp(arg, "-Xdiag:resolver") == 0) {
- AddOption("-Djdk.launcher.traceResolver=true", NULL);
+ } else if (JLI_StrCmp(arg, "--show-module-resolution") == 0) {
+ AddOption("-Djdk.module.showModuleResolution=true", NULL);
/*
* The following case provide backward compatibility with old-style
* command line options.
@@ -1399,7 +1427,10 @@ ParseArguments(int *pargc, char ***pargv,
}
if (*pwhat == NULL) {
- *pret = 1;
+ /* LM_UNKNOWN okay for options that exit */
+ if (!listModules && !describeModule && !validateModules) {
+ *pret = 1;
+ }
} else if (mode == LM_UNKNOWN) {
/* default to LM_CLASS if -m, -jar and -cp options are
* not specified */
@@ -1828,21 +1859,61 @@ ShowSettings(JNIEnv *env, char *optString)
}
/**
- * List modules supported by the runtime
+ * Show resolved modules
*/
static void
-ListModules(JNIEnv *env, char *optString)
+ShowResolvedModules(JNIEnv *env)
+{
+ jmethodID showResolvedModulesID;
+ jclass cls = GetLauncherHelperClass(env);
+ NULL_CHECK(cls);
+ NULL_CHECK(showResolvedModulesID = (*env)->GetStaticMethodID(env, cls,
+ "showResolvedModules", "()V"));
+ (*env)->CallStaticVoidMethod(env, cls, showResolvedModulesID);
+}
+
+/**
+ * List observable modules
+ */
+static void
+ListModules(JNIEnv *env)
{
jmethodID listModulesID;
- jstring joptString = NULL;
jclass cls = GetLauncherHelperClass(env);
NULL_CHECK(cls);
NULL_CHECK(listModulesID = (*env)->GetStaticMethodID(env, cls,
- "listModules", "(ZLjava/lang/String;)V"));
+ "listModules", "()V"));
+ (*env)->CallStaticVoidMethod(env, cls, listModulesID);
+}
+
+/**
+ * Describe a module
+ */
+static void
+DescribeModule(JNIEnv *env, char *optString)
+{
+ jmethodID describeModuleID;
+ jstring joptString = NULL;
+ jclass cls = GetLauncherHelperClass(env);
+ NULL_CHECK(cls);
+ NULL_CHECK(describeModuleID = (*env)->GetStaticMethodID(env, cls,
+ "describeModule", "(Ljava/lang/String;)V"));
NULL_CHECK(joptString = (*env)->NewStringUTF(env, optString));
- (*env)->CallStaticVoidMethod(env, cls, listModulesID,
- USE_STDOUT,
- joptString);
+ (*env)->CallStaticVoidMethod(env, cls, describeModuleID, joptString);
+}
+
+/**
+ * Validate modules
+ */
+static jboolean
+ValidateModules(JNIEnv *env)
+{
+ jmethodID validateModulesID;
+ jclass cls = GetLauncherHelperClass(env);
+ NULL_CHECK_RETURN_VALUE(cls, JNI_FALSE);
+ validateModulesID = (*env)->GetStaticMethodID(env, cls, "validateModules", "()Z");
+ NULL_CHECK_RETURN_VALUE(cls, JNI_FALSE);
+ return (*env)->CallStaticBooleanMethod(env, cls, validateModulesID);
}
/*
diff --git a/jdk/src/java.instrument/share/classes/java/lang/instrument/Instrumentation.java b/jdk/src/java.instrument/share/classes/java/lang/instrument/Instrumentation.java
index 65d1569d0a0..fb94e384116 100644
--- a/jdk/src/java.instrument/share/classes/java/lang/instrument/Instrumentation.java
+++ b/jdk/src/java.instrument/share/classes/java/lang/instrument/Instrumentation.java
@@ -729,7 +729,8 @@ public interface Instrumentation {
* Tests whether a module can be modified with {@link #redefineModule
* redefineModule}. If a module is modifiable then this method returns
* {@code true}. If a module is not modifiable then this method returns
- * {@code false}.
+ * {@code false}. This method always returns {@code true} when the module
+ * is an unnamed module (as redefining an unnamed module is a no-op).
*
* @param module the module to test if it can be modified
* @return {@code true} if the module is modifiable, otherwise {@code false}
diff --git a/jdk/src/java.instrument/share/classes/java/lang/instrument/package.html b/jdk/src/java.instrument/share/classes/java/lang/instrument/package.html
index e7f8d8f6996..5c40a234c91 100644
--- a/jdk/src/java.instrument/share/classes/java/lang/instrument/package.html
+++ b/jdk/src/java.instrument/share/classes/java/lang/instrument/package.html
@@ -1,5 +1,5 @@