--- a/.hgtags-top-repo Fri Aug 04 23:29:08 2017 +0000
+++ b/.hgtags-top-repo Thu Aug 24 16:34:26 2017 +0200
@@ -440,3 +440,4 @@
ec4159ebe7050fcc5dcee8a2d150cf948ecc97db jdk-9+178
252475ccfd84cc249f8d6faf4b7806b5e2c384ce jdk-9+179
a133a7d1007b1456bc62824382fd8ac93b45d329 jdk-10+17
+536b81db8075486ca0fe3225d8e59313df5b936c jdk-10+18
--- a/hotspot/.hgtags Fri Aug 04 23:29:08 2017 +0000
+++ b/hotspot/.hgtags Thu Aug 24 16:34:26 2017 +0200
@@ -600,3 +600,4 @@
9d032191f82fca5ba0aac98682f69c4ff0f1283d jdk-9+178
d2661aa42bff322badbe6c1337fc638d2e0f5730 jdk-9+179
73e2cb8700bfa51304bd4b02f224620859a3f600 jdk-10+17
+c9d3317623d48da3327232c81e3f8cfc0d29d888 jdk-10+18
--- a/jdk/.hgtags Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/.hgtags Thu Aug 24 16:34:26 2017 +0200
@@ -440,3 +440,4 @@
443025bee731eb2225371b92c1c74b519b7baf33 jdk-9+178
06df1ce4b9b887d05ce6a13f4def3547e434dd1a jdk-9+179
d93f2fd542b7d7855c2cd49ae15ebcc3d441a83b jdk-10+17
+c4b709bad6c5d29294124de5e74e1e2ac84fcf1f jdk-10+18
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/DESKey.java Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/DESKey.java Thu Aug 24 16:34:26 2017 +0200
@@ -31,6 +31,8 @@
import javax.crypto.SecretKey;
import javax.crypto.spec.DESKeySpec;
+import jdk.internal.ref.CleanerFactory;
+
/**
* This class represents a DES key.
*
@@ -74,6 +76,11 @@
this.key = new byte[DESKeySpec.DES_KEY_LEN];
System.arraycopy(key, offset, this.key, 0, DESKeySpec.DES_KEY_LEN);
DESKeyGenerator.setParityBit(this.key, 0);
+
+ // Use the cleaner to zero the key when no longer referenced
+ final byte[] k = this.key;
+ CleanerFactory.cleaner().register(this,
+ () -> java.util.Arrays.fill(k, (byte)0x00));
}
public byte[] getEncoded() {
@@ -144,20 +151,4 @@
getFormat(),
getEncoded());
}
-
- /**
- * Ensures that the bytes of this key are
- * set to zero when there are no more references to it.
- */
- @SuppressWarnings("deprecation")
- protected void finalize() throws Throwable {
- try {
- if (this.key != null) {
- java.util.Arrays.fill(this.key, (byte)0x00);
- this.key = null;
- }
- } finally {
- super.finalize();
- }
- }
}
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/DESedeKey.java Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/DESedeKey.java Thu Aug 24 16:34:26 2017 +0200
@@ -31,6 +31,8 @@
import javax.crypto.SecretKey;
import javax.crypto.spec.DESedeKeySpec;
+import jdk.internal.ref.CleanerFactory;
+
/**
* This class represents a DES-EDE key.
*
@@ -76,6 +78,11 @@
DESKeyGenerator.setParityBit(this.key, 0);
DESKeyGenerator.setParityBit(this.key, 8);
DESKeyGenerator.setParityBit(this.key, 16);
+
+ // Use the cleaner to zero the key when no longer referenced
+ final byte[] k = this.key;
+ CleanerFactory.cleaner().register(this,
+ () -> java.util.Arrays.fill(k, (byte)0x00));
}
public byte[] getEncoded() {
@@ -145,20 +152,4 @@
getFormat(),
getEncoded());
}
-
- /**
- * Ensures that the bytes of this key are
- * set to zero when there are no more references to it.
- */
- @SuppressWarnings("deprecation")
- protected void finalize() throws Throwable {
- try {
- if (this.key != null) {
- java.util.Arrays.fill(this.key, (byte)0x00);
- this.key = null;
- }
- } finally {
- super.finalize();
- }
- }
}
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/PBEKey.java Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/PBEKey.java Thu Aug 24 16:34:26 2017 +0200
@@ -32,6 +32,8 @@
import javax.crypto.SecretKey;
import javax.crypto.spec.PBEKeySpec;
+import jdk.internal.ref.CleanerFactory;
+
/**
* This class represents a PBE key.
*
@@ -49,7 +51,7 @@
/**
* Creates a PBE key from a given PBE key specification.
*
- * @param key the given PBE key specification
+ * @param keytype the given PBE key specification
*/
PBEKey(PBEKeySpec keySpec, String keytype) throws InvalidKeySpecException {
char[] passwd = keySpec.getPassword();
@@ -70,6 +72,11 @@
this.key[i] = (byte) (passwd[i] & 0x7f);
java.util.Arrays.fill(passwd, ' ');
type = keytype;
+
+ // Use the cleaner to zero the key when no longer referenced
+ final byte[] k = this.key;
+ CleanerFactory.cleaner().register(this,
+ () -> java.util.Arrays.fill(k, (byte)0x00));
}
public byte[] getEncoded() {
@@ -140,20 +147,4 @@
getFormat(),
getEncoded());
}
-
- /**
- * Ensures that the password bytes of this key are
- * set to zero when there are no more references to it.
- */
- @SuppressWarnings("deprecation")
- protected void finalize() throws Throwable {
- try {
- if (this.key != null) {
- java.util.Arrays.fill(this.key, (byte)0x00);
- this.key = null;
- }
- } finally {
- super.finalize();
- }
- }
}
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java Thu Aug 24 16:34:26 2017 +0200
@@ -40,6 +40,8 @@
import javax.crypto.SecretKey;
import javax.crypto.spec.PBEKeySpec;
+import jdk.internal.ref.CleanerFactory;
+
/**
* This class represents a PBE key derived using PBKDF2 defined
* in PKCS#5 v2.0. meaning that
@@ -76,7 +78,8 @@
/**
* Creates a PBE key from a given PBE key specification.
*
- * @param key the given PBE key specification
+ * @param keySpec the given PBE key specification
+ * @param prfAlgo the given PBE key algorithm
*/
PBKDF2KeyImpl(PBEKeySpec keySpec, String prfAlgo)
throws InvalidKeySpecException {
@@ -120,6 +123,15 @@
throw ike;
}
this.key = deriveKey(prf, passwdBytes, salt, iterCount, keyLength);
+
+ // Use the cleaner to zero the key when no longer referenced
+ final byte[] k = this.key;
+ final char[] p = this.passwd;
+ CleanerFactory.cleaner().register(this,
+ () -> {
+ java.util.Arrays.fill(k, (byte)0x00);
+ java.util.Arrays.fill(p, '0');
+ });
}
private static byte[] deriveKey(final Mac prf, final byte[] password,
@@ -262,24 +274,4 @@
return new KeyRep(KeyRep.Type.SECRET, getAlgorithm(),
getFormat(), getEncoded());
}
-
- /**
- * Ensures that the password bytes of this key are
- * erased when there are no more references to it.
- */
- @SuppressWarnings("deprecation")
- protected void finalize() throws Throwable {
- try {
- if (this.passwd != null) {
- java.util.Arrays.fill(this.passwd, '0');
- this.passwd = null;
- }
- if (this.key != null) {
- java.util.Arrays.fill(this.key, (byte)0x00);
- this.key = null;
- }
- } finally {
- super.finalize();
- }
- }
}
--- a/jdk/src/java.base/share/classes/java/lang/Class.java Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/Class.java Thu Aug 24 16:34:26 2017 +0200
@@ -432,18 +432,21 @@
Objects.requireNonNull(module);
Objects.requireNonNull(name);
- Class<?> caller = Reflection.getCallerClass();
- if (caller != null && caller.getModule() != module) {
- // if caller is null, Class.forName is the last java frame on the stack.
- // java.base has all permissions
- SecurityManager sm = System.getSecurityManager();
- if (sm != null) {
+ ClassLoader cl;
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ Class<?> caller = Reflection.getCallerClass();
+ if (caller != null && caller.getModule() != module) {
+ // if caller is null, Class.forName is the last java frame on the stack.
+ // java.base has all permissions
sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
}
+ PrivilegedAction<ClassLoader> pa = module::getClassLoader;
+ cl = AccessController.doPrivileged(pa);
+ } else {
+ cl = module.getClassLoader();
}
- PrivilegedAction<ClassLoader> pa = module::getClassLoader;
- ClassLoader cl = AccessController.doPrivileged(pa);
if (cl != null) {
return cl.loadClass(module, name);
} else {
--- a/jdk/src/java.base/share/classes/java/lang/Module.java Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/Module.java Thu Aug 24 16:34:26 2017 +0200
@@ -246,7 +246,6 @@
return null;
}
-
// --
// special Module to mean "all unnamed modules"
@@ -257,17 +256,38 @@
private static final Module EVERYONE_MODULE = new Module(null);
private static final Set<Module> EVERYONE_SET = Set.of(EVERYONE_MODULE);
+ /**
+ * The holder of data structures to support readability, exports, and
+ * service use added at runtime with the reflective APIs.
+ */
+ private static class ReflectionData {
+ /**
+ * A module (1st key) reads another module (2nd key)
+ */
+ static final WeakPairMap<Module, Module, Boolean> reads =
+ new WeakPairMap<>();
+
+ /**
+ * A module (1st key) exports or opens a package to another module
+ * (2nd key). The map value is a map of package name to a boolean
+ * that indicates if the package is opened.
+ */
+ static final WeakPairMap<Module, Module, Map<String, Boolean>> exports =
+ new WeakPairMap<>();
+
+ /**
+ * A module (1st key) uses a service (2nd key)
+ */
+ static final WeakPairMap<Module, Class<?>, Boolean> uses =
+ new WeakPairMap<>();
+ }
+
// -- readability --
// the modules that this module reads
private volatile Set<Module> reads;
- // additional module (2nd key) that some module (1st key) reflectively reads
- private static final WeakPairMap<Module, Module, Boolean> reflectivelyReads
- = new WeakPairMap<>();
-
-
/**
* Indicates if this module reads the given module. This method returns
* {@code true} if invoked to test if this module reads itself. It also
@@ -300,13 +320,13 @@
}
// check if this module reads the other module reflectively
- if (reflectivelyReads.containsKeyPair(this, other))
+ if (ReflectionData.reads.containsKeyPair(this, other))
return true;
// if other is an unnamed module then check if this module reads
// all unnamed modules
if (!other.isNamed()
- && reflectivelyReads.containsKeyPair(this, ALL_UNNAMED_MODULE))
+ && ReflectionData.reads.containsKeyPair(this, ALL_UNNAMED_MODULE))
return true;
return false;
@@ -393,7 +413,7 @@
}
// add reflective read
- reflectivelyReads.putIfAbsent(this, other, Boolean.TRUE);
+ ReflectionData.reads.putIfAbsent(this, other, Boolean.TRUE);
}
}
@@ -408,13 +428,6 @@
// if the value contains EVERYONE_MODULE then the package is exported to all
private volatile Map<String, Set<Module>> exportedPackages;
- // additional exports or opens added at run-time
- // this module (1st key), other module (2nd key)
- // (package name, open?) (value)
- private static final WeakPairMap<Module, Module, Map<String, Boolean>>
- reflectivelyExports = new WeakPairMap<>();
-
-
/**
* Returns {@code true} if this module exports the given package to at
* least the given module.
@@ -600,7 +613,7 @@
*/
private boolean isReflectivelyExportedOrOpen(String pn, Module other, boolean open) {
// exported or open to all modules
- Map<String, Boolean> exports = reflectivelyExports.get(this, EVERYONE_MODULE);
+ Map<String, Boolean> exports = ReflectionData.exports.get(this, EVERYONE_MODULE);
if (exports != null) {
Boolean b = exports.get(pn);
if (b != null) {
@@ -612,7 +625,7 @@
if (other != EVERYONE_MODULE) {
// exported or open to other
- exports = reflectivelyExports.get(this, other);
+ exports = ReflectionData.exports.get(this, other);
if (exports != null) {
Boolean b = exports.get(pn);
if (b != null) {
@@ -623,7 +636,7 @@
// other is an unnamed module && exported or open to all unnamed
if (!other.isNamed()) {
- exports = reflectivelyExports.get(this, ALL_UNNAMED_MODULE);
+ exports = ReflectionData.exports.get(this, ALL_UNNAMED_MODULE);
if (exports != null) {
Boolean b = exports.get(pn);
if (b != null) {
@@ -886,8 +899,8 @@
}
}
- // add package name to reflectivelyExports if absent
- Map<String, Boolean> map = reflectivelyExports
+ // add package name to exports if absent
+ Map<String, Boolean> map = ReflectionData.exports
.computeIfAbsent(this, other,
(m1, m2) -> new ConcurrentHashMap<>());
if (open) {
@@ -932,10 +945,6 @@
// -- services --
- // additional service type (2nd key) that some module (1st key) uses
- private static final WeakPairMap<Module, Class<?>, Boolean> reflectivelyUses
- = new WeakPairMap<>();
-
/**
* If the caller's module is this module then update this module to add a
* service dependence on the given service type. This method is intended
@@ -980,7 +989,7 @@
*/
void implAddUses(Class<?> service) {
if (!canUse(service)) {
- reflectivelyUses.putIfAbsent(this, service, Boolean.TRUE);
+ ReflectionData.uses.putIfAbsent(this, service, Boolean.TRUE);
}
}
@@ -1011,7 +1020,7 @@
return true;
// uses added via addUses
- return reflectivelyUses.containsKeyPair(this, service);
+ return ReflectionData.uses.containsKeyPair(this, service);
}
@@ -1060,8 +1069,11 @@
Function<String, ClassLoader> clf,
ModuleLayer layer)
{
- Map<String, Module> nameToModule = new HashMap<>();
- Map<String, ClassLoader> moduleToLoader = new HashMap<>();
+ boolean isBootLayer = (ModuleLayer.boot() == null);
+
+ int cap = (int)(cf.modules().size() / 0.75f + 1.0f);
+ Map<String, Module> nameToModule = new HashMap<>(cap);
+ Map<String, ClassLoader> nameToLoader = new HashMap<>(cap);
Set<ClassLoader> loaders = new HashSet<>();
boolean hasPlatformModules = false;
@@ -1070,7 +1082,7 @@
for (ResolvedModule resolvedModule : cf.modules()) {
String name = resolvedModule.name();
ClassLoader loader = clf.apply(name);
- moduleToLoader.put(name, loader);
+ nameToLoader.put(name, loader);
if (loader == null || loader == ClassLoaders.platformClassLoader()) {
if (!(clf instanceof ModuleLoaderMap.Mapper)) {
throw new IllegalArgumentException("loader can't be 'null'"
@@ -1087,20 +1099,19 @@
ModuleReference mref = resolvedModule.reference();
ModuleDescriptor descriptor = mref.descriptor();
String name = descriptor.name();
- URI uri = mref.location().orElse(null);
- ClassLoader loader = moduleToLoader.get(resolvedModule.name());
+ ClassLoader loader = nameToLoader.get(name);
Module m;
if (loader == null && name.equals("java.base")) {
// java.base is already defined to the VM
m = Object.class.getModule();
} else {
+ URI uri = mref.location().orElse(null);
m = new Module(layer, loader, descriptor, uri);
}
nameToModule.put(name, m);
- moduleToLoader.put(name, loader);
}
- // setup readability and exports
+ // setup readability and exports/opens
for (ResolvedModule resolvedModule : cf.modules()) {
ModuleReference mref = resolvedModule.reference();
ModuleDescriptor descriptor = mref.descriptor();
@@ -1146,7 +1157,18 @@
}
// exports and opens
- initExportsAndOpens(m, nameToSource, nameToModule, layer.parents());
+ if (descriptor.isOpen() || descriptor.isAutomatic()) {
+ // The VM doesn't special case open or automatic modules yet
+ // so need to export all packages
+ for (String source : descriptor.packages()) {
+ addExportsToAll0(m, source);
+ }
+ } else if (isBootLayer && descriptor.opens().isEmpty()) {
+ // no open packages, no qualified exports to modules in parent layers
+ initExports(m, nameToModule);
+ } else {
+ initExportsAndOpens(m, nameToSource, nameToModule, layer.parents());
+ }
}
// if there are modules defined to the boot or platform class loaders
@@ -1161,7 +1183,7 @@
if (!descriptor.provides().isEmpty()) {
String name = descriptor.name();
Module m = nameToModule.get(name);
- ClassLoader loader = moduleToLoader.get(name);
+ ClassLoader loader = nameToLoader.get(name);
if (loader == null) {
bootCatalog.register(m);
} else if (loader == pcl) {
@@ -1179,7 +1201,6 @@
return nameToModule;
}
-
/**
* Find the runtime Module corresponding to the given ResolvedModule
* in the given parent layer (or its parents).
@@ -1201,25 +1222,55 @@
.orElse(null);
}
+ /**
+ * Initialize/setup a module's exports.
+ *
+ * @param m the module
+ * @param nameToModule map of module name to Module (for qualified exports)
+ */
+ private static void initExports(Module m, Map<String, Module> nameToModule) {
+ Map<String, Set<Module>> exportedPackages = new HashMap<>();
+
+ for (Exports exports : m.getDescriptor().exports()) {
+ String source = exports.source();
+ if (exports.isQualified()) {
+ // qualified exports
+ Set<Module> targets = new HashSet<>();
+ for (String target : exports.targets()) {
+ Module m2 = nameToModule.get(target);
+ if (m2 != null) {
+ addExports0(m, source, m2);
+ targets.add(m2);
+ }
+ }
+ if (!targets.isEmpty()) {
+ exportedPackages.put(source, targets);
+ }
+ } else {
+ // unqualified exports
+ addExportsToAll0(m, source);
+ exportedPackages.put(source, EVERYONE_SET);
+ }
+ }
+
+ if (!exportedPackages.isEmpty())
+ m.exportedPackages = exportedPackages;
+ }
/**
- * Initialize the maps of exported and open packages for module m.
+ * Initialize/setup a module's exports.
+ *
+ * @param m the module
+ * @param nameToSource map of module name to Module for modules that m reads
+ * @param nameToModule map of module name to Module for modules in the layer
+ * under construction
+ * @param parents the parent layers
*/
private static void initExportsAndOpens(Module m,
Map<String, Module> nameToSource,
Map<String, Module> nameToModule,
List<ModuleLayer> parents) {
- // The VM doesn't special case open or automatic modules so need to
- // export all packages
ModuleDescriptor descriptor = m.getDescriptor();
- if (descriptor.isOpen() || descriptor.isAutomatic()) {
- assert descriptor.opens().isEmpty();
- for (String source : descriptor.packages()) {
- addExportsToAll0(m, source);
- }
- return;
- }
-
Map<String, Set<Module>> openPackages = new HashMap<>();
Map<String, Set<Module>> exportedPackages = new HashMap<>();
@@ -1272,7 +1323,6 @@
if (!targets.isEmpty()) {
exportedPackages.put(source, targets);
}
-
} else {
// unqualified exports
addExportsToAll0(m, source);
--- a/jdk/src/java.base/share/classes/java/lang/System.java Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/System.java Thu Aug 24 16:34:26 2017 +0200
@@ -313,6 +313,10 @@
* @see java.lang.RuntimePermission
*/
public static void setSecurityManager(final SecurityManager s) {
+ if (security == null) {
+ // ensure image reader is initialized
+ Object.class.getResource("java/lang/ANY");
+ }
if (s != null) {
try {
s.checkPackageAccess("java.lang");
--- a/jdk/src/java.base/share/classes/java/lang/module/Configuration.java Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/module/Configuration.java Thu Aug 24 16:34:26 2017 +0200
@@ -31,6 +31,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -41,6 +42,9 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;
+import jdk.internal.module.ModuleReferenceImpl;
+import jdk.internal.module.ModuleTarget;
+
/**
* A configuration that is the result of <a href="package-summary.html#resolution">
* resolution</a> or resolution with <a href="#service-binding">service binding</a>.
@@ -121,11 +125,8 @@
this.targetPlatform = null;
}
- private Configuration(List<Configuration> parents,
- Resolver resolver,
- boolean check)
- {
- Map<ResolvedModule, Set<ResolvedModule>> g = resolver.finish(this, check);
+ private Configuration(List<Configuration> parents, Resolver resolver) {
+ Map<ResolvedModule, Set<ResolvedModule>> g = resolver.finish(this);
@SuppressWarnings(value = {"rawtypes", "unchecked"})
Entry<String, ResolvedModule>[] nameEntries
@@ -147,6 +148,62 @@
}
/**
+ * Creates the Configuration for the boot layer from a pre-generated
+ * readability graph.
+ *
+ * @apiNote This method is coded for startup performance.
+ */
+ Configuration(ModuleFinder finder, Map<String, Set<String>> map) {
+ int moduleCount = map.size();
+
+ // create map of name -> ResolvedModule
+ @SuppressWarnings(value = {"rawtypes", "unchecked"})
+ Entry<String, ResolvedModule>[] nameEntries
+ = (Entry<String, ResolvedModule>[])new Entry[moduleCount];
+ ResolvedModule[] moduleArray = new ResolvedModule[moduleCount];
+ String targetPlatform = null;
+ int i = 0;
+ for (String name : map.keySet()) {
+ ModuleReference mref = finder.find(name).orElse(null);
+ assert mref != null;
+
+ if (targetPlatform == null && mref instanceof ModuleReferenceImpl) {
+ ModuleTarget target = ((ModuleReferenceImpl)mref).moduleTarget();
+ if (target != null) {
+ targetPlatform = target.targetPlatform();
+ }
+ }
+
+ ResolvedModule resolvedModule = new ResolvedModule(this, mref);
+ moduleArray[i] = resolvedModule;
+ nameEntries[i] = Map.entry(name, resolvedModule);
+ i++;
+ }
+ Map<String, ResolvedModule> nameToModule = Map.ofEntries(nameEntries);
+
+ // create entries for readability graph
+ @SuppressWarnings(value = {"rawtypes", "unchecked"})
+ Entry<ResolvedModule, Set<ResolvedModule>>[] moduleEntries
+ = (Entry<ResolvedModule, Set<ResolvedModule>>[])new Entry[moduleCount];
+ i = 0;
+ for (ResolvedModule resolvedModule : moduleArray) {
+ Set<String> names = map.get(resolvedModule.name());
+ ResolvedModule[] readsArray = new ResolvedModule[names.size()];
+ int j = 0;
+ for (String name : names) {
+ readsArray[j++] = nameToModule.get(name);
+ }
+ moduleEntries[i++] = Map.entry(resolvedModule, Set.of(readsArray));
+ }
+
+ this.parents = List.of(empty());
+ this.graph = Map.ofEntries(moduleEntries);
+ this.modules = Set.of(moduleArray);
+ this.nameToModule = nameToModule;
+ this.targetPlatform = targetPlatform;
+ }
+
+ /**
* Resolves a collection of root modules, with this configuration as its
* parent, to create a new configuration. This method works exactly as
* specified by the static {@link
@@ -233,24 +290,20 @@
/**
* Resolves a collection of root modules, with service binding, and with
- * the empty configuration as its parent. The consistency checks
- * are optionally run.
+ * the empty configuration as its parent.
*
* This method is used to create the configuration for the boot layer.
*/
static Configuration resolveAndBind(ModuleFinder finder,
Collection<String> roots,
- boolean check,
PrintStream traceOutput)
{
List<Configuration> parents = List.of(empty());
Resolver resolver = new Resolver(finder, parents, ModuleFinder.of(), traceOutput);
resolver.resolve(roots).bind();
-
- return new Configuration(parents, resolver, check);
+ return new Configuration(parents, resolver);
}
-
/**
* Resolves a collection of root modules to create a configuration.
*
@@ -356,7 +409,7 @@
Resolver resolver = new Resolver(before, parentList, after, null);
resolver.resolve(roots);
- return new Configuration(parentList, resolver, true);
+ return new Configuration(parentList, resolver);
}
/**
@@ -427,7 +480,7 @@
Resolver resolver = new Resolver(before, parentList, after, null);
resolver.resolve(roots).bind();
- return new Configuration(parentList, resolver, true);
+ return new Configuration(parentList, resolver);
}
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java Thu Aug 24 16:34:26 2017 +0200
@@ -2728,10 +2728,15 @@
@Override
public Configuration resolveAndBind(ModuleFinder finder,
Collection<String> roots,
- boolean check,
PrintStream traceOutput)
{
- return Configuration.resolveAndBind(finder, roots, check, traceOutput);
+ return Configuration.resolveAndBind(finder, roots, traceOutput);
+ }
+
+ @Override
+ public Configuration newConfiguration(ModuleFinder finder,
+ Map<String, Set<String>> graph) {
+ return new Configuration(finder, graph);
}
});
}
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java Thu Aug 24 16:34:26 2017 +0200
@@ -25,9 +25,7 @@
package java.lang.module;
-import java.nio.file.Files;
import java.nio.file.Path;
-import java.nio.file.Paths;
import java.security.AccessController;
import java.security.Permission;
import java.security.PrivilegedAction;
@@ -40,10 +38,8 @@
import java.util.Optional;
import java.util.Set;
-import jdk.internal.module.ModuleBootstrap;
-import jdk.internal.module.ModulePatcher;
import jdk.internal.module.ModulePath;
-import jdk.internal.module.SystemModuleFinder;
+import jdk.internal.module.SystemModuleFinders;
/**
* A finder of modules. A {@code ModuleFinder} is used to find modules during
@@ -157,53 +153,14 @@
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("accessSystemModules"));
- PrivilegedAction<ModuleFinder> pa = ModuleFinder::privilegedOfSystem;
+ PrivilegedAction<ModuleFinder> pa = SystemModuleFinders::ofSystem;
return AccessController.doPrivileged(pa);
} else {
- return privilegedOfSystem();
- }
- }
-
- /**
- * Returns a module finder that locates the system modules. This method
- * assumes it has permissions to access the runtime image.
- */
- private static ModuleFinder privilegedOfSystem() {
- String home = System.getProperty("java.home");
- Path modules = Paths.get(home, "lib", "modules");
- if (Files.isRegularFile(modules)) {
- return SystemModuleFinder.getInstance();
- } else {
- Path dir = Paths.get(home, "modules");
- if (Files.isDirectory(dir)) {
- return privilegedOf(ModuleBootstrap.patcher(), dir);
- } else {
- throw new InternalError("Unable to detect the run-time image");
- }
+ return SystemModuleFinders.ofSystem();
}
}
/**
- * Returns a module finder that locates the system modules in an exploded
- * image. The image may be patched.
- */
- private static ModuleFinder privilegedOf(ModulePatcher patcher, Path dir) {
- ModuleFinder finder = ModulePath.of(patcher, dir);
- return new ModuleFinder() {
- @Override
- public Optional<ModuleReference> find(String name) {
- PrivilegedAction<Optional<ModuleReference>> pa = () -> finder.find(name);
- return AccessController.doPrivileged(pa);
- }
- @Override
- public Set<ModuleReference> findAll() {
- PrivilegedAction<Set<ModuleReference>> pa = finder::findAll;
- return AccessController.doPrivileged(pa);
- }
- };
- }
-
- /**
* Returns a module finder that locates modules on the file system by
* searching a sequence of directories and/or packaged modules.
*
--- a/jdk/src/java.base/share/classes/java/lang/module/Resolver.java Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/module/Resolver.java Thu Aug 24 16:34:26 2017 +0200
@@ -353,25 +353,13 @@
/**
* Execute post-resolution checks and returns the module graph of resolved
- * modules as {@code Map}. The resolved modules will be in the given
- * configuration.
- *
- * @param check {@true} to execute the post resolution checks
+ * modules as a map.
*/
- Map<ResolvedModule, Set<ResolvedModule>> finish(Configuration cf,
- boolean check)
- {
- if (check) {
- detectCycles();
- checkHashes();
- }
-
+ Map<ResolvedModule, Set<ResolvedModule>> finish(Configuration cf) {
+ detectCycles();
+ checkHashes();
Map<ResolvedModule, Set<ResolvedModule>> graph = makeGraph(cf);
-
- if (check) {
- checkExportSuppliers(graph);
- }
-
+ checkExportSuppliers(graph);
return graph;
}
--- a/jdk/src/java.base/share/classes/java/net/URL.java Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/src/java.base/share/classes/java/net/URL.java Thu Aug 24 16:34:26 2017 +0200
@@ -409,7 +409,7 @@
}
}
- protocol = protocol.toLowerCase(Locale.ROOT);
+ protocol = toLowerCase(protocol);
this.protocol = protocol;
if (host != null) {
@@ -585,7 +585,7 @@
for (i = start ; !aRef && (i < limit) &&
((c = spec.charAt(i)) != '/') ; i++) {
if (c == ':') {
- String s = spec.substring(start, i).toLowerCase(Locale.ROOT);
+ String s = toLowerCase(spec.substring(start, i));
if (isValidProtocol(s)) {
newProtocol = s;
start = i + 1;
@@ -1318,6 +1318,17 @@
}
}
+ /**
+ * Returns the protocol in lower case. Special cases known protocols
+ * to avoid loading locale classes during startup.
+ */
+ static String toLowerCase(String protocol) {
+ if (protocol.equals("jrt") || protocol.equals("file") || protocol.equals("jar")) {
+ return protocol;
+ } else {
+ return protocol.toLowerCase(Locale.ROOT);
+ }
+ }
/**
* Non-overrideable protocols: "jrt" and "file"
--- a/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java Thu Aug 24 16:34:26 2017 +0200
@@ -55,13 +55,13 @@
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
import java.util.stream.Stream;
import jdk.internal.misc.VM;
import jdk.internal.module.ModulePatcher.PatchedModuleReader;
-import jdk.internal.module.SystemModules;
import jdk.internal.module.Resources;
@@ -139,7 +139,7 @@
// maps package name to loaded module for modules in the boot layer
private static final Map<String, LoadedModule> packageToModule
- = new ConcurrentHashMap<>(SystemModules.PACKAGES_IN_BOOT_LAYER);
+ = new ConcurrentHashMap<>(1024);
// maps a module name to a module reference
private final Map<String, ModuleReference> nameToModule;
@@ -946,9 +946,16 @@
URL url = cs.getLocation();
if (url == null)
return perms;
- Permission p = null;
+
+ // avoid opening connection when URL is to resource in run-time image
+ if (url.getProtocol().equals("jrt")) {
+ perms.add(new RuntimePermission("accessSystemModules"));
+ return perms;
+ }
+
+ // open connection to determine the permission needed
try {
- p = url.openConnection().getPermission();
+ Permission p = url.openConnection().getPermission();
if (p != null) {
// for directories then need recursive access
if (p instanceof FilePermission) {
@@ -969,23 +976,26 @@
// -- miscellaneous supporting methods
/**
- * Returns the ModuleReader for the given module.
+ * Returns the ModuleReader for the given module, creating it if needed
*/
private ModuleReader moduleReaderFor(ModuleReference mref) {
- return moduleToReader.computeIfAbsent(mref, BuiltinClassLoader::createModuleReader);
- }
-
- /**
- * Creates a ModuleReader for the given module.
- */
- private static ModuleReader createModuleReader(ModuleReference mref) {
- try {
- return mref.open();
- } catch (IOException e) {
- // Return a null module reader to avoid a future class load
- // attempting to open the module again.
- return new NullModuleReader();
+ ModuleReader reader = moduleToReader.get(mref);
+ if (reader == null) {
+ // avoid method reference during startup
+ Function<ModuleReference, ModuleReader> create = new Function<>() {
+ public ModuleReader apply(ModuleReference moduleReference) {
+ try {
+ return mref.open();
+ } catch (IOException e) {
+ // Return a null module reader to avoid a future class
+ // load attempting to open the module again.
+ return new NullModuleReader();
+ }
+ }
+ };
+ reader = moduleToReader.computeIfAbsent(mref, create);
}
+ return reader;
}
/**
--- a/jdk/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java Thu Aug 24 16:34:26 2017 +0200
@@ -25,7 +25,6 @@
package jdk.internal.loader;
-import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.file.InvalidPathException;
@@ -38,7 +37,6 @@
import jdk.internal.misc.SharedSecrets;
import jdk.internal.misc.VM;
-
/**
* Creates and provides access to the built-in platform and application class
* loaders. It also creates the class loader that is used to locate resources
@@ -61,23 +59,30 @@
*/
static {
- // -Xbootclasspth/a or -javaagent Boot-Class-Path
+ // -Xbootclasspath/a or -javaagent with Boot-Class-Path attribute
URLClassPath bcp = null;
String s = VM.getSavedProperty("jdk.boot.class.path.append");
if (s != null && s.length() > 0)
- bcp = toURLClassPath(s);
+ bcp = new URLClassPath(s, true);
// we have a class path if -cp is specified or -m is not specified.
// If neither is specified then default to -cp <working directory>
// If -cp is not specified and -m is specified, the value of
// java.class.path is an empty string, then no class path.
- URLClassPath ucp = new URLClassPath(new URL[0]);
String mainMid = System.getProperty("jdk.module.main");
String cp = System.getProperty("java.class.path");
- if (cp == null)
- cp = "";
- if (mainMid == null || cp.length() > 0)
- addClassPathToUCP(cp, ucp);
+ if (mainMid == null) {
+ // no main module specified so class path required
+ if (cp == null) {
+ cp = "";
+ }
+ } else {
+ // main module specified, ignore empty class path
+ if (cp != null && cp.length() == 0) {
+ cp = null;
+ }
+ }
+ URLClassPath ucp = new URLClassPath(cp, false);
// create the class loaders
BOOT_LOADER = new BootClassLoader(bcp);
@@ -198,7 +203,7 @@
* @see java.lang.instrument.Instrumentation#appendToSystemClassLoaderSearch
*/
void appendToClassPathForInstrumentation(String path) {
- addClassPathToUCP(path, ucp);
+ ucp.addFile(path);
}
/**
@@ -220,40 +225,11 @@
}
/**
- * Returns a {@code URLClassPath} of file URLs to each of the elements in
- * the given class path.
- */
- private static URLClassPath toURLClassPath(String cp) {
- URLClassPath ucp = new URLClassPath(new URL[0]);
- addClassPathToUCP(cp, ucp);
- return ucp;
- }
-
- /**
- * Converts the elements in the given class path to file URLs and adds
- * them to the given URLClassPath.
- */
- private static void addClassPathToUCP(String cp, URLClassPath ucp) {
- int off = 0;
- int next;
- while ((next = cp.indexOf(File.pathSeparator, off)) != -1) {
- URL url = toFileURL(cp.substring(off, next));
- if (url != null)
- ucp.addURL(url);
- off = next + 1;
- }
-
- // remaining
- URL url = toFileURL(cp.substring(off));
- if (url != null)
- ucp.addURL(url);
- }
-
- /**
* Attempts to convert the given string to a file URL.
*
* @apiNote This is called by the VM
*/
+ @Deprecated
private static URL toFileURL(String s) {
try {
// Use an intermediate File object to construct a URI/URL without
@@ -265,5 +241,4 @@
return null;
}
}
-
}
--- a/jdk/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java Thu Aug 24 16:34:26 2017 +0200
@@ -46,6 +46,7 @@
import java.security.PrivilegedExceptionAction;
import java.security.cert.Certificate;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
@@ -66,7 +67,6 @@
import java.util.zip.ZipFile;
import jdk.internal.misc.JavaNetURLAccess;
-import jdk.internal.misc.JavaNetURLClassLoaderAccess;
import jdk.internal.misc.JavaUtilZipFileAccess;
import jdk.internal.misc.SharedSecrets;
import jdk.internal.util.jar.InvalidJarIndexError;
@@ -100,19 +100,19 @@
}
/* The original search path of URLs. */
- private ArrayList<URL> path = new ArrayList<>();
+ private final List<URL> path;
/* The stack of unopened URLs */
- Stack<URL> urls = new Stack<>();
+ private final Stack<URL> urls = new Stack<>();
/* The resulting search path of Loaders */
- ArrayList<Loader> loaders = new ArrayList<>();
+ private final ArrayList<Loader> loaders = new ArrayList<>();
/* Map of each URL opened to its corresponding Loader */
- HashMap<String, Loader> lmap = new HashMap<>();
+ private final HashMap<String, Loader> lmap = new HashMap<>();
/* The jar protocol handler to use when creating new URLs */
- private URLStreamHandler jarHandler;
+ private final URLStreamHandler jarHandler;
/* Whether this URLClassLoader has been closed yet */
private boolean closed = false;
@@ -137,12 +137,16 @@
public URLClassPath(URL[] urls,
URLStreamHandlerFactory factory,
AccessControlContext acc) {
- for (int i = 0; i < urls.length; i++) {
- path.add(urls[i]);
+ List<URL> path = new ArrayList<>(urls.length);
+ for (URL url : urls) {
+ path.add(url);
}
+ this.path = path;
push(urls);
if (factory != null) {
jarHandler = factory.createURLStreamHandler("jar");
+ } else {
+ jarHandler = null;
}
if (DISABLE_ACC_CHECKING)
this.acc = null;
@@ -150,16 +154,50 @@
this.acc = acc;
}
- /**
- * Constructs a URLClassPath with no additional security restrictions.
- * Used by code that implements the class path.
- */
- public URLClassPath(URL[] urls) {
- this(urls, null, null);
+ public URLClassPath(URL[] urls, AccessControlContext acc) {
+ this(urls, null, acc);
}
- public URLClassPath(URL[] urls, AccessControlContext acc) {
- this(urls, null, acc);
+ /**
+ * Constructs a URLClassPath from a class path string.
+ *
+ * @param cp the class path string
+ * @param skipEmptyElements indicates if empty elements are ignored or
+ * treated as the current working directory
+ *
+ * @apiNote Used to create the application class path.
+ */
+ URLClassPath(String cp, boolean skipEmptyElements) {
+ List<URL> path = new ArrayList<>();
+ if (cp != null) {
+ // map each element of class path to a file URL
+ int off = 0;
+ int next;
+ while ((next = cp.indexOf(File.pathSeparator, off)) != -1) {
+ String element = cp.substring(off, next);
+ if (element.length() > 0 || !skipEmptyElements) {
+ URL url = toFileURL(element);
+ if (url != null) path.add(url);
+ }
+ off = next + 1;
+ }
+
+ // remaining element
+ String element = cp.substring(off);
+ if (element.length() > 0 || !skipEmptyElements) {
+ URL url = toFileURL(element);
+ if (url != null) path.add(url);
+ }
+
+ // push the URLs
+ for (int i = path.size() - 1; i >= 0; --i) {
+ urls.push(path.get(i));
+ }
+ }
+
+ this.path = path;
+ this.jarHandler = null;
+ this.acc = null;
}
public synchronized List<IOException> closeLoaders() {
@@ -198,6 +236,28 @@
}
/**
+ * Appends the specified file path as a file URL to the search path.
+ */
+ public void addFile(String s) {
+ URL url = toFileURL(s);
+ if (url != null) {
+ addURL(url);
+ }
+ }
+
+ /**
+ * Returns a file URL for the given file path.
+ */
+ private static URL toFileURL(String s) {
+ try {
+ File f = new File(s).getCanonicalFile();
+ return ParseUtil.fileToEncodedURL(f);
+ } catch (IOException e) {
+ return null;
+ }
+ }
+
+ /**
* Returns the original search path of URLs.
*/
public URL[] getURLs() {
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java Thu Aug 24 16:34:26 2017 +0200
@@ -34,16 +34,10 @@
import java.lang.module.ModuleDescriptor.Provides;
import java.lang.module.ModuleDescriptor.Version;
import java.lang.module.ModuleFinder;
-import java.lang.module.ModuleReader;
-import java.lang.module.ModuleReference;
-import java.net.URI;
-import java.nio.file.Path;
import java.util.Collection;
import java.util.List;
+import java.util.Map;
import java.util.Set;
-import java.util.function.Supplier;
-
-import jdk.internal.module.ModuleHashes;
/**
* Provides access to non-public methods in java.lang.module.
@@ -131,12 +125,16 @@
/**
* Resolves a collection of root modules, with service binding
- * and the empty configuration as the parent. The post resolution
- * checks are optionally run.
+ * and the empty configuration as the parent.
*/
Configuration resolveAndBind(ModuleFinder finder,
Collection<String> roots,
- boolean check,
PrintStream traceOutput);
+ /**
+ * Creates a configuration from a pre-generated readability graph.
+ */
+ Configuration newConfiguration(ModuleFinder finder,
+ Map<String, Set<String>> graph);
+
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/DefaultRoots.java Thu Aug 24 16:34:26 2017 +0200
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.module;
+
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReference;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Defines methods to compute the default set of root modules for the unnamed
+ * module.
+ */
+
+public final class DefaultRoots {
+ private static final String JAVA_SE = "java.se";
+
+ private DefaultRoots() { }
+
+ /**
+ * Returns the default set of root modules for the unnamed module computed from
+ * the system modules observable with the given module finder.
+ */
+ static Set<String> compute(ModuleFinder systemModuleFinder, ModuleFinder finder) {
+ Set<String> roots = new HashSet<>();
+
+ boolean hasJava = false;
+ if (systemModuleFinder.find(JAVA_SE).isPresent()) {
+ if (finder == systemModuleFinder || finder.find(JAVA_SE).isPresent()) {
+ // java.se is a system module
+ hasJava = true;
+ roots.add(JAVA_SE);
+ }
+ }
+
+ for (ModuleReference mref : systemModuleFinder.findAll()) {
+ String mn = mref.descriptor().name();
+ if (hasJava && mn.startsWith("java.")) {
+ // not a root
+ continue;
+ }
+
+ if (ModuleResolution.doNotResolveByDefault(mref)) {
+ // not a root
+ continue;
+ }
+
+ if ((finder == systemModuleFinder || finder.find(mn).isPresent())) {
+ // add as root if exports at least one package to all modules
+ ModuleDescriptor descriptor = mref.descriptor();
+ for (ModuleDescriptor.Exports e : descriptor.exports()) {
+ if (!e.isQualified()) {
+ roots.add(mn);
+ break;
+ }
+ }
+ }
+ }
+
+ return roots;
+ }
+
+ /**
+ * Returns the default set of root modules for the unnamed module from the
+ * modules observable with the given module finder.
+ */
+ public static Set<String> compute(ModuleFinder finder) {
+ return compute(finder, finder);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ExplodedSystemModules.java Thu Aug 24 16:34:26 2017 +0200
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.module;
+
+import java.lang.module.ModuleDescriptor;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A dummy SystemModules for use with exploded builds or testing.
+ */
+
+class ExplodedSystemModules implements SystemModules {
+ @Override
+ public boolean hasSplitPackages() {
+ return true; // not known
+ }
+
+ @Override
+ public boolean hasIncubatorModules() {
+ return true; // not known
+ }
+
+ @Override
+ public ModuleDescriptor[] moduleDescriptors() {
+ throw new InternalError();
+ }
+
+ @Override
+ public ModuleTarget[] moduleTargets() {
+ throw new InternalError();
+ }
+
+ @Override
+ public ModuleHashes[] moduleHashes() {
+ throw new InternalError();
+ }
+
+ @Override
+ public ModuleResolution[] moduleResolutions() {
+ throw new InternalError();
+ }
+
+ @Override
+ public Map<String, Set<String>> moduleReads() {
+ throw new InternalError();
+ }
+
+ @Override
+ public Map<String, Set<String>> concealedPackagesToOpen() {
+ return Collections.emptyMap();
+ }
+
+ @Override
+ public Map<String, Set<String>> exportedPackagesToOpen() {
+ return Collections.emptyMap();
+ }
+}
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java Thu Aug 24 16:34:26 2017 +0200
@@ -40,16 +40,20 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
+import java.util.Objects;
import java.util.Optional;
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.misc.JavaLangAccess;
+import jdk.internal.misc.JavaLangModuleAccess;
import jdk.internal.misc.SharedSecrets;
import jdk.internal.perf.PerfCounter;
@@ -70,8 +74,6 @@
private static final String JAVA_BASE = "java.base";
- private static final String JAVA_SE = "java.se";
-
// the token for "all default modules"
private static final String ALL_DEFAULT = "ALL-DEFAULT";
@@ -84,13 +86,13 @@
// the token for "all modules on the module path"
private static final String ALL_MODULE_PATH = "ALL-MODULE-PATH";
+ // access to java.lang/module
+ private static final JavaLangModuleAccess JLMA
+ = SharedSecrets.getJavaLangModuleAccess();
+
// The ModulePatcher for the initial configuration
private static final ModulePatcher patcher = initModulePatcher();
- // ModuleFinders for the initial configuration
- private static ModuleFinder unlimitedFinder;
- private static ModuleFinder limitedFinder;
-
/**
* Returns the ModulePatcher for the initial configuration.
*/
@@ -98,21 +100,38 @@
return patcher;
}
+ // ModuleFinders for the initial configuration
+ private static volatile ModuleFinder unlimitedFinder;
+ private static volatile ModuleFinder limitedFinder;
+
/**
- * Returns the ModuleFinder for the initial configuration before observability
- * is limited by the --limit-modules command line option.
+ * Returns the ModuleFinder for the initial configuration before
+ * observability is limited by the --limit-modules command line option.
+ *
+ * @apiNote Used to support locating modules {@code java.instrument} and
+ * {@code jdk.management.agent} modules when they are loaded dynamically.
*/
public static ModuleFinder unlimitedFinder() {
- assert unlimitedFinder != null;
- return unlimitedFinder;
+ ModuleFinder finder = unlimitedFinder;
+ if (finder == null) {
+ return ModuleFinder.ofSystem();
+ } else {
+ return finder;
+ }
}
/**
* Returns the ModuleFinder for the initial configuration.
+ *
+ * @apiNote Used to support "{@code java --list-modules}".
*/
public static ModuleFinder limitedFinder() {
- assert limitedFinder != null;
- return limitedFinder;
+ ModuleFinder finder = limitedFinder;
+ if (finder == null) {
+ return unlimitedFinder();
+ } else {
+ return finder;
+ }
}
/**
@@ -120,13 +139,60 @@
*
* @see java.lang.System#initPhase2()
*/
- public static ModuleLayer boot() {
+ public static ModuleLayer boot() throws Exception {
+
+ // Step 0: Command line options
+
+ long t0 = System.nanoTime();
+
+ ModuleFinder upgradeModulePath = finderFor("jdk.module.upgrade.path");
+ ModuleFinder appModulePath = finderFor("jdk.module.path");
+ boolean isPatched = patcher.hasPatches();
- // Step 1: Locate system modules (may be patched)
+ String mainModule = System.getProperty("jdk.module.main");
+ Set<String> addModules = addModules();
+ Set<String> limitModules = limitModules();
+
+ PrintStream traceOutput = null;
+ String trace = getAndRemoveProperty("jdk.module.showModuleResolution");
+ if (trace != null && Boolean.parseBoolean(trace))
+ traceOutput = System.out;
+
+
+ // Step 1: The observable system modules, either all system modules
+ // or the system modules pre-generated for the initial module (the
+ // initial module may be the unnamed module). If the system modules
+ // are pre-generated for the initial module then resolution can be
+ // skipped.
long t1 = System.nanoTime();
- ModuleFinder systemModules = ModuleFinder.ofSystem();
- PerfCounters.systemModulesTime.addElapsedTimeFrom(t1);
+
+ SystemModules systemModules = null;
+ ModuleFinder systemModuleFinder;
+
+ boolean haveModulePath = (appModulePath != null || upgradeModulePath != null);
+ boolean needResolution = true;
+
+ if (!haveModulePath && addModules.isEmpty() && limitModules.isEmpty()) {
+ systemModules = SystemModuleFinders.systemModules(mainModule);
+ if (systemModules != null && !isPatched && (traceOutput == null)) {
+ needResolution = false;
+ }
+ }
+ if (systemModules == null) {
+ // all system modules are observable
+ systemModules = SystemModuleFinders.allSystemModules();
+ }
+ if (systemModules != null) {
+ // images build
+ systemModuleFinder = SystemModuleFinders.of(systemModules);
+ } else {
+ // exploded build or testing
+ systemModules = new ExplodedSystemModules();
+ systemModuleFinder = SystemModuleFinders.ofSystem();
+ }
+
+ Counters.add("jdk.module.boot.1.systemModulesTime", t1);
// Step 2: Define and load java.base. This patches all classes loaded
@@ -136,7 +202,7 @@
long t2 = System.nanoTime();
- ModuleReference base = systemModules.find(JAVA_BASE).orElse(null);
+ ModuleReference base = systemModuleFinder.find(JAVA_BASE).orElse(null);
if (base == null)
throw new InternalError(JAVA_BASE + " not found");
URI baseUri = base.location().orElse(null);
@@ -145,171 +211,138 @@
BootLoader.loadModule(base);
Modules.defineModule(null, base.descriptor(), baseUri);
- PerfCounters.defineBaseTime.addElapsedTimeFrom(t2);
+ Counters.add("jdk.module.boot.2.defineBaseTime", t2);
// Step 2a: If --validate-modules is specified then the VM needs to
// start with only java.base, all other options are ignored.
- String propValue = getAndRemoveProperty("jdk.module.minimumBoot");
- if (propValue != null) {
+ if (getAndRemoveProperty("jdk.module.minimumBoot") != null) {
return createMinimalBootLayer();
}
- // Step 3: Construct the module path and the set of root modules to
- // resolve. If --limit-modules is specified then it limits the set
- // modules that are observable.
+ // Step 3: If resolution is needed then create the module finder and
+ // the set of root modules to resolve.
long t3 = System.nanoTime();
- // --upgrade-module-path option specified to launcher
- ModuleFinder upgradeModulePath
- = createModulePathFinder("jdk.module.upgrade.path");
- if (upgradeModulePath != null)
- systemModules = ModuleFinder.compose(upgradeModulePath, systemModules);
+ ModuleFinder savedModuleFinder = null;
+ ModuleFinder finder;
+ Set<String> roots;
+ if (needResolution) {
- // --module-path option specified to the launcher
- ModuleFinder appModulePath = createModulePathFinder("jdk.module.path");
+ // upgraded modules override the modules in the run-time image
+ if (upgradeModulePath != null)
+ systemModuleFinder = ModuleFinder.compose(upgradeModulePath,
+ systemModuleFinder);
- // The module finder: [--upgrade-module-path] system [--module-path]
- ModuleFinder finder = systemModules;
- if (appModulePath != null)
- finder = ModuleFinder.compose(finder, appModulePath);
+ // The module finder: [--upgrade-module-path] system [--module-path]
+ if (appModulePath != null) {
+ finder = ModuleFinder.compose(systemModuleFinder, appModulePath);
+ } else {
+ finder = systemModuleFinder;
+ }
- // The root modules to resolve
- Set<String> roots = new HashSet<>();
-
- // launcher -m option to specify the main/initial module
- String mainModule = System.getProperty("jdk.module.main");
- if (mainModule != null)
- roots.add(mainModule);
+ // The root modules to resolve
+ roots = new HashSet<>();
- // additional module(s) specified by --add-modules
- boolean addAllDefaultModules = false;
- boolean addAllSystemModules = false;
- boolean addAllApplicationModules = false;
- for (String mod: getExtraAddModules()) {
- switch (mod) {
- case ALL_DEFAULT:
- addAllDefaultModules = true;
- break;
- case ALL_SYSTEM:
- addAllSystemModules = true;
- break;
- case ALL_MODULE_PATH:
- addAllApplicationModules = true;
- break;
- default :
- roots.add(mod);
- }
- }
+ // launcher -m option to specify the main/initial module
+ if (mainModule != null)
+ roots.add(mainModule);
- // --limit-modules
- unlimitedFinder = finder;
- propValue = getAndRemoveProperty("jdk.module.limitmods");
- if (propValue != null) {
- Set<String> mods = new HashSet<>();
- for (String mod: propValue.split(",")) {
- mods.add(mod);
- }
- 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
- // is implemented by resolving "java.se" and all (non-java.*) modules
- // that export an API. If "java.se" is not observable then all java.*
- // modules are resolved. Modules that have the DO_NOT_RESOLVE_BY_DEFAULT
- // bit set in their ModuleResolution attribute flags are excluded from
- // the default set of roots.
- if (mainModule == null || addAllDefaultModules) {
- boolean hasJava = false;
- if (systemModules.find(JAVA_SE).isPresent()) {
- // java.se is a system module
- if (finder == systemModules || finder.find(JAVA_SE).isPresent()) {
- // java.se is observable
- hasJava = true;
- roots.add(JAVA_SE);
+ // additional module(s) specified by --add-modules
+ boolean addAllDefaultModules = false;
+ boolean addAllSystemModules = false;
+ boolean addAllApplicationModules = false;
+ for (String mod : addModules) {
+ switch (mod) {
+ case ALL_DEFAULT:
+ addAllDefaultModules = true;
+ break;
+ case ALL_SYSTEM:
+ addAllSystemModules = true;
+ break;
+ case ALL_MODULE_PATH:
+ addAllApplicationModules = true;
+ break;
+ default:
+ roots.add(mod);
}
}
- for (ModuleReference mref : systemModules.findAll()) {
- String mn = mref.descriptor().name();
- if (hasJava && mn.startsWith("java."))
- continue;
+ // --limit-modules
+ savedModuleFinder = finder;
+ if (!limitModules.isEmpty()) {
+ finder = limitFinder(finder, limitModules, roots);
+ }
- if (ModuleResolution.doNotResolveByDefault(mref))
- continue;
+ // If there is no initial module specified then assume that the initial
+ // module is the unnamed module of the application class loader. This
+ // is implemented by resolving "java.se" and all (non-java.*) modules
+ // that export an API. If "java.se" is not observable then all java.*
+ // modules are resolved. Modules that have the DO_NOT_RESOLVE_BY_DEFAULT
+ // bit set in their ModuleResolution attribute flags are excluded from
+ // the default set of roots.
+ if (mainModule == null || addAllDefaultModules) {
+ roots.addAll(DefaultRoots.compute(systemModuleFinder, finder));
+ }
- // add as root if observable and exports at least one package
- if ((finder == systemModules || finder.find(mn).isPresent())) {
- ModuleDescriptor descriptor = mref.descriptor();
- for (ModuleDescriptor.Exports e : descriptor.exports()) {
- if (!e.isQualified()) {
- roots.add(mn);
- break;
- }
- }
- }
+ // If `--add-modules ALL-SYSTEM` is specified then all observable system
+ // modules will be resolved.
+ if (addAllSystemModules) {
+ ModuleFinder f = finder; // observable modules
+ systemModuleFinder.findAll()
+ .stream()
+ .map(ModuleReference::descriptor)
+ .map(ModuleDescriptor::name)
+ .filter(mn -> f.find(mn).isPresent()) // observable
+ .forEach(mn -> roots.add(mn));
}
+
+ // If `--add-modules ALL-MODULE-PATH` is specified then all observable
+ // modules on the application module path will be resolved.
+ if (appModulePath != null && addAllApplicationModules) {
+ ModuleFinder f = finder; // observable modules
+ appModulePath.findAll()
+ .stream()
+ .map(ModuleReference::descriptor)
+ .map(ModuleDescriptor::name)
+ .filter(mn -> f.find(mn).isPresent()) // observable
+ .forEach(mn -> roots.add(mn));
+ }
+ } else {
+ // no resolution case
+ finder = systemModuleFinder;
+ roots = null;
}
- // If `--add-modules ALL-SYSTEM` is specified then all observable system
- // modules will be resolved.
- if (addAllSystemModules) {
- ModuleFinder f = finder; // observable modules
- systemModules.findAll()
- .stream()
- .map(ModuleReference::descriptor)
- .map(ModuleDescriptor::name)
- .filter(mn -> f.find(mn).isPresent()) // observable
- .forEach(mn -> roots.add(mn));
- }
-
- // If `--add-modules ALL-MODULE-PATH` is specified then all observable
- // modules on the application module path will be resolved.
- if (appModulePath != null && addAllApplicationModules) {
- ModuleFinder f = finder; // observable modules
- appModulePath.findAll()
- .stream()
- .map(ModuleReference::descriptor)
- .map(ModuleDescriptor::name)
- .filter(mn -> f.find(mn).isPresent()) // observable
- .forEach(mn -> roots.add(mn));
- }
-
- PerfCounters.optionsAndRootsTime.addElapsedTimeFrom(t3);
-
+ Counters.add("jdk.module.boot.3.optionsAndRootsTime", t3);
// Step 4: Resolve the root modules, with service binding, to create
- // the configuration for the boot layer.
+ // the configuration for the boot layer. If resolution is not needed
+ // then create the configuration for the boot layer from the
+ // readability graph created at link time.
long t4 = System.nanoTime();
- // determine if post resolution checks are needed
- boolean needPostResolutionChecks = true;
- if (baseUri.getScheme().equals("jrt") // toLowerCase not needed here
- && (upgradeModulePath == null)
- && (appModulePath == null)
- && (patcher.isEmpty())) {
- needPostResolutionChecks = false;
+ Configuration cf;
+ if (needResolution) {
+ cf = JLMA.resolveAndBind(finder, roots, traceOutput);
+ } else {
+ Map<String, Set<String>> map = systemModules.moduleReads();
+ cf = JLMA.newConfiguration(systemModuleFinder, map);
}
- PrintStream traceOutput = null;
- propValue = getAndRemoveProperty("jdk.module.showModuleResolution");
- if (propValue != null && Boolean.parseBoolean(propValue))
- traceOutput = System.out;
+ // check that modules specified to --patch-module are resolved
+ if (isPatched) {
+ patcher.patchedModules()
+ .stream()
+ .filter(mn -> !cf.findModule(mn).isPresent())
+ .forEach(mn -> warnUnknownModule(PATCH_MODULE, mn));
+ }
- // run the resolver to create the configuration
- Configuration cf = SharedSecrets.getJavaLangModuleAccess()
- .resolveAndBind(finder,
- roots,
- needPostResolutionChecks,
- traceOutput);
-
- PerfCounters.resolveTime.addElapsedTimeFrom(t4);
+ Counters.add("jdk.module.boot.4.resolveTime", t4);
// Step 5: Map the modules in the configuration to class loaders.
@@ -326,7 +359,7 @@
// check that all modules to be mapped to the boot loader will be
// loaded from the runtime image
- if (needPostResolutionChecks) {
+ if (haveModulePath) {
for (ResolvedModule resolvedModule : cf.modules()) {
ModuleReference mref = resolvedModule.reference();
String name = mref.descriptor().name();
@@ -335,51 +368,54 @@
if (upgradeModulePath != null
&& upgradeModulePath.find(name).isPresent())
fail(name + ": cannot be loaded from upgrade module path");
- if (!systemModules.find(name).isPresent())
+ if (!systemModuleFinder.find(name).isPresent())
fail(name + ": cannot be loaded from application module path");
}
}
-
- // check if module specified in --patch-module is present
- for (String mn: patcher.patchedModules()) {
- if (!cf.findModule(mn).isPresent()) {
- warnUnknownModule(PATCH_MODULE, mn);
- }
- }
}
// check for split packages in the modules mapped to the built-in loaders
- if (SystemModules.hasSplitPackages() || needPostResolutionChecks) {
+ if (systemModules.hasSplitPackages() || isPatched || haveModulePath) {
checkSplitPackages(cf, clf);
}
// load/register the modules with the built-in class loaders
loadModules(cf, clf);
- PerfCounters.loadModulesTime.addElapsedTimeFrom(t5);
+ Counters.add("jdk.module.boot.5.loadModulesTime", t5);
// Step 6: Define all modules to the VM
long t6 = System.nanoTime();
ModuleLayer bootLayer = ModuleLayer.empty().defineModules(cf, clf);
- PerfCounters.layerCreateTime.addElapsedTimeFrom(t6);
+ Counters.add("jdk.module.boot.6.layerCreateTime", t6);
// Step 7: Miscellaneous
// check incubating status
- checkIncubatingStatus(cf);
+ if (systemModules.hasIncubatorModules() || haveModulePath) {
+ checkIncubatingStatus(cf);
+ }
- // --add-reads, --add-exports/--add-opens, and -illegal-access
+ // --add-reads, --add-exports/--add-opens, and --illegal-access
long t7 = System.nanoTime();
addExtraReads(bootLayer);
boolean extraExportsOrOpens = addExtraExportsAndOpens(bootLayer);
- addIllegalAccess(bootLayer, upgradeModulePath, extraExportsOrOpens);
- PerfCounters.adjustModulesTime.addElapsedTimeFrom(t7);
+ addIllegalAccess(upgradeModulePath, systemModules, bootLayer, extraExportsOrOpens);
+ Counters.add("jdk.module.boot.7.adjustModulesTime", t7);
+
+ // save module finders for later use
+ if (savedModuleFinder != null) {
+ unlimitedFinder = new SafeModuleFinder(savedModuleFinder);
+ if (savedModuleFinder != finder)
+ limitedFinder = new SafeModuleFinder(finder);
+ }
// total time to initialize
- PerfCounters.bootstrapTime.addElapsedTimeFrom(t1);
+ Counters.add("jdk.module.boot.totalTime", t0);
+ Counters.publish();
return bootLayer;
}
@@ -391,7 +427,6 @@
Configuration cf = SharedSecrets.getJavaLangModuleAccess()
.resolveAndBind(ModuleFinder.ofSystem(),
Set.of(JAVA_BASE),
- false,
null);
Function<String, ClassLoader> clf = ModuleLoaderMap.mappingFunction(cf);
@@ -439,7 +474,6 @@
}
}
}
-
}
}
@@ -489,7 +523,7 @@
* Creates a finder from the module path that is the value of the given
* system property and optionally patched by --patch-module
*/
- private static ModuleFinder createModulePathFinder(String prop) {
+ private static ModuleFinder finderFor(String prop) {
String s = System.getProperty(prop);
if (s == null) {
return null;
@@ -510,35 +544,48 @@
*/
private static ModulePatcher initModulePatcher() {
Map<String, List<String>> map = decode("jdk.module.patch.",
- File.pathSeparator,
- false);
+ File.pathSeparator,
+ false);
return new ModulePatcher(map);
}
/**
- * Returns the set of module names specified via --add-modules options
- * on the command line
+ * Returns the set of module names specified by --add-module options.
*/
- private static Set<String> getExtraAddModules() {
+ private static Set<String> addModules() {
String prefix = "jdk.module.addmods.";
int index = 0;
-
// the system property is removed after decoding
String value = getAndRemoveProperty(prefix + index);
if (value == null) {
return Collections.emptySet();
+ } else {
+ Set<String> modules = new HashSet<>();
+ while (value != null) {
+ for (String s : value.split(",")) {
+ if (s.length() > 0) modules.add(s);
+ }
+ index++;
+ value = getAndRemoveProperty(prefix + index);
+ }
+ return modules;
}
+ }
- Set<String> modules = new HashSet<>();
- while (value != null) {
- for (String s : value.split(",")) {
- if (s.length() > 0) modules.add(s);
+ /**
+ * Returns the set of module names specified by --limit-modules.
+ */
+ private static Set<String> limitModules() {
+ String value = getAndRemoveProperty("jdk.module.limitmods");
+ if (value == null) {
+ return Collections.emptySet();
+ } else {
+ Set<String> names = new HashSet<>();
+ for (String name : value.split(",")) {
+ if (name.length() > 0) names.add(name);
}
- index++;
- value = getAndRemoveProperty(prefix + index);
+ return names;
}
-
- return modules;
}
/**
@@ -676,8 +723,9 @@
* Process the --illegal-access option (and its default) to open packages
* of system modules in the boot layer to code in unnamed modules.
*/
- private static void addIllegalAccess(ModuleLayer bootLayer,
- ModuleFinder upgradeModulePath,
+ private static void addIllegalAccess(ModuleFinder upgradeModulePath,
+ SystemModules systemModules,
+ ModuleLayer bootLayer,
boolean extraExportsOrOpens) {
String value = getAndRemoveProperty("jdk.module.illegalAccess");
IllegalAccessLogger.Mode mode = IllegalAccessLogger.Mode.ONESHOT;
@@ -702,10 +750,10 @@
IllegalAccessLogger.Builder builder
= new IllegalAccessLogger.Builder(mode, System.err);
- Map<String, Set<String>> map1 = SystemModules.concealedPackagesToOpen();
- Map<String, Set<String>> map2 = SystemModules.exportedPackagesToOpen();
+ Map<String, Set<String>> map1 = systemModules.concealedPackagesToOpen();
+ Map<String, Set<String>> map2 = systemModules.exportedPackagesToOpen();
if (map1.isEmpty() && map2.isEmpty()) {
- // need to generate maps when on exploded build
+ // need to generate (exploded build)
IllegalAccessMaps maps = IllegalAccessMaps.generate(limitedFinder());
map1 = maps.concealedPackagesToOpen();
map2 = maps.exportedPackagesToOpen();
@@ -906,6 +954,10 @@
}
}
+ /**
+ * Returns an iterator that yields all elements of the first iterator
+ * followed by all the elements of the second iterator.
+ */
static <T> Iterator<T> concat(Iterator<T> iterator1, Iterator<T> iterator2) {
return new Iterator<T>() {
@Override
@@ -921,23 +973,76 @@
};
}
- static class PerfCounters {
+ /**
+ * Wraps a (potentially not thread safe) ModuleFinder created during startup
+ * for use after startup.
+ */
+ static class SafeModuleFinder implements ModuleFinder {
+ private final Set<ModuleReference> mrefs;
+ private volatile Map<String, ModuleReference> nameToModule;
+
+ SafeModuleFinder(ModuleFinder finder) {
+ this.mrefs = Collections.unmodifiableSet(finder.findAll());
+ }
+ @Override
+ public Optional<ModuleReference> find(String name) {
+ Objects.requireNonNull(name);
+ Map<String, ModuleReference> nameToModule = this.nameToModule;
+ if (nameToModule == null) {
+ this.nameToModule = nameToModule = mrefs.stream()
+ .collect(Collectors.toMap(m -> m.descriptor().name(),
+ Function.identity()));
+ }
+ return Optional.ofNullable(nameToModule.get(name));
+ }
+ @Override
+ public Set<ModuleReference> findAll() {
+ return mrefs;
+ }
+ }
- static PerfCounter systemModulesTime
- = PerfCounter.newPerfCounter("jdk.module.bootstrap.systemModulesTime");
- static PerfCounter defineBaseTime
- = PerfCounter.newPerfCounter("jdk.module.bootstrap.defineBaseTime");
- static PerfCounter optionsAndRootsTime
- = PerfCounter.newPerfCounter("jdk.module.bootstrap.optionsAndRootsTime");
- static PerfCounter resolveTime
- = PerfCounter.newPerfCounter("jdk.module.bootstrap.resolveTime");
- static PerfCounter layerCreateTime
- = PerfCounter.newPerfCounter("jdk.module.bootstrap.layerCreateTime");
- static PerfCounter loadModulesTime
- = PerfCounter.newPerfCounter("jdk.module.bootstrap.loadModulesTime");
- static PerfCounter adjustModulesTime
- = PerfCounter.newPerfCounter("jdk.module.bootstrap.adjustModulesTime");
- static PerfCounter bootstrapTime
- = PerfCounter.newPerfCounter("jdk.module.bootstrap.totalTime");
+ /**
+ * Counters for startup performance analysis.
+ */
+ static class Counters {
+ private static final boolean PUBLISH_COUNTERS;
+ private static final boolean PRINT_COUNTERS;
+ private static Map<String, Long> counters;
+ static {
+ String s = System.getProperty("jdk.module.boot.usePerfData");
+ if (s == null) {
+ PUBLISH_COUNTERS = false;
+ PRINT_COUNTERS = false;
+ } else {
+ PUBLISH_COUNTERS = true;
+ PRINT_COUNTERS = s.equals("debug");
+ counters = new LinkedHashMap<>(); // preserve insert order
+ }
+ }
+
+ /**
+ * Add a counter
+ */
+ static void add(String name, long start) {
+ if (PUBLISH_COUNTERS || PRINT_COUNTERS) {
+ counters.put(name, (System.nanoTime() - start));
+ }
+ }
+
+ /**
+ * Publish the counters to the instrumentation buffer or stdout.
+ */
+ static void publish() {
+ if (PUBLISH_COUNTERS || PRINT_COUNTERS) {
+ for (Map.Entry<String, Long> e : counters.entrySet()) {
+ String name = e.getKey();
+ long value = e.getValue();
+ if (PUBLISH_COUNTERS)
+ PerfCounter.newPerfCounter(name).set(value);
+ if (PRINT_COUNTERS)
+ System.out.println(name + " = " + value);
+ }
+ }
+ }
}
}
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java Thu Aug 24 16:34:26 2017 +0200
@@ -200,10 +200,10 @@
}
/**
- * Returns true is this module patcher has no patches.
+ * Returns true is this module patcher has patches.
*/
- public boolean isEmpty() {
- return map.isEmpty();
+ public boolean hasPatches() {
+ return !map.isEmpty();
}
/*
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferenceImpl.java Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferenceImpl.java Thu Aug 24 16:34:26 2017 +0200
@@ -68,14 +68,14 @@
/**
* Constructs a new instance of this class.
*/
- ModuleReferenceImpl(ModuleDescriptor descriptor,
- URI location,
- Supplier<ModuleReader> readerSupplier,
- ModulePatcher patcher,
- ModuleTarget target,
- ModuleHashes recordedHashes,
- ModuleHashes.HashSupplier hasher,
- ModuleResolution moduleResolution)
+ public ModuleReferenceImpl(ModuleDescriptor descriptor,
+ URI location,
+ Supplier<ModuleReader> readerSupplier,
+ ModulePatcher patcher,
+ ModuleTarget target,
+ ModuleHashes recordedHashes,
+ ModuleHashes.HashSupplier hasher,
+ ModuleResolution moduleResolution)
{
super(descriptor, Objects.requireNonNull(location));
this.location = location;
--- a/jdk/src/java.base/share/classes/jdk/internal/module/SystemModuleFinder.java Fri Aug 04 23:29:08 2017 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,469 +0,0 @@
-/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.internal.module;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UncheckedIOException;
-import java.lang.module.ModuleDescriptor;
-import java.lang.module.ModuleFinder;
-import java.lang.module.ModuleReader;
-import java.lang.module.ModuleReference;
-import java.net.URI;
-import java.net.URLConnection;
-import java.nio.ByteBuffer;
-import java.util.ArrayDeque;
-import java.util.Collections;
-import java.util.Deque;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import java.util.Spliterator;
-import java.util.function.Consumer;
-import java.util.function.Supplier;
-import java.util.stream.Stream;
-import java.util.stream.StreamSupport;
-
-import jdk.internal.jimage.ImageLocation;
-import jdk.internal.jimage.ImageReader;
-import jdk.internal.jimage.ImageReaderFactory;
-import jdk.internal.misc.JavaNetUriAccess;
-import jdk.internal.misc.SharedSecrets;
-import jdk.internal.module.ModuleHashes.HashSupplier;
-import jdk.internal.perf.PerfCounter;
-
-/**
- * A {@code ModuleFinder} that finds modules that are linked into the
- * run-time image.
- *
- * The modules linked into the run-time image are assumed to have the
- * Packages attribute.
- */
-
-public class SystemModuleFinder implements ModuleFinder {
-
- private static final JavaNetUriAccess JNUA = SharedSecrets.getJavaNetUriAccess();
-
- private static final PerfCounter initTime
- = PerfCounter.newPerfCounter("jdk.module.finder.jimage.initTime");
- private static final PerfCounter moduleCount
- = PerfCounter.newPerfCounter("jdk.module.finder.jimage.modules");
- private static final PerfCounter packageCount
- = PerfCounter.newPerfCounter("jdk.module.finder.jimage.packages");
- private static final PerfCounter exportsCount
- = PerfCounter.newPerfCounter("jdk.module.finder.jimage.exports");
-
- // singleton finder to find modules in the run-time images
- private static final SystemModuleFinder INSTANCE;
-
- public static SystemModuleFinder getInstance() {
- return INSTANCE;
- }
-
- /**
- * For now, the module references are created eagerly on the assumption
- * that service binding will require all modules to be located.
- */
- static {
- long t0 = System.nanoTime();
-
- INSTANCE = new SystemModuleFinder();
-
- initTime.addElapsedTimeFrom(t0);
- }
-
- /**
- * Holder class for the ImageReader
- */
- private static class SystemImage {
- static final ImageReader READER;
- static {
- long t0 = System.nanoTime();
- READER = ImageReaderFactory.getImageReader();
- initTime.addElapsedTimeFrom(t0);
- }
-
- static ImageReader reader() {
- return READER;
- }
- }
-
- private static boolean isFastPathSupported() {
- return SystemModules.MODULE_NAMES.length > 0;
- }
-
- private static String[] moduleNames() {
- if (isFastPathSupported())
- // module names recorded at link time
- return SystemModules.MODULE_NAMES;
-
- // this happens when java.base is patched with java.base
- // from an exploded image
- return SystemImage.reader().getModuleNames();
- }
-
- // the set of modules in the run-time image
- private final Set<ModuleReference> modules;
-
- // maps module name to module reference
- private final Map<String, ModuleReference> nameToModule;
-
- // module name to hashes
- private final Map<String, byte[]> hashes;
-
- private SystemModuleFinder() {
- String[] names = moduleNames();
- int n = names.length;
- moduleCount.add(n);
-
- // fastpath is enabled by default.
- // It can be disabled for troubleshooting purpose.
- boolean disabled =
- System.getProperty("jdk.system.module.finder.disabledFastPath") != null;
-
- ModuleDescriptor[] descriptors;
- ModuleTarget[] targets;
- ModuleHashes[] recordedHashes;
- ModuleResolution[] moduleResolutions;
-
- // fast loading of ModuleDescriptor of system modules
- if (isFastPathSupported() && !disabled) {
- descriptors = SystemModules.descriptors();
- targets = SystemModules.targets();
- recordedHashes = SystemModules.hashes();
- moduleResolutions = SystemModules.moduleResolutions();
- } else {
- // if fast loading of ModuleDescriptors is disabled
- // fallback to read module-info.class
- descriptors = new ModuleDescriptor[n];
- targets = new ModuleTarget[n];
- recordedHashes = new ModuleHashes[n];
- moduleResolutions = new ModuleResolution[n];
- ImageReader imageReader = SystemImage.reader();
- for (int i = 0; i < names.length; i++) {
- String mn = names[i];
- ImageLocation loc = imageReader.findLocation(mn, "module-info.class");
- ModuleInfo.Attributes attrs =
- ModuleInfo.read(imageReader.getResourceBuffer(loc), null);
- descriptors[i] = attrs.descriptor();
- targets[i] = attrs.target();
- recordedHashes[i] = attrs.recordedHashes();
- moduleResolutions[i] = attrs.moduleResolution();
- }
- }
-
- Map<String, byte[]> hashes = null;
- boolean secondSeen = false;
- // record the hashes to build HashSupplier
- for (ModuleHashes mh : recordedHashes) {
- if (mh != null) {
- // if only one module contain ModuleHashes, use it
- if (hashes == null) {
- hashes = mh.hashes();
- } else {
- if (!secondSeen) {
- hashes = new HashMap<>(hashes);
- secondSeen = true;
- }
- hashes.putAll(mh.hashes());
- }
- }
- }
- this.hashes = (hashes == null) ? Map.of() : hashes;
-
- ModuleReference[] mods = new ModuleReference[n];
-
- @SuppressWarnings(value = {"rawtypes", "unchecked"})
- Entry<String, ModuleReference>[] map
- = (Entry<String, ModuleReference>[])new Entry[n];
-
- for (int i = 0; i < n; i++) {
- ModuleDescriptor md = descriptors[i];
-
- // create the ModuleReference
- ModuleReference mref = toModuleReference(md,
- targets[i],
- recordedHashes[i],
- hashSupplier(names[i]),
- moduleResolutions[i]);
- mods[i] = mref;
- map[i] = Map.entry(names[i], mref);
-
- // counters
- packageCount.add(md.packages().size());
- exportsCount.add(md.exports().size());
- }
-
- modules = Set.of(mods);
- nameToModule = Map.ofEntries(map);
- }
-
- @Override
- public Optional<ModuleReference> find(String name) {
- Objects.requireNonNull(name);
- return Optional.ofNullable(nameToModule.get(name));
- }
-
- @Override
- public Set<ModuleReference> findAll() {
- return modules;
- }
-
- private ModuleReference toModuleReference(ModuleDescriptor md,
- ModuleTarget target,
- ModuleHashes recordedHashes,
- HashSupplier hasher,
- ModuleResolution mres) {
- String mn = md.name();
- URI uri = JNUA.create("jrt", "/".concat(mn));
-
- Supplier<ModuleReader> readerSupplier = new Supplier<>() {
- @Override
- public ModuleReader get() {
- return new ImageModuleReader(mn, uri);
- }
- };
-
- ModuleReference mref = new ModuleReferenceImpl(md,
- uri,
- readerSupplier,
- null,
- target,
- recordedHashes,
- hasher,
- mres);
-
- // may need a reference to a patched module if --patch-module specified
- mref = ModuleBootstrap.patcher().patchIfNeeded(mref);
-
- return mref;
- }
-
- private HashSupplier hashSupplier(String name) {
- if (!hashes.containsKey(name))
- return null;
-
- return new HashSupplier() {
- @Override
- public byte[] generate(String algorithm) {
- return hashes.get(name);
- }
- };
- }
-
- /**
- * A ModuleReader for reading resources from a module linked into the
- * run-time image.
- */
- static class ImageModuleReader implements ModuleReader {
- private final String module;
- private volatile boolean closed;
-
- /**
- * If there is a security manager set then check permission to
- * connect to the run-time image.
- */
- private static void checkPermissionToConnect(URI uri) {
- SecurityManager sm = System.getSecurityManager();
- if (sm != null) {
- try {
- URLConnection uc = uri.toURL().openConnection();
- sm.checkPermission(uc.getPermission());
- } catch (IOException ioe) {
- throw new UncheckedIOException(ioe);
- }
- }
- }
-
- ImageModuleReader(String module, URI uri) {
- checkPermissionToConnect(uri);
- this.module = module;
- }
-
- /**
- * Returns the ImageLocation for the given resource, {@code null}
- * if not found.
- */
- private ImageLocation findImageLocation(String name) throws IOException {
- Objects.requireNonNull(name);
- if (closed)
- throw new IOException("ModuleReader is closed");
- ImageReader imageReader = SystemImage.reader();
- if (imageReader != null) {
- return imageReader.findLocation(module, name);
- } else {
- // not an images build
- return null;
- }
- }
-
- @Override
- public Optional<URI> find(String name) throws IOException {
- ImageLocation location = findImageLocation(name);
- if (location != null) {
- URI u = URI.create("jrt:/" + module + "/" + name);
- return Optional.of(u);
- } else {
- return Optional.empty();
- }
- }
-
- @Override
- public Optional<InputStream> open(String name) throws IOException {
- return read(name).map(this::toInputStream);
- }
-
- private InputStream toInputStream(ByteBuffer bb) { // ## -> ByteBuffer?
- try {
- int rem = bb.remaining();
- byte[] bytes = new byte[rem];
- bb.get(bytes);
- return new ByteArrayInputStream(bytes);
- } finally {
- release(bb);
- }
- }
-
- @Override
- public Optional<ByteBuffer> read(String name) throws IOException {
- ImageLocation location = findImageLocation(name);
- if (location != null) {
- return Optional.of(SystemImage.reader().getResourceBuffer(location));
- } else {
- return Optional.empty();
- }
- }
-
- @Override
- public void release(ByteBuffer bb) {
- Objects.requireNonNull(bb);
- ImageReader.releaseByteBuffer(bb);
- }
-
- @Override
- public Stream<String> list() throws IOException {
- if (closed)
- throw new IOException("ModuleReader is closed");
-
- Spliterator<String> s = new ModuleContentSpliterator(module);
- return StreamSupport.stream(s, false);
- }
-
- @Override
- public void close() {
- // nothing else to do
- closed = true;
- }
- }
-
- /**
- * A Spliterator for traversing the resources of a module linked into the
- * run-time image.
- */
- static class ModuleContentSpliterator implements Spliterator<String> {
- final String moduleRoot;
- final Deque<ImageReader.Node> stack;
- Iterator<ImageReader.Node> iterator;
-
- ModuleContentSpliterator(String module) throws IOException {
- moduleRoot = "/modules/" + module;
- stack = new ArrayDeque<>();
-
- // push the root node to the stack to get started
- ImageReader.Node dir = SystemImage.reader().findNode(moduleRoot);
- if (dir == null || !dir.isDirectory())
- throw new IOException(moduleRoot + " not a directory");
- stack.push(dir);
- iterator = Collections.emptyIterator();
- }
-
- /**
- * Returns the name of the next non-directory node or {@code null} if
- * there are no remaining nodes to visit.
- */
- private String next() throws IOException {
- for (;;) {
- while (iterator.hasNext()) {
- ImageReader.Node node = iterator.next();
- String name = node.getName();
- if (node.isDirectory()) {
- // build node
- ImageReader.Node dir = SystemImage.reader().findNode(name);
- assert dir.isDirectory();
- stack.push(dir);
- } else {
- // strip /modules/$MODULE/ prefix
- return name.substring(moduleRoot.length() + 1);
- }
- }
-
- if (stack.isEmpty()) {
- return null;
- } else {
- ImageReader.Node dir = stack.poll();
- assert dir.isDirectory();
- iterator = dir.getChildren().iterator();
- }
- }
- }
-
- @Override
- public boolean tryAdvance(Consumer<? super String> action) {
- String next;
- try {
- next = next();
- } catch (IOException ioe) {
- throw new UncheckedIOException(ioe);
- }
- if (next != null) {
- action.accept(next);
- return true;
- } else {
- return false;
- }
- }
-
- @Override
- public Spliterator<String> trySplit() {
- return null;
- }
-
- @Override
- public int characteristics() {
- return Spliterator.DISTINCT + Spliterator.NONNULL + Spliterator.IMMUTABLE;
- }
-
- @Override
- public long estimateSize() {
- return Long.MAX_VALUE;
- }
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/SystemModuleFinders.java Thu Aug 24 16:34:26 2017 +0200
@@ -0,0 +1,576 @@
+/*
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.module;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReader;
+import java.lang.module.ModuleReference;
+import java.lang.reflect.Constructor;
+import java.net.URI;
+import java.net.URLConnection;
+import java.nio.ByteBuffer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayDeque;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+import jdk.internal.jimage.ImageLocation;
+import jdk.internal.jimage.ImageReader;
+import jdk.internal.jimage.ImageReaderFactory;
+import jdk.internal.misc.JavaNetUriAccess;
+import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.ModuleHashes.HashSupplier;
+
+/**
+ * The factory for SystemModules objects and for creating ModuleFinder objects
+ * that find modules in the runtime image.
+ *
+ * This class supports initializing the module system when the runtime is an
+ * images build, an exploded build, or an images build with java.base patched
+ * by an exploded java.base. It also supports a testing mode that re-parses
+ * the module-info.class resources in the run-time image.
+ */
+
+public final class SystemModuleFinders {
+ private static final JavaNetUriAccess JNUA = SharedSecrets.getJavaNetUriAccess();
+
+ private static final boolean USE_FAST_PATH;
+ static {
+ String value = System.getProperty("jdk.system.module.finder.disableFastPath");
+ if (value == null) {
+ USE_FAST_PATH = true;
+ } else {
+ USE_FAST_PATH = (value.length() > 0) && !Boolean.parseBoolean(value);
+ }
+ }
+
+ // cached ModuleFinder returned from ofSystem
+ private static volatile ModuleFinder cachedSystemModuleFinder;
+
+ private SystemModuleFinders() { }
+
+ /**
+ * Returns the SystemModules object to reconstitute all modules. Returns
+ * null if this is an exploded build or java.base is patched by an exploded
+ * build.
+ */
+ static SystemModules allSystemModules() {
+ if (USE_FAST_PATH) {
+ return SystemModulesMap.allSystemModules();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Returns a SystemModules object to reconstitute the modules for the
+ * given initial module. If the initial module is null then return the
+ * SystemModules object to reconstitute the default modules.
+ *
+ * Return null if there is no SystemModules class for the initial module,
+ * this is an exploded build, or java.base is patched by an exploded build.
+ */
+ static SystemModules systemModules(String initialModule) {
+ if (USE_FAST_PATH) {
+ if (initialModule == null) {
+ return SystemModulesMap.defaultSystemModules();
+ }
+
+ String[] initialModules = SystemModulesMap.moduleNames();
+ for (int i = 0; i < initialModules.length; i++) {
+ String moduleName = initialModules[i];
+ if (initialModule.equals(moduleName)) {
+ String cn = SystemModulesMap.classNames()[i];
+ try {
+ // one-arg Class.forName as java.base may not be defined
+ Constructor<?> ctor = Class.forName(cn).getConstructor();
+ return (SystemModules) ctor.newInstance();
+ } catch (Exception e) {
+ throw new InternalError(e);
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns a ModuleFinder that is backed by the given SystemModules object.
+ *
+ * @apiNote The returned ModuleFinder is thread safe.
+ */
+ static ModuleFinder of(SystemModules systemModules) {
+ ModuleDescriptor[] descriptors = systemModules.moduleDescriptors();
+ ModuleTarget[] targets = systemModules.moduleTargets();
+ ModuleHashes[] recordedHashes = systemModules.moduleHashes();
+ ModuleResolution[] moduleResolutions = systemModules.moduleResolutions();
+
+ int moduleCount = descriptors.length;
+ ModuleReference[] mrefs = new ModuleReference[moduleCount];
+ @SuppressWarnings(value = {"rawtypes", "unchecked"})
+ Map.Entry<String, ModuleReference>[] map
+ = (Map.Entry<String, ModuleReference>[])new Map.Entry[moduleCount];
+
+ Map<String, byte[]> nameToHash = generateNameToHash(recordedHashes);
+
+ for (int i = 0; i < moduleCount; i++) {
+ String name = descriptors[i].name();
+ HashSupplier hashSupplier = hashSupplier(nameToHash, name);
+ ModuleReference mref = toModuleReference(descriptors[i],
+ targets[i],
+ recordedHashes[i],
+ hashSupplier,
+ moduleResolutions[i]);
+ mrefs[i] = mref;
+ map[i] = Map.entry(name, mref);
+ }
+
+ return new SystemModuleFinder(mrefs, map);
+ }
+
+ /**
+ * Returns the ModuleFinder to find all system modules. Supports both
+ * images and exploded builds.
+ *
+ * @apiNote Used by ModuleFinder.ofSystem()
+ */
+ public static ModuleFinder ofSystem() {
+ ModuleFinder finder = cachedSystemModuleFinder;
+ if (finder != null) {
+ return finder;
+ }
+
+ // probe to see if this is an images build
+ String home = System.getProperty("java.home");
+ Path modules = Paths.get(home, "lib", "modules");
+ if (Files.isRegularFile(modules)) {
+ if (USE_FAST_PATH) {
+ SystemModules systemModules = allSystemModules();
+ if (systemModules != null) {
+ finder = of(systemModules);
+ }
+ }
+
+ // fall back to parsing the module-info.class files in image
+ if (finder == null) {
+ finder = ofModuleInfos();
+ }
+
+ cachedSystemModuleFinder = finder;
+ return finder;
+
+ }
+
+ // exploded build (do not cache module finder)
+ Path dir = Paths.get(home, "modules");
+ if (!Files.isDirectory(dir))
+ throw new InternalError("Unable to detect the run-time image");
+ ModuleFinder f = ModulePath.of(ModuleBootstrap.patcher(), dir);
+ return new ModuleFinder() {
+ @Override
+ public Optional<ModuleReference> find(String name) {
+ PrivilegedAction<Optional<ModuleReference>> pa = () -> f.find(name);
+ return AccessController.doPrivileged(pa);
+ }
+ @Override
+ public Set<ModuleReference> findAll() {
+ PrivilegedAction<Set<ModuleReference>> pa = f::findAll;
+ return AccessController.doPrivileged(pa);
+ }
+ };
+ }
+
+ /**
+ * Parses the module-info.class of all module in the runtime image and
+ * returns a ModuleFinder to find the modules.
+ *
+ * @apiNote The returned ModuleFinder is thread safe.
+ */
+ private static ModuleFinder ofModuleInfos() {
+ // parse the module-info.class in every module
+ Map<String, ModuleInfo.Attributes> nameToAttributes = new HashMap<>();
+ Map<String, byte[]> nameToHash = new HashMap<>();
+ ImageReader reader = SystemImage.reader();
+ for (String mn : reader.getModuleNames()) {
+ ImageLocation loc = reader.findLocation(mn, "module-info.class");
+ ModuleInfo.Attributes attrs
+ = ModuleInfo.read(reader.getResourceBuffer(loc), null);
+
+ nameToAttributes.put(mn, attrs);
+ ModuleHashes hashes = attrs.recordedHashes();
+ if (hashes != null) {
+ for (String name : hashes.names()) {
+ nameToHash.computeIfAbsent(name, k -> hashes.hashFor(name));
+ }
+ }
+ }
+
+ // create a ModuleReference for each module
+ Set<ModuleReference> mrefs = new HashSet<>();
+ Map<String, ModuleReference> nameToModule = new HashMap<>();
+ for (Map.Entry<String, ModuleInfo.Attributes> e : nameToAttributes.entrySet()) {
+ String mn = e.getKey();
+ ModuleInfo.Attributes attrs = e.getValue();
+ HashSupplier hashSupplier = hashSupplier(nameToHash, mn);
+ ModuleReference mref = toModuleReference(attrs.descriptor(),
+ attrs.target(),
+ attrs.recordedHashes(),
+ hashSupplier,
+ attrs.moduleResolution());
+ mrefs.add(mref);
+ nameToModule.put(mn, mref);
+ }
+
+ return new SystemModuleFinder(mrefs, nameToModule);
+ }
+
+ /**
+ * A ModuleFinder that finds module in an array or set of modules.
+ */
+ private static class SystemModuleFinder implements ModuleFinder {
+ final Set<ModuleReference> mrefs;
+ final Map<String, ModuleReference> nameToModule;
+
+ SystemModuleFinder(ModuleReference[] array,
+ Map.Entry<String, ModuleReference>[] map) {
+ this.mrefs = Set.of(array);
+ this.nameToModule = Map.ofEntries(map);
+ }
+
+ SystemModuleFinder(Set<ModuleReference> mrefs,
+ Map<String, ModuleReference> nameToModule) {
+ this.mrefs = Collections.unmodifiableSet(mrefs);
+ this.nameToModule = Collections.unmodifiableMap(nameToModule);
+ }
+
+ @Override
+ public Optional<ModuleReference> find(String name) {
+ Objects.requireNonNull(name);
+ return Optional.ofNullable(nameToModule.get(name));
+ }
+
+ @Override
+ public Set<ModuleReference> findAll() {
+ return mrefs;
+ }
+ }
+
+ /**
+ * Creates a ModuleReference to the system module.
+ */
+ static ModuleReference toModuleReference(ModuleDescriptor descriptor,
+ ModuleTarget target,
+ ModuleHashes recordedHashes,
+ HashSupplier hasher,
+ ModuleResolution mres) {
+ String mn = descriptor.name();
+ URI uri = JNUA.create("jrt", "/".concat(mn));
+
+ Supplier<ModuleReader> readerSupplier = new Supplier<>() {
+ @Override
+ public ModuleReader get() {
+ return new SystemModuleReader(mn, uri);
+ }
+ };
+
+ ModuleReference mref = new ModuleReferenceImpl(descriptor,
+ uri,
+ readerSupplier,
+ null,
+ target,
+ recordedHashes,
+ hasher,
+ mres);
+
+ // may need a reference to a patched module if --patch-module specified
+ mref = ModuleBootstrap.patcher().patchIfNeeded(mref);
+
+ return mref;
+ }
+
+ /**
+ * Generates a map of module name to hash value.
+ */
+ static Map<String, byte[]> generateNameToHash(ModuleHashes[] recordedHashes) {
+ Map<String, byte[]> nameToHash = null;
+
+ boolean secondSeen = false;
+ // record the hashes to build HashSupplier
+ for (ModuleHashes mh : recordedHashes) {
+ if (mh != null) {
+ // if only one module contain ModuleHashes, use it
+ if (nameToHash == null) {
+ nameToHash = mh.hashes();
+ } else {
+ if (!secondSeen) {
+ nameToHash = new HashMap<>(nameToHash);
+ secondSeen = true;
+ }
+ nameToHash.putAll(mh.hashes());
+ }
+ }
+ }
+ return (nameToHash != null) ? nameToHash : Collections.emptyMap();
+ }
+
+ /**
+ * Returns a HashSupplier that returns the hash of the given module.
+ */
+ static HashSupplier hashSupplier(Map<String, byte[]> nameToHash, String name) {
+ byte[] hash = nameToHash.get(name);
+ if (hash != null) {
+ // avoid lambda here
+ return new HashSupplier() {
+ @Override
+ public byte[] generate(String algorithm) {
+ return hash;
+ }
+ };
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Holder class for the ImageReader
+ *
+ * @apiNote This class must be loaded before a security manager is set.
+ */
+ private static class SystemImage {
+ static final ImageReader READER = ImageReaderFactory.getImageReader();
+ static ImageReader reader() {
+ return READER;
+ }
+ }
+
+ /**
+ * A ModuleReader for reading resources from a module linked into the
+ * run-time image.
+ */
+ private static class SystemModuleReader implements ModuleReader {
+ private final String module;
+ private volatile boolean closed;
+
+ /**
+ * If there is a security manager set then check permission to
+ * connect to the run-time image.
+ */
+ private static void checkPermissionToConnect(URI uri) {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ try {
+ URLConnection uc = uri.toURL().openConnection();
+ sm.checkPermission(uc.getPermission());
+ } catch (IOException ioe) {
+ throw new UncheckedIOException(ioe);
+ }
+ }
+ }
+
+ SystemModuleReader(String module, URI uri) {
+ checkPermissionToConnect(uri);
+ this.module = module;
+ }
+
+ /**
+ * Returns the ImageLocation for the given resource, {@code null}
+ * if not found.
+ */
+ private ImageLocation findImageLocation(String name) throws IOException {
+ Objects.requireNonNull(name);
+ if (closed)
+ throw new IOException("ModuleReader is closed");
+ ImageReader imageReader = SystemImage.reader();
+ if (imageReader != null) {
+ return imageReader.findLocation(module, name);
+ } else {
+ // not an images build
+ return null;
+ }
+ }
+
+ @Override
+ public Optional<URI> find(String name) throws IOException {
+ ImageLocation location = findImageLocation(name);
+ if (location != null) {
+ URI u = URI.create("jrt:/" + module + "/" + name);
+ return Optional.of(u);
+ } else {
+ return Optional.empty();
+ }
+ }
+
+ @Override
+ public Optional<InputStream> open(String name) throws IOException {
+ return read(name).map(this::toInputStream);
+ }
+
+ private InputStream toInputStream(ByteBuffer bb) { // ## -> ByteBuffer?
+ try {
+ int rem = bb.remaining();
+ byte[] bytes = new byte[rem];
+ bb.get(bytes);
+ return new ByteArrayInputStream(bytes);
+ } finally {
+ release(bb);
+ }
+ }
+
+ @Override
+ public Optional<ByteBuffer> read(String name) throws IOException {
+ ImageLocation location = findImageLocation(name);
+ if (location != null) {
+ return Optional.of(SystemImage.reader().getResourceBuffer(location));
+ } else {
+ return Optional.empty();
+ }
+ }
+
+ @Override
+ public void release(ByteBuffer bb) {
+ Objects.requireNonNull(bb);
+ ImageReader.releaseByteBuffer(bb);
+ }
+
+ @Override
+ public Stream<String> list() throws IOException {
+ if (closed)
+ throw new IOException("ModuleReader is closed");
+
+ Spliterator<String> s = new ModuleContentSpliterator(module);
+ return StreamSupport.stream(s, false);
+ }
+
+ @Override
+ public void close() {
+ // nothing else to do
+ closed = true;
+ }
+ }
+
+ /**
+ * A Spliterator for traversing the resources of a module linked into the
+ * run-time image.
+ */
+ private static class ModuleContentSpliterator implements Spliterator<String> {
+ final String moduleRoot;
+ final Deque<ImageReader.Node> stack;
+ Iterator<ImageReader.Node> iterator;
+
+ ModuleContentSpliterator(String module) throws IOException {
+ moduleRoot = "/modules/" + module;
+ stack = new ArrayDeque<>();
+
+ // push the root node to the stack to get started
+ ImageReader.Node dir = SystemImage.reader().findNode(moduleRoot);
+ if (dir == null || !dir.isDirectory())
+ throw new IOException(moduleRoot + " not a directory");
+ stack.push(dir);
+ iterator = Collections.emptyIterator();
+ }
+
+ /**
+ * Returns the name of the next non-directory node or {@code null} if
+ * there are no remaining nodes to visit.
+ */
+ private String next() throws IOException {
+ for (;;) {
+ while (iterator.hasNext()) {
+ ImageReader.Node node = iterator.next();
+ String name = node.getName();
+ if (node.isDirectory()) {
+ // build node
+ ImageReader.Node dir = SystemImage.reader().findNode(name);
+ assert dir.isDirectory();
+ stack.push(dir);
+ } else {
+ // strip /modules/$MODULE/ prefix
+ return name.substring(moduleRoot.length() + 1);
+ }
+ }
+
+ if (stack.isEmpty()) {
+ return null;
+ } else {
+ ImageReader.Node dir = stack.poll();
+ assert dir.isDirectory();
+ iterator = dir.getChildren().iterator();
+ }
+ }
+ }
+
+ @Override
+ public boolean tryAdvance(Consumer<? super String> action) {
+ String next;
+ try {
+ next = next();
+ } catch (IOException ioe) {
+ throw new UncheckedIOException(ioe);
+ }
+ if (next != null) {
+ action.accept(next);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public Spliterator<String> trySplit() {
+ return null;
+ }
+
+ @Override
+ public int characteristics() {
+ return Spliterator.DISTINCT + Spliterator.NONNULL + Spliterator.IMMUTABLE;
+ }
+
+ @Override
+ public long estimateSize() {
+ return Long.MAX_VALUE;
+ }
+ }
+}
--- a/jdk/src/java.base/share/classes/jdk/internal/module/SystemModules.java Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/SystemModules.java Thu Aug 24 16:34:26 2017 +0200
@@ -26,94 +26,73 @@
package jdk.internal.module;
import java.lang.module.ModuleDescriptor;
-import java.util.Collections;
import java.util.Map;
import java.util.Set;
/**
- * SystemModules class will be generated at link time to create
- * ModuleDescriptor for the system modules directly to improve
- * the module descriptor reconstitution time.
+ * A SystemModules object reconstitutes module descriptors and other modules
+ * attributes in an efficient way to avoid parsing module-info.class files at
+ * startup. Implementations of this class are generated by the "system modules"
+ * jlink plugin.
*
- * This will skip parsing of module-info.class file and validating
- * names such as module name, package name, service and provider type names.
- * It also avoids taking a defensive copy of any collection.
- *
+ * @see SystemModuleFinders
* @see jdk.tools.jlink.internal.plugins.SystemModulesPlugin
*/
-public final class SystemModules {
- /**
- * Name of the system modules.
- *
- * This array provides a way for SystemModuleFinder to fallback
- * and read module-info.class from the run-time image instead of
- * the fastpath.
- */
- public static final String[] MODULE_NAMES = new String[0];
+
+interface SystemModules {
/**
- * Number of packages in the boot layer from the installed modules.
- *
- * Don't make it final to avoid inlining during compile time as
- * the value will be changed at jlink time.
+ * Returns false if the module reconstituted by this SystemModules object
+ * have no overlapping packages. Returns true if there are overlapping
+ * packages or unknown.
*/
- public static int PACKAGES_IN_BOOT_LAYER = 1024;
+ boolean hasSplitPackages();
+
+ /**
+ * Return false if the modules reconstituted by this SystemModules object
+ * do not include any incubator modules. Returns true if there are
+ * incubating modules or unknown.
+ */
+ boolean hasIncubatorModules();
/**
- * Return true if there are no split packages in the run-time image.
+ * Returns the non-empty array of ModuleDescriptor objects.
*/
- public static boolean hasSplitPackages() {
- return true;
- }
+ ModuleDescriptor[] moduleDescriptors();
/**
- * Returns a non-empty array of ModuleDescriptor objects in the run-time image.
- *
- * When running an exploded image it returns an empty array.
+ * Returns the array of ModuleTarget objects. The array elements correspond
+ * to the array of ModuleDescriptor objects.
*/
- public static ModuleDescriptor[] descriptors() {
- throw new InternalError("expected to be overridden at link time");
- }
+ ModuleTarget[] moduleTargets();
/**
- * Returns a non-empty array of ModuleTarget objects in the run-time image.
- *
- * When running an exploded image it returns an empty array.
+ * Returns the array of ModuleHashes objects. The array elements correspond
+ * to the array of ModuleDescriptor objects.
*/
- public static ModuleTarget[] targets() {
- throw new InternalError("expected to be overridden at link time");
- }
+ ModuleHashes[] moduleHashes();
/**
- * Returns a non-empty array of ModuleHashes recorded in each module
- * in the run-time image.
- *
- * When running an exploded image it returns an empty array.
+ * Returns the array of ModuleResolution objects. The array elements correspond
+ * to the array of ModuleDescriptor objects.
*/
- public static ModuleHashes[] hashes() {
- throw new InternalError("expected to be overridden at link time");
- }
+ ModuleResolution[] moduleResolutions();
/**
- * Returns a non-empty array of ModuleResolutions in the run-time image.
+ * Returns the map representing readability graph for the modules reconstituted
+ * by this SystemModules object.
*/
- public static ModuleResolution[] moduleResolutions() {
- throw new InternalError("expected to be overridden at link time");
- }
+ Map<String, Set<String>> moduleReads();
/**
* Returns the map of module concealed packages to open. The map key is the
* module name, the value is the set of concealed packages to open.
*/
- public static Map<String, Set<String>> concealedPackagesToOpen() {
- return Collections.emptyMap();
- }
+ Map<String, Set<String>> concealedPackagesToOpen();
/**
* Returns the map of module exported packages to open. The map key is the
* module name, the value is the set of exported packages to open.
*/
- public static Map<String, Set<String>> exportedPackagesToOpen() {
- return Collections.emptyMap();
- }
+ Map<String, Set<String>> exportedPackagesToOpen();
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/SystemModulesMap.java Thu Aug 24 16:34:26 2017 +0200
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.module;
+
+/**
+ * This class is generated/overridden at link time to return the names of the
+ * SystemModules classes generated at link time.
+ *
+ * @see SystemModuleFinders
+ * @see jdk.tools.jlink.internal.plugins.SystemModulesPlugin
+ */
+
+class SystemModulesMap {
+
+ /**
+ * Returns the SystemModules object to reconstitute all modules or null
+ * if this is an exploded build.
+ */
+ static SystemModules allSystemModules() {
+ return null;
+ }
+
+ /**
+ * Returns the SystemModules object to reconstitute default modules or null
+ * if this is an exploded build.
+ */
+ static SystemModules defaultSystemModules() {
+ return null;
+ }
+
+ /**
+ * Returns the array of initial module names identified at link time.
+ */
+ static String[] moduleNames() {
+ return new String[0];
+ }
+
+ /**
+ * Returns the array of of SystemModules class names. The elements
+ * correspond to the elements in the array returned by moduleNames().
+ */
+ static String[] classNames() {
+ return new String[0];
+ }
+}
\ No newline at end of file
--- a/jdk/src/java.base/share/classes/sun/nio/ch/SelectorImpl.java Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/src/java.base/share/classes/sun/nio/ch/SelectorImpl.java Thu Aug 24 16:34:26 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,10 +26,18 @@
package sun.nio.ch;
import java.io.IOException;
-import java.nio.channels.*;
-import java.nio.channels.spi.*;
import java.net.SocketException;
-import java.util.*;
+import java.nio.channels.ClosedSelectorException;
+import java.nio.channels.IllegalSelectorException;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.spi.AbstractSelectableChannel;
+import java.nio.channels.spi.AbstractSelector;
+import java.nio.channels.spi.SelectorProvider;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
/**
@@ -54,23 +62,18 @@
super(sp);
keys = new HashSet<>();
selectedKeys = new HashSet<>();
- if (Util.atBugLevel("1.4")) {
- publicKeys = keys;
- publicSelectedKeys = selectedKeys;
- } else {
- publicKeys = Collections.unmodifiableSet(keys);
- publicSelectedKeys = Util.ungrowableSet(selectedKeys);
- }
+ publicKeys = Collections.unmodifiableSet(keys);
+ publicSelectedKeys = Util.ungrowableSet(selectedKeys);
}
public Set<SelectionKey> keys() {
- if (!isOpen() && !Util.atBugLevel("1.4"))
+ if (!isOpen())
throw new ClosedSelectorException();
return publicKeys;
}
public Set<SelectionKey> selectedKeys() {
- if (!isOpen() && !Util.atBugLevel("1.4"))
+ if (!isOpen())
throw new ClosedSelectorException();
return publicSelectedKeys;
}
--- a/jdk/src/java.base/share/classes/sun/nio/ch/Util.java Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/src/java.base/share/classes/sun/nio/ch/Util.java Thu Aug 24 16:34:26 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,13 +25,16 @@
package sun.nio.ch;
-import java.lang.reflect.*;
import java.io.FileDescriptor;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.security.AccessController;
import java.security.PrivilegedAction;
-import java.util.*;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Set;
import jdk.internal.misc.Unsafe;
import sun.security.action.GetPropertyAction;
@@ -456,21 +459,4 @@
}
return dbb;
}
-
-
- // -- Bug compatibility --
-
- private static volatile String bugLevel;
-
- static boolean atBugLevel(String bl) { // package-private
- if (bugLevel == null) {
- if (!jdk.internal.misc.VM.isBooted())
- return false;
- String value = GetPropertyAction
- .privilegedGetProperty("sun.nio.ch.bugLevel");
- bugLevel = (value != null) ? value : "";
- }
- return bugLevel.equals(bl);
- }
-
}
--- a/jdk/src/java.base/share/classes/sun/security/provider/KeyProtector.java Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/provider/KeyProtector.java Thu Aug 24 16:34:26 2017 +0200
@@ -35,6 +35,7 @@
import java.security.UnrecoverableKeyException;
import java.util.*;
+import jdk.internal.ref.CleanerFactory;
import sun.security.pkcs.PKCS8Key;
import sun.security.pkcs.EncryptedPrivateKeyInfo;
import sun.security.x509.AlgorithmId;
@@ -141,18 +142,10 @@
passwdBytes[j++] = (byte)(password[i] >> 8);
passwdBytes[j++] = (byte)password[i];
}
- }
-
- /**
- * Ensures that the password bytes of this key protector are
- * set to zero when there are no more references to it.
- */
- @SuppressWarnings("deprecation")
- protected void finalize() {
- if (passwdBytes != null) {
- Arrays.fill(passwdBytes, (byte)0x00);
- passwdBytes = null;
- }
+ // Use the cleaner to zero the password when no longer referenced
+ final byte[] k = this.passwdBytes;
+ CleanerFactory.cleaner().register(this,
+ () -> java.util.Arrays.fill(k, (byte)0x00));
}
/*
--- a/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/SocketTransportService.java Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/SocketTransportService.java Thu Aug 24 16:34:26 2017 +0200
@@ -275,6 +275,12 @@
sa = new InetSocketAddress(localaddress, port);
}
ServerSocket ss = new ServerSocket();
+ if (port == 0) {
+ // Only need SO_REUSEADDR if we're using a fixed port. If we
+ // start seeing EADDRINUSE due to collisions in free ports
+ // then we should retry the bind() a few times.
+ ss.setReuseAddress(false);
+ }
ss.bind(sa);
return new SocketListenKey(ss);
}
--- a/jdk/src/jdk.jdwp.agent/share/native/libdt_socket/socketTransport.c Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/src/jdk.jdwp.agent/share/native/libdt_socket/socketTransport.c Thu Aug 24 16:34:26 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 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
@@ -119,8 +119,26 @@
return (char *)dbgsysTlsGet(tlsIndex);
}
+/* Set options common to client and server sides */
static jdwpTransportError
-setOptions(int fd)
+setOptionsCommon(int fd)
+{
+ jvalue dontcare;
+ int err;
+
+ dontcare.i = 0; /* keep compiler happy */
+
+ err = dbgsysSetSocketOption(fd, TCP_NODELAY, JNI_TRUE, dontcare);
+ if (err < 0) {
+ RETURN_IO_ERROR("setsockopt TCPNODELAY failed");
+ }
+
+ return JDWPTRANSPORT_ERROR_NONE;
+}
+
+/* Set the SO_REUSEADDR option */
+static jdwpTransportError
+setReuseAddrOption(int fd)
{
jvalue dontcare;
int err;
@@ -132,11 +150,6 @@
RETURN_IO_ERROR("setsockopt SO_REUSEADDR failed");
}
- err = dbgsysSetSocketOption(fd, TCP_NODELAY, JNI_TRUE, dontcare);
- if (err < 0) {
- RETURN_IO_ERROR("setsockopt TCPNODELAY failed");
- }
-
return JDWPTRANSPORT_ERROR_NONE;
}
@@ -350,10 +363,21 @@
RETURN_IO_ERROR("socket creation failed");
}
- err = setOptions(serverSocketFD);
+ err = setOptionsCommon(serverSocketFD);
if (err) {
return err;
}
+ if (sa.sin_port != 0) {
+ /*
+ * Only need SO_REUSEADDR if we're using a fixed port. If we
+ * start seeing EADDRINUSE due to collisions in free ports
+ * then we should retry the dbgsysBind() a few times.
+ */
+ err = setReuseAddrOption(serverSocketFD);
+ if (err) {
+ return err;
+ }
+ }
err = dbgsysBind(serverSocketFD, (struct sockaddr *)&sa, sizeof(sa));
if (err < 0) {
@@ -510,12 +534,18 @@
RETURN_IO_ERROR("unable to create socket");
}
- err = setOptions(socketFD);
+ err = setOptionsCommon(socketFD);
if (err) {
return err;
}
/*
+ * We don't call setReuseAddrOption() for the non-server socket
+ * case. If we start seeing EADDRINUSE due to collisions in free
+ * ports then we should retry the dbgsysConnect() a few times.
+ */
+
+ /*
* To do a timed connect we make the socket non-blocking
* and poll with a timeout;
*/
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java Thu Aug 24 16:34:26 2017 +0200
@@ -28,6 +28,7 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.lang.module.Configuration;
import java.lang.module.ModuleDescriptor;
import java.lang.module.ModuleDescriptor.Exports;
import java.lang.module.ModuleDescriptor.Opens;
@@ -37,12 +38,15 @@
import java.lang.module.ModuleFinder;
import java.lang.module.ModuleReader;
import java.lang.module.ModuleReference;
+import java.lang.module.ResolvedModule;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -50,18 +54,20 @@
import java.util.Set;
import java.util.TreeSet;
import java.util.function.IntSupplier;
+import java.util.function.Supplier;
import java.util.stream.Collectors;
import jdk.internal.module.Checks;
import jdk.internal.module.ClassFileAttributes;
import jdk.internal.module.ClassFileConstants;
+import jdk.internal.module.DefaultRoots;
import jdk.internal.module.IllegalAccessMaps;
import jdk.internal.module.ModuleHashes;
import jdk.internal.module.ModuleInfo.Attributes;
import jdk.internal.module.ModuleInfoExtender;
+import jdk.internal.module.ModuleReferenceImpl;
import jdk.internal.module.ModuleResolution;
import jdk.internal.module.ModuleTarget;
-import jdk.internal.module.SystemModules;
import jdk.internal.org.objectweb.asm.Attribute;
import jdk.internal.org.objectweb.asm.ClassReader;
import jdk.internal.org.objectweb.asm.ClassVisitor;
@@ -72,33 +78,42 @@
import static jdk.internal.org.objectweb.asm.Opcodes.*;
import jdk.tools.jlink.internal.ModuleSorter;
+import jdk.tools.jlink.plugin.Plugin;
import jdk.tools.jlink.plugin.PluginException;
import jdk.tools.jlink.plugin.ResourcePool;
-import jdk.tools.jlink.plugin.Plugin;
import jdk.tools.jlink.plugin.ResourcePoolBuilder;
import jdk.tools.jlink.plugin.ResourcePoolEntry;
/**
- * Jlink plugin to reconstitute module descriptors for system modules.
- * It will extend module-info.class with ModulePackages attribute,
- * if not present. It also determines the number of packages of
- * the boot layer at link time.
+ * Jlink plugin to reconstitute module descriptors and other attributes for system
+ * modules. The plugin generates implementations of SystemModules to avoid parsing
+ * module-info.class files at startup. It also generates SystemModulesMap to return
+ * the SystemModules implementation for a specific initial module.
*
- * This plugin will override jdk.internal.module.SystemModules class
+ * As a side effect, the plugin adds the ModulePackages class file attribute to the
+ * module-info.class files that don't have the attribute.
*
- * @see jdk.internal.module.SystemModuleFinder
- * @see SystemModules
+ * @see jdk.internal.module.SystemModuleFinders
+ * @see jdk.internal.module.SystemModules
*/
+
public final class SystemModulesPlugin implements Plugin {
private static final String NAME = "system-modules";
private static final String DESCRIPTION =
- PluginsResourceBundle.getDescription(NAME);
+ PluginsResourceBundle.getDescription(NAME);
+ private static final String SYSTEM_MODULES_MAP_CLASS =
+ "jdk/internal/module/SystemModulesMap";
+ private static final String SYSTEM_MODULES_CLASS_PREFIX =
+ "jdk/internal/module/SystemModules$";
+ private static final String ALL_SYSTEM_MODULES_CLASS =
+ SYSTEM_MODULES_CLASS_PREFIX + "all";
+ private static final String DEFAULT_SYSTEM_MODULES_CLASS =
+ SYSTEM_MODULES_CLASS_PREFIX + "default";
private boolean enabled;
- private boolean retainModuleTarget;
+
public SystemModulesPlugin() {
this.enabled = true;
- this.retainModuleTarget = false;
}
@Override
@@ -131,11 +146,7 @@
public void configure(Map<String, String> config) {
String arg = config.get(NAME);
if (arg != null) {
- if (arg.equals("retainModuleTarget")) {
- retainModuleTarget = true;
- } else {
- throw new IllegalArgumentException(NAME + ": " + arg);
- }
+ throw new IllegalArgumentException(NAME + ": " + arg);
}
}
@@ -145,25 +156,56 @@
throw new PluginException(NAME + " was set");
}
- SystemModulesClassGenerator generator =
- new SystemModulesClassGenerator(retainModuleTarget);
+ // validate, transform (if needed), and add the module-info.class files
+ List<ModuleInfo> moduleInfos = transformModuleInfos(in, out);
+
+ // generate and add the SystemModuleMap and SystemModules classes
+ Set<String> generated = genSystemModulesClasses(moduleInfos, out);
+
+ // pass through all other resources
+ in.entries()
+ .filter(data -> !data.path().endsWith("/module-info.class")
+ && !generated.contains(data.path()))
+ .forEach(data -> out.add(data));
- // generate the byte code to create ModuleDescriptors
- // such that the modules linked in the image would skip parsing
- // of module-info.class and also skip name check
+ return out.build();
+ }
+
+ /**
+ * Validates and transforms the module-info.class files in the modules, adding
+ * the ModulePackages class file attribute if needed.
+ *
+ * @return the list of ModuleInfo objects, the first element is java.base
+ */
+ List<ModuleInfo> transformModuleInfos(ResourcePool in, ResourcePoolBuilder out) {
+ List<ModuleInfo> moduleInfos = new ArrayList<>();
// Sort modules in the topological order so that java.base is always first.
new ModuleSorter(in.moduleView()).sorted().forEach(module -> {
ResourcePoolEntry data = module.findEntry("module-info.class").orElseThrow(
- // automatic module not supported yet
+ // automatic modules not supported
() -> new PluginException("module-info.class not found for " +
- module.name() + " module")
+ module.name() + " module")
);
assert module.name().equals(data.moduleName());
+
try {
- // validate the module and add to system modules
- data = generator.buildModuleInfo(data, module.packages());
+ byte[] content = data.contentBytes();
+ Set<String> packages = module.packages();
+ ModuleInfo moduleInfo = new ModuleInfo(content, packages);
+
+ // link-time validation
+ moduleInfo.validateNames();
+
+ // check if any exported or open package is not present
+ moduleInfo.validatePackages();
+
+ // module-info.class may be overridden to add ModulePackages
+ if (moduleInfo.shouldRewrite()) {
+ data = data.copyWithContent(moduleInfo.getBytes());
+ }
+ moduleInfos.add(moduleInfo);
// add resource pool entry
out.add(data);
@@ -172,37 +214,134 @@
}
});
- // Generate the new class
- ClassWriter cwriter = generator.getClassWriter();
- in.entries().forEach(data -> {
- if (data.path().endsWith("module-info.class"))
- return;
- if (generator.isOverriddenClass(data.path())) {
- byte[] bytes = cwriter.toByteArray();
- ResourcePoolEntry ndata = data.copyWithContent(bytes);
- out.add(ndata);
- } else {
- out.add(data);
+ return moduleInfos;
+ }
+
+ /**
+ * Generates the SystemModules classes (at least one) and the SystemModulesMap
+ * class to map initial modules to a SystemModules class.
+ *
+ * @return the resource names of the resources added to the pool
+ */
+ private Set<String> genSystemModulesClasses(List<ModuleInfo> moduleInfos,
+ ResourcePoolBuilder out) {
+ int moduleCount = moduleInfos.size();
+ ModuleFinder finder = finderOf(moduleInfos);
+ assert finder.findAll().size() == moduleCount;
+
+ // map of initial module name to SystemModules class name
+ Map<String, String> map = new LinkedHashMap<>();
+
+ // the names of resources written to the pool
+ Set<String> generated = new HashSet<>();
+
+ // generate the SystemModules implementation to reconstitute all modules
+ Set<String> allModuleNames = moduleInfos.stream()
+ .map(ModuleInfo::moduleName)
+ .collect(Collectors.toSet());
+ String rn = genSystemModulesClass(moduleInfos,
+ resolve(finder, allModuleNames),
+ ALL_SYSTEM_MODULES_CLASS,
+ out);
+ generated.add(rn);
+
+ // generate, if needed, a SystemModules class to reconstitute the modules
+ // needed for the case that the initial module is the unnamed module.
+ String defaultSystemModulesClassName;
+ Configuration cf = resolve(finder, DefaultRoots.compute(finder));
+ if (cf.modules().size() == moduleCount) {
+ // all modules are resolved so no need to generate a class
+ defaultSystemModulesClassName = ALL_SYSTEM_MODULES_CLASS;
+ } else {
+ defaultSystemModulesClassName = DEFAULT_SYSTEM_MODULES_CLASS;
+ rn = genSystemModulesClass(sublist(moduleInfos, cf),
+ cf,
+ defaultSystemModulesClassName,
+ out);
+ generated.add(rn);
+ }
+
+ // Generate a SystemModules class for each module with a main class
+ int suffix = 0;
+ for (ModuleInfo mi : moduleInfos) {
+ if (mi.descriptor().mainClass().isPresent()) {
+ String moduleName = mi.moduleName();
+ cf = resolve(finder, Set.of(moduleName));
+ if (cf.modules().size() == moduleCount) {
+ // resolves all modules so no need to generate a class
+ map.put(moduleName, ALL_SYSTEM_MODULES_CLASS);
+ } else {
+ String cn = SYSTEM_MODULES_CLASS_PREFIX + (suffix++);
+ rn = genSystemModulesClass(sublist(moduleInfos, cf), cf, cn, out);
+ map.put(moduleName, cn);
+ generated.add(rn);
+ }
}
- });
+ }
+
+ // generate SystemModulesMap
+ rn = genSystemModulesMapClass(ALL_SYSTEM_MODULES_CLASS,
+ defaultSystemModulesClassName,
+ map,
+ out);
+ generated.add(rn);
+
+ // return the resource names of the generated classes
+ return generated;
+ }
+
+ /**
+ * Resolves a collection of root modules, with service binding, to create
+ * configuration.
+ */
+ private Configuration resolve(ModuleFinder finder, Set<String> roots) {
+ return Configuration.empty().resolveAndBind(finder, ModuleFinder.of(), roots);
+ }
- return out.build();
+ /**
+ * Returns the list of ModuleInfo objects that correspond to the modules in
+ * the given configuration.
+ */
+ private List<ModuleInfo> sublist(List<ModuleInfo> moduleInfos, Configuration cf) {
+ Set<String> names = cf.modules()
+ .stream()
+ .map(ResolvedModule::name)
+ .collect(Collectors.toSet());
+ return moduleInfos.stream()
+ .filter(mi -> names.contains(mi.moduleName()))
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Generate a SystemModules implementation class and add it as a resource.
+ *
+ * @return the name of the class resource added to the pool
+ */
+ private String genSystemModulesClass(List<ModuleInfo> moduleInfos,
+ Configuration cf,
+ String className,
+ ResourcePoolBuilder out) {
+ SystemModulesClassGenerator generator
+ = new SystemModulesClassGenerator(className, moduleInfos);
+ byte[] bytes = generator.getClassWriter(cf).toByteArray();
+ String rn = "/java.base/" + className + ".class";
+ ResourcePoolEntry e = ResourcePoolEntry.create(rn, bytes);
+ out.add(e);
+ return rn;
}
static class ModuleInfo {
- private final ByteArrayInputStream bain;
+ private final ByteArrayInputStream bais;
private final Attributes attrs;
private final Set<String> packages;
- private final boolean dropModuleTarget;
private final boolean addModulePackages;
private ModuleDescriptor descriptor; // may be different that the original one
- ModuleInfo(byte[] bytes, Set<String> packages, boolean dropModuleTarget)
- throws IOException
- {
- this.bain = new ByteArrayInputStream(bytes);
+ ModuleInfo(byte[] bytes, Set<String> packages) throws IOException {
+ this.bais = new ByteArrayInputStream(bytes);
this.packages = packages;
- this.attrs = jdk.internal.module.ModuleInfo.read(bain, null);
+ this.attrs = jdk.internal.module.ModuleInfo.read(bais, null);
+
// If ModulePackages attribute is present, the packages from this
// module descriptor returns the packages in that attribute.
// If it's not present, ModuleDescriptor::packages only contains
@@ -215,14 +354,6 @@
// add ModulePackages attribute if this module contains some packages
// and ModulePackages is not present
this.addModulePackages = packages.size() > 0 && !hasModulePackages();
-
- // drop target attribute only if any OS property is present
- ModuleTarget target = attrs.target();
- if (dropModuleTarget && target != null) {
- this.dropModuleTarget = (target.targetPlatform() != null);
- } else {
- this.dropModuleTarget = false;
- }
}
String moduleName() {
@@ -233,7 +364,6 @@
return descriptor;
}
-
Set<String> packages() {
return packages;
}
@@ -283,7 +413,6 @@
}
}
-
/**
* Validates if exported and open packages are present
*/
@@ -328,17 +457,15 @@
}
/**
- * Returns true if module-info.class should be written
- * 1. add ModulePackages attribute if not present; or
- * 2. drop ModuleTarget attribute except java.base
+ * Returns true if module-info.class should be rewritten to add the
+ * ModulePackages attribute.
*/
boolean shouldRewrite() {
- return addModulePackages || dropModuleTarget;
+ return addModulePackages;
}
/**
- * Returns the bytes for the module-info.class with ModulePackages
- * attribute added and/or with ModuleTarget attribute dropped.
+ * Returns the bytes for the (possibly updated) module-info.class.
*/
byte[] getBytes() throws IOException {
try (InputStream in = getInputStream()) {
@@ -347,13 +474,10 @@
if (addModulePackages) {
rewriter.addModulePackages(packages);
}
- if (dropModuleTarget) {
- rewriter.dropModuleTarget();
- }
// rewritten module descriptor
byte[] bytes = rewriter.getBytes();
- try (ByteArrayInputStream bain = new ByteArrayInputStream(bytes)) {
- this.descriptor = ModuleDescriptor.read(bain);
+ try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes)) {
+ this.descriptor = ModuleDescriptor.read(bais);
}
return bytes;
} else {
@@ -366,8 +490,8 @@
* Returns the input stream of the module-info.class
*/
InputStream getInputStream() {
- bain.reset();
- return bain;
+ bais.reset();
+ return bais;
}
class ModuleInfoRewriter extends ByteArrayOutputStream {
@@ -383,10 +507,6 @@
}
}
- void dropModuleTarget() {
- extender.targetPlatform("");
- }
-
byte[] getBytes() throws IOException {
extender.write(this);
return buf;
@@ -395,12 +515,10 @@
}
/**
- * ClassWriter of a new jdk.internal.module.SystemModules class
- * to reconstitute ModuleDescriptor of the system modules.
+ * Generates a SystemModules class to reconstitute the ModuleDescriptor
+ * and other attributes of system modules.
*/
static class SystemModulesClassGenerator {
- private static final String CLASSNAME =
- "jdk/internal/module/SystemModules";
private static final String MODULE_DESCRIPTOR_BUILDER =
"jdk/internal/module/Builder";
private static final String MODULE_DESCRIPTOR_ARRAY_SIGNATURE =
@@ -422,10 +540,6 @@
private static final String MODULE_RESOLUTIONS_ARRAY_SIGNATURE =
"[Ljdk/internal/module/ModuleResolution;";
- // static variables in SystemModules class
- private static final String MODULE_NAMES = "MODULE_NAMES";
- private static final String PACKAGE_COUNT = "PACKAGES_IN_BOOT_LAYER";
-
private static final int MAX_LOCAL_VARS = 256;
private final int BUILDER_VAR = 0;
@@ -434,14 +548,14 @@
private final int MH_VAR = 1; // variable for ModuleHashes
private int nextLocalVar = 2; // index to next local variable
- private final ClassWriter cw;
- private boolean dropModuleTarget;
-
// Method visitor for generating the SystemModules::modules() method
private MethodVisitor mv;
+ // name of class to generate
+ private final String className;
+
// list of all ModuleDescriptorBuilders, invoked in turn when building.
- private final List<ModuleInfo> moduleInfos = new ArrayList<>();
+ private final List<ModuleInfo> moduleInfos;
// A builder to create one single Set instance for a given set of
// names or modifiers to reduce the footprint
@@ -449,10 +563,11 @@
private final DedupSetBuilder dedupSetBuilder
= new DedupSetBuilder(this::getNextLocalVar);
- public SystemModulesClassGenerator(boolean retainModuleTarget) {
- this.cw = new ClassWriter(ClassWriter.COMPUTE_MAXS +
- ClassWriter.COMPUTE_FRAMES);
- this.dropModuleTarget = !retainModuleTarget;
+ public SystemModulesClassGenerator(String className,
+ List<ModuleInfo> moduleInfos) {
+ this.className = className;
+ this.moduleInfos = moduleInfos;
+ moduleInfos.forEach(mi -> dedups(mi.descriptor()));
}
private int getNextLocalVar() {
@@ -460,105 +575,10 @@
}
/*
- * static initializer initializing the static fields
- *
- * static Map<String, ModuleDescriptor> map = new HashMap<>();
- */
- private void clinit(int numModules, int numPackages,
- boolean hasSplitPackages) {
- cw.visit(Opcodes.V1_8, ACC_PUBLIC+ACC_FINAL+ACC_SUPER, CLASSNAME,
- null, "java/lang/Object", null);
-
- // public static String[] MODULE_NAMES = new String[] {....};
- cw.visitField(ACC_PUBLIC+ACC_FINAL+ACC_STATIC, MODULE_NAMES,
- "[Ljava/lang/String;", null, null)
- .visitEnd();
-
- // public static int PACKAGES_IN_BOOT_LAYER;
- cw.visitField(ACC_PUBLIC+ACC_FINAL+ACC_STATIC, PACKAGE_COUNT,
- "I", null, numPackages)
- .visitEnd();
-
- MethodVisitor clinit =
- cw.visitMethod(ACC_STATIC, "<clinit>", "()V",
- null, null);
- clinit.visitCode();
-
- // create the MODULE_NAMES array
- pushInt(clinit, numModules);
- clinit.visitTypeInsn(ANEWARRAY, "java/lang/String");
-
- int index = 0;
- for (ModuleInfo minfo : moduleInfos) {
- clinit.visitInsn(DUP); // arrayref
- pushInt(clinit, index++);
- clinit.visitLdcInsn(minfo.moduleName()); // value
- clinit.visitInsn(AASTORE);
- }
-
- clinit.visitFieldInsn(PUTSTATIC, CLASSNAME, MODULE_NAMES,
- "[Ljava/lang/String;");
-
- clinit.visitInsn(RETURN);
- clinit.visitMaxs(0, 0);
- clinit.visitEnd();
-
- // public static boolean hasSplitPackages();
- MethodVisitor split =
- cw.visitMethod(ACC_PUBLIC+ACC_STATIC, "hasSplitPackages",
- "()Z", null, null);
- split.visitCode();
- split.visitInsn(hasSplitPackages ? ICONST_1 : ICONST_0);
- split.visitInsn(IRETURN);
- split.visitMaxs(0, 0);
- split.visitEnd();
-
- }
-
- /*
* Adds the given ModuleDescriptor to the system module list.
* It performs link-time validation and prepares mapping from various
* Sets to SetBuilders to emit an optimized number of sets during build.
*/
- public ResourcePoolEntry buildModuleInfo(ResourcePoolEntry entry,
- Set<String> packages)
- throws IOException
- {
- if (moduleInfos.isEmpty() && !entry.moduleName().equals("java.base")) {
- throw new InternalError("java.base must be the first module to process");
- }
-
- ModuleInfo moduleInfo;
- if (entry.moduleName().equals("java.base")) {
- moduleInfo = new ModuleInfo(entry.contentBytes(), packages, false);
- ModuleDescriptor md = moduleInfo.descriptor;
- // drop ModuleTarget attribute if java.base has all OS properties
- ModuleTarget target = moduleInfo.target();
- if (dropModuleTarget && target.targetPlatform() != null) {
- dropModuleTarget = true;
- } else {
- dropModuleTarget = false;
- }
- } else {
- moduleInfo = new ModuleInfo(entry.contentBytes(), packages, dropModuleTarget);
- }
-
- // link-time validation
- moduleInfo.validateNames();
- // check if any exported or open package is not present
- moduleInfo.validatePackages();
-
- // module-info.class may be overridden for optimization
- // 1. update ModuleTarget attribute to drop targetPlartform
- // 2. add/update ModulePackages attribute
- if (moduleInfo.shouldRewrite()) {
- entry = entry.copyWithContent(moduleInfo.getBytes());
- }
- moduleInfos.add(moduleInfo);
- dedups(moduleInfo.descriptor());
- return entry;
- }
-
private void dedups(ModuleDescriptor md) {
// exports
for (Exports e : md.exports()) {
@@ -581,47 +601,123 @@
dedupSetBuilder.stringSet(md.uses());
}
- /*
- * Generate bytecode for SystemModules
+ /**
+ * Generate SystemModules class
*/
- public ClassWriter getClassWriter() {
- int numModules = moduleInfos.size();
- Set<String> allPackages = new HashSet<>();
- int packageCount = 0;
- for (ModuleInfo minfo : moduleInfos) {
- allPackages.addAll(minfo.packages);
- packageCount += minfo.packages.size();
- }
+ public ClassWriter getClassWriter(Configuration cf) {
+ ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS
+ + ClassWriter.COMPUTE_FRAMES);
+ cw.visit(Opcodes.V1_8,
+ ACC_FINAL+ACC_SUPER,
+ className,
+ null,
+ "java/lang/Object",
+ new String[] { "jdk/internal/module/SystemModules" });
- int numPackages = allPackages.size();
- boolean hasSplitPackages = (numPackages < packageCount);
- clinit(numModules, numPackages, hasSplitPackages);
+ // generate <init>
+ genConstructor(cw);
+
+ // generate hasSplitPackages
+ genHasSplitPackages(cw);
- // generate SystemModules::descriptors
- genDescriptorsMethod();
+ // generate hasIncubatorModules
+ genIncubatorModules(cw);
- // generate SystemModules::targets
- genTargetsMethod();
+ // generate moduleDescriptors
+ genModuleDescriptorsMethod(cw);
+
+ // generate moduleTargets
+ genModuleTargetsMethod(cw);
- // generate SystemModules::hashes
- genHashesMethod();
+ // generate moduleHashes
+ genModuleHashesMethod(cw);
+
+ // generate moduleResolutions
+ genModuleResolutionsMethod(cw);
- // generate SystemModules::moduleResolutions
- genModuleResolutionsMethod();
+ // generate moduleReads
+ genModuleReads(cw, cf);
- // generate SystemModules::concealedPackagesToOpen and
- // SystemModules::exportedPackagesToOpen
- genXXXPackagesToOpenMethods();
+ // generate concealedPackagesToOpen and exportedPackagesToOpen
+ genXXXPackagesToOpenMethods(cw);
return cw;
}
/**
- * Generate bytecode for SystemModules::descriptors method
+ * Generate byteccode for no-arg constructor
+ */
+ private void genConstructor(ClassWriter cw) {
+ MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitMethodInsn(INVOKESPECIAL,
+ "java/lang/Object",
+ "<init>",
+ "()V",
+ false);
+ mv.visitInsn(RETURN);
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+ }
+
+ /**
+ * Generate bytecode for hasSplitPackages method
*/
- private void genDescriptorsMethod() {
- this.mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC,
- "descriptors",
+ private void genHasSplitPackages(ClassWriter cw) {
+ boolean distinct = moduleInfos.stream()
+ .map(ModuleInfo::packages)
+ .flatMap(Set::stream)
+ .allMatch(new HashSet<>()::add);
+ boolean hasSplitPackages = !distinct;
+
+ mv = cw.visitMethod(ACC_PUBLIC,
+ "hasSplitPackages",
+ "()Z",
+ "()Z",
+ null);
+ mv.visitCode();
+ if (hasSplitPackages) {
+ mv.visitInsn(ICONST_1);
+ } else {
+ mv.visitInsn(ICONST_0);
+ }
+ mv.visitInsn(IRETURN);
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+ }
+
+ /**
+ * Generate bytecode for hasIncubatorModules method
+ */
+ private void genIncubatorModules(ClassWriter cw) {
+ boolean hasIncubatorModules = moduleInfos.stream()
+ .map(ModuleInfo::moduleResolution)
+ .filter(mres -> (mres != null && mres.hasIncubatingWarning()))
+ .findFirst()
+ .isPresent();
+
+ mv = cw.visitMethod(ACC_PUBLIC,
+ "hasIncubatorModules",
+ "()Z",
+ "()Z",
+ null);
+ mv.visitCode();
+ if (hasIncubatorModules) {
+ mv.visitInsn(ICONST_1);
+ } else {
+ mv.visitInsn(ICONST_0);
+ }
+ mv.visitInsn(IRETURN);
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+ }
+
+ /**
+ * Generate bytecode for moduleDescriptors method
+ */
+ private void genModuleDescriptorsMethod(ClassWriter cw) {
+ this.mv = cw.visitMethod(ACC_PUBLIC,
+ "moduleDescriptors",
"()" + MODULE_DESCRIPTOR_ARRAY_SIGNATURE,
"()" + MODULE_DESCRIPTOR_ARRAY_SIGNATURE,
null);
@@ -643,11 +739,11 @@
}
/**
- * Generate bytecode for SystemModules::targets method
+ * Generate bytecode for moduleTargets method
*/
- private void genTargetsMethod() {
- MethodVisitor mv = cw.visitMethod(ACC_PUBLIC+ACC_STATIC,
- "targets",
+ private void genModuleTargetsMethod(ClassWriter cw) {
+ MethodVisitor mv = cw.visitMethod(ACC_PUBLIC,
+ "moduleTargets",
"()" + MODULE_TARGET_ARRAY_SIGNATURE,
"()" + MODULE_TARGET_ARRAY_SIGNATURE,
null);
@@ -656,18 +752,34 @@
mv.visitTypeInsn(ANEWARRAY, MODULE_TARGET_CLASSNAME);
mv.visitVarInsn(ASTORE, MT_VAR);
- for (int index=0; index < moduleInfos.size(); index++) {
+
+ // if java.base has a ModuleTarget attribute then generate the array
+ // with one element, all other elements will be null.
+
+ ModuleInfo base = moduleInfos.get(0);
+ if (!base.moduleName().equals("java.base"))
+ throw new InternalError("java.base should be first module in list");
+ ModuleTarget target = base.target();
+
+ int count;
+ if (target != null && target.targetPlatform() != null) {
+ count = 1;
+ } else {
+ count = moduleInfos.size();
+ }
+
+ for (int index = 0; index < count; index++) {
ModuleInfo minfo = moduleInfos.get(index);
- if (minfo.target() != null && !minfo.dropModuleTarget) {
+ if (minfo.target() != null) {
mv.visitVarInsn(ALOAD, MT_VAR);
pushInt(mv, index);
- // new ModuleTarget(String, String)
+ // new ModuleTarget(String)
mv.visitTypeInsn(NEW, MODULE_TARGET_CLASSNAME);
mv.visitInsn(DUP);
mv.visitLdcInsn(minfo.target().targetPlatform());
mv.visitMethodInsn(INVOKESPECIAL, MODULE_TARGET_CLASSNAME,
- "<init>", "(Ljava/lang/String;)V", false);
+ "<init>", "(Ljava/lang/String;)V", false);
mv.visitInsn(AASTORE);
}
@@ -680,12 +792,12 @@
}
/**
- * Generate bytecode for SystemModules::hashes method
+ * Generate bytecode for moduleHashes method
*/
- private void genHashesMethod() {
+ private void genModuleHashesMethod(ClassWriter cw) {
MethodVisitor hmv =
- cw.visitMethod(ACC_PUBLIC + ACC_STATIC,
- "hashes",
+ cw.visitMethod(ACC_PUBLIC,
+ "moduleHashes",
"()" + MODULE_HASHES_ARRAY_SIGNATURE,
"()" + MODULE_HASHES_ARRAY_SIGNATURE,
null);
@@ -710,11 +822,11 @@
}
/**
- * Generate bytecode for SystemModules::methodResoultions method
+ * Generate bytecode for moduleResolutions method
*/
- private void genModuleResolutionsMethod() {
+ private void genModuleResolutionsMethod(ClassWriter cw) {
MethodVisitor mresmv =
- cw.visitMethod(ACC_PUBLIC+ACC_STATIC,
+ cw.visitMethod(ACC_PUBLIC,
"moduleResolutions",
"()" + MODULE_RESOLUTIONS_ARRAY_SIGNATURE,
"()" + MODULE_RESOLUTIONS_ARRAY_SIGNATURE,
@@ -746,75 +858,88 @@
}
/**
- * Generate SystemModules::concealedPackagesToOpen and
- * SystemModules::exportedPackagesToOpen methods.
+ * Generate bytecode for moduleReads method
*/
- private void genXXXPackagesToOpenMethods() {
- List<ModuleDescriptor> descriptors = moduleInfos.stream()
- .map(ModuleInfo::descriptor)
- .collect(Collectors.toList());
- ModuleFinder finder = finderOf(descriptors);
- IllegalAccessMaps maps = IllegalAccessMaps.generate(finder);
- generate("concealedPackagesToOpen", maps.concealedPackagesToOpen());
- generate("exportedPackagesToOpen", maps.exportedPackagesToOpen());
+ private void genModuleReads(ClassWriter cw, Configuration cf) {
+ // module name -> names of modules that it reads
+ Map<String, Set<String>> map = cf.modules().stream()
+ .collect(Collectors.toMap(
+ ResolvedModule::name,
+ m -> m.reads().stream()
+ .map(ResolvedModule::name)
+ .collect(Collectors.toSet())));
+ generate(cw, "moduleReads", map, true);
}
/**
- * Generate SystemModules:XXXPackagesToOpen
+ * Generate concealedPackagesToOpen and exportedPackagesToOpen methods.
*/
- private void generate(String methodName, Map<String, Set<String>> map) {
- // Map<String, Set<String>> XXXPackagesToOpen()
- MethodVisitor mv = cw.visitMethod(ACC_PUBLIC+ACC_STATIC,
+ private void genXXXPackagesToOpenMethods(ClassWriter cw) {
+ ModuleFinder finder = finderOf(moduleInfos);
+ IllegalAccessMaps maps = IllegalAccessMaps.generate(finder);
+ generate(cw, "concealedPackagesToOpen", maps.concealedPackagesToOpen(), false);
+ generate(cw, "exportedPackagesToOpen", maps.exportedPackagesToOpen(), false);
+ }
+
+ /**
+ * Generate method to return {@code Map<String, Set<String>>}.
+ *
+ * If {@code dedup} is true then the values are de-duplicated.
+ */
+ private void generate(ClassWriter cw,
+ String methodName,
+ Map<String, Set<String>> map,
+ boolean dedup) {
+ MethodVisitor mv = cw.visitMethod(ACC_PUBLIC,
methodName,
"()Ljava/util/Map;",
"()Ljava/util/Map;",
null);
mv.visitCode();
- // new Map$Entry[moduleCount]
+ // map of Set -> local
+ Map<Set<String>, Integer> locals;
+
+ // generate code to create the sets that are duplicated
+ if (dedup) {
+ Collection<Set<String>> values = map.values();
+ Set<Set<String>> duplicateSets = values.stream()
+ .distinct()
+ .filter(s -> Collections.frequency(values, s) > 1)
+ .collect(Collectors.toSet());
+ locals = new HashMap<>();
+ int index = 1;
+ for (Set<String> s : duplicateSets) {
+ genImmutableSet(mv, s);
+ mv.visitVarInsn(ASTORE, index);
+ locals.put(s, index);
+ if (++index >= MAX_LOCAL_VARS) {
+ break;
+ }
+ }
+ } else {
+ locals = Map.of();
+ }
+
+ // new Map$Entry[size]
pushInt(mv, map.size());
mv.visitTypeInsn(ANEWARRAY, "java/util/Map$Entry");
int index = 0;
for (Map.Entry<String, Set<String>> e : map.entrySet()) {
- String moduleName = e.getKey();
- Set<String> packages = e.getValue();
- int packageCount = packages.size();
+ String name = e.getKey();
+ Set<String> s = e.getValue();
mv.visitInsn(DUP);
pushInt(mv, index);
- mv.visitLdcInsn(moduleName);
+ mv.visitLdcInsn(name);
- // use Set.of(Object[]) when there are more than 2 packages
- // use Set.of(Object) or Set.of(Object, Object) when fewer packages
- if (packageCount > 2) {
- pushInt(mv, packageCount);
- mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
- int i = 0;
- for (String pn : packages) {
- mv.visitInsn(DUP);
- pushInt(mv, i);
- mv.visitLdcInsn(pn);
- mv.visitInsn(AASTORE);
- i++;
- }
- mv.visitMethodInsn(INVOKESTATIC,
- "java/util/Set",
- "of",
- "([Ljava/lang/Object;)Ljava/util/Set;",
- true);
+ // if de-duplicated then load the local, otherwise generate code
+ Integer varIndex = locals.get(s);
+ if (varIndex == null) {
+ genImmutableSet(mv, s);
} else {
- StringBuilder sb = new StringBuilder("(");
- for (String pn : packages) {
- mv.visitLdcInsn(pn);
- sb.append("Ljava/lang/Object;");
- }
- sb.append(")Ljava/util/Set;");
- mv.visitMethodInsn(INVOKESTATIC,
- "java/util/Set",
- "of",
- sb.toString(),
- true);
+ mv.visitVarInsn(ALOAD, varIndex);
}
String desc = "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/util/Map$Entry;";
@@ -835,19 +960,42 @@
mv.visitEnd();
}
- public boolean isOverriddenClass(String path) {
- return path.equals("/java.base/" + CLASSNAME + ".class");
- }
+ /**
+ * Generate code to generate an immutable set.
+ */
+ private void genImmutableSet(MethodVisitor mv, Set<String> set) {
+ int size = set.size();
- void pushInt(MethodVisitor mv, int num) {
- if (num <= 5) {
- mv.visitInsn(ICONST_0 + num);
- } else if (num < Byte.MAX_VALUE) {
- mv.visitIntInsn(BIPUSH, num);
- } else if (num < Short.MAX_VALUE) {
- mv.visitIntInsn(SIPUSH, num);
+ // use Set.of(Object[]) when there are more than 2 elements
+ // use Set.of(Object) or Set.of(Object, Object) when fewer
+ if (size > 2) {
+ pushInt(mv, size);
+ mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
+ int i = 0;
+ for (String element : set) {
+ mv.visitInsn(DUP);
+ pushInt(mv, i);
+ mv.visitLdcInsn(element);
+ mv.visitInsn(AASTORE);
+ i++;
+ }
+ mv.visitMethodInsn(INVOKESTATIC,
+ "java/util/Set",
+ "of",
+ "([Ljava/lang/Object;)Ljava/util/Set;",
+ true);
} else {
- throw new IllegalArgumentException("exceed limit: " + num);
+ StringBuilder sb = new StringBuilder("(");
+ for (String element : set) {
+ mv.visitLdcInsn(element);
+ sb.append("Ljava/lang/Object;");
+ }
+ sb.append(")Ljava/util/Set;");
+ mv.visitMethodInsn(INVOKESTATIC,
+ "java/util/Set",
+ "of",
+ sb.toString(),
+ true);
}
}
@@ -1564,18 +1712,159 @@
}
}
- static ModuleFinder finderOf(Iterable<ModuleDescriptor> descriptors) {
+ /**
+ * Generate SystemModulesMap and add it as a resource.
+ *
+ * @return the name of the class resource added to the pool
+ */
+ private String genSystemModulesMapClass(String allSystemModulesClassName,
+ String defaultSystemModulesClassName,
+ Map<String, String> map,
+ ResourcePoolBuilder out) {
+ ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS
+ + ClassWriter.COMPUTE_FRAMES);
+ cw.visit(Opcodes.V1_8,
+ ACC_FINAL+ACC_SUPER,
+ SYSTEM_MODULES_MAP_CLASS,
+ null,
+ "java/lang/Object",
+ null);
+
+ // <init>
+ MethodVisitor mv = cw.visitMethod(0, "<init>", "()V", null, null);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitMethodInsn(INVOKESPECIAL,
+ "java/lang/Object",
+ "<init>",
+ "()V",
+ false);
+ mv.visitInsn(RETURN);
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+
+ // allSystemModules()
+ mv = cw.visitMethod(ACC_STATIC,
+ "allSystemModules",
+ "()Ljdk/internal/module/SystemModules;",
+ "()Ljdk/internal/module/SystemModules;",
+ null);
+ mv.visitCode();
+ mv.visitTypeInsn(NEW, allSystemModulesClassName);
+ mv.visitInsn(DUP);
+ mv.visitMethodInsn(INVOKESPECIAL,
+ allSystemModulesClassName,
+ "<init>",
+ "()V",
+ false);
+ mv.visitInsn(ARETURN);
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+
+ // defaultSystemModules()
+ mv = cw.visitMethod(ACC_STATIC,
+ "defaultSystemModules",
+ "()Ljdk/internal/module/SystemModules;",
+ "()Ljdk/internal/module/SystemModules;",
+ null);
+ mv.visitCode();
+ mv.visitTypeInsn(NEW, defaultSystemModulesClassName);
+ mv.visitInsn(DUP);
+ mv.visitMethodInsn(INVOKESPECIAL,
+ defaultSystemModulesClassName,
+ "<init>",
+ "()V",
+ false);
+ mv.visitInsn(ARETURN);
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+
+ // moduleNames()
+ mv = cw.visitMethod(ACC_STATIC,
+ "moduleNames",
+ "()[Ljava/lang/String;",
+ "()[Ljava/lang/String;",
+ null);
+ mv.visitCode();
+ pushInt(mv, map.size());
+ mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
+
+ int index = 0;
+ for (String moduleName : map.keySet()) {
+ mv.visitInsn(DUP); // arrayref
+ pushInt(mv, index);
+ mv.visitLdcInsn(moduleName);
+ mv.visitInsn(AASTORE);
+ index++;
+ }
+
+ mv.visitInsn(ARETURN);
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+
+ // classNames()
+ mv = cw.visitMethod(ACC_STATIC,
+ "classNames",
+ "()[Ljava/lang/String;",
+ "()[Ljava/lang/String;",
+ null);
+ mv.visitCode();
+ pushInt(mv, map.size());
+ mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
+
+ index = 0;
+ for (String className : map.values()) {
+ mv.visitInsn(DUP); // arrayref
+ pushInt(mv, index);
+ mv.visitLdcInsn(className.replace('/', '.'));
+ mv.visitInsn(AASTORE);
+ index++;
+ }
+
+ mv.visitInsn(ARETURN);
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+
+ // write the class file to the pool as a resource
+ String rn = "/java.base/" + SYSTEM_MODULES_MAP_CLASS + ".class";
+ ResourcePoolEntry e = ResourcePoolEntry.create(rn, cw.toByteArray());
+ out.add(e);
+
+ return rn;
+ }
+
+ /**
+ * Pushes an int constant
+ */
+ private static void pushInt(MethodVisitor mv, int value) {
+ if (value <= 5) {
+ mv.visitInsn(ICONST_0 + value);
+ } else if (value < Byte.MAX_VALUE) {
+ mv.visitIntInsn(BIPUSH, value);
+ } else if (value < Short.MAX_VALUE) {
+ mv.visitIntInsn(SIPUSH, value);
+ } else {
+ throw new IllegalArgumentException("exceed limit: " + value);
+ }
+ }
+
+ /**
+ * Returns a module finder that finds all modules in the given list
+ */
+ private static ModuleFinder finderOf(Collection<ModuleInfo> moduleInfos) {
+ Supplier<ModuleReader> readerSupplier = () -> null;
Map<String, ModuleReference> namesToReference = new HashMap<>();
- for (ModuleDescriptor descriptor : descriptors) {
- String name = descriptor.name();
- URI uri = URI.create("module:/" + name);
- ModuleReference mref = new ModuleReference(descriptor, uri) {
- @Override
- public ModuleReader open() {
- throw new UnsupportedOperationException();
- }
- };
- namesToReference.putIfAbsent(name, mref);
+ for (ModuleInfo mi : moduleInfos) {
+ String name = mi.moduleName();
+ ModuleReference mref
+ = new ModuleReferenceImpl(mi.descriptor(),
+ URI.create("jrt:/" + name),
+ readerSupplier,
+ null,
+ mi.target(),
+ null,
+ null,
+ mi.moduleResolution());
+ namesToReference.put(name, mref);
}
return new ModuleFinder() {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/crypto/provider/Cipher/DES/DESKeyCleanupTest.java Thu Aug 24 16:34:26 2017 +0200
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @modules java.base/com.sun.crypto.provider:+open
+ * @run main/othervm DESKeyCleanupTest
+ * @summary Verify that key storage is cleared
+ */
+
+import java.lang.ref.PhantomReference;
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.reflect.Field;
+import java.util.Arrays;
+
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+
+/**
+ * Test that the array holding the key bytes is cleared when it is
+ * no longer referenced by the key.
+ */
+
+public class DESKeyCleanupTest {
+
+ private final static String SunJCEProvider = "SunJCE";
+
+ public static void main(String[] args) throws Exception {
+ testCleanupSecret("DES");
+ testCleanupSecret("DESede");
+ }
+
+ static void testCleanupSecret(String algorithm) throws Exception {
+ KeyGenerator desGen = KeyGenerator.getInstance(algorithm, SunJCEProvider);
+ SecretKey key = desGen.generateKey();
+
+ // Break into the implementation to observe the key byte array.
+ Class<?> keyClass = key.getClass();
+ Field keyField = keyClass.getDeclaredField("key");
+ keyField.setAccessible(true);
+ byte[] array = (byte[])keyField.get(key);
+
+ byte[] zeros = new byte[array.length];
+ do {
+ // Wait for array to be cleared; if not cleared test will timeout
+ System.out.printf("%s array: %s%n", algorithm, Arrays.toString(array));
+ key = null;
+ System.gc(); // attempt to reclaim the key
+ } while (Arrays.compare(zeros, array) != 0);
+ System.out.printf("%s array: %s%n", algorithm, Arrays.toString(array));
+
+ Reference.reachabilityFence(key); // Keep key alive
+ Reference.reachabilityFence(array); // Keep array alive
+ }
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/crypto/provider/Cipher/PBE/PBEKeyCleanupTest.java Thu Aug 24 16:34:26 2017 +0200
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @modules java.base/com.sun.crypto.provider:+open
+ * @run main/othervm PBEKeyCleanupTest
+ * @summary Verify that key storage is cleared
+ */
+
+import java.lang.ref.PhantomReference;
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.Random;
+
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+
+/**
+ * Test that the array holding the key bytes is cleared when it is
+ * no longer referenced by the key.
+ */
+public class PBEKeyCleanupTest {
+
+ private final static String SunJCEProvider = "SunJCE";
+
+ private static final String PASS_PHRASE = "some hidden string";
+ private static final int ITERATION_COUNT = 1000;
+ private static final int KEY_SIZE = 128;
+
+ public static void main(String[] args) throws Exception {
+ testPBESecret("PBEWithMD5AndDES");
+ testPBKSecret("PBKDF2WithHmacSHA1");
+ }
+
+ private static void testPBESecret(String algorithm) throws Exception {
+ char[] password = new char[] {'f', 'o', 'o'};
+ PBEKeySpec pbeKeySpec = new PBEKeySpec(password);
+ SecretKeyFactory keyFac =
+ SecretKeyFactory.getInstance(algorithm, SunJCEProvider);
+
+ testCleanupSecret(algorithm, keyFac.generateSecret(pbeKeySpec));
+ }
+
+ private static void testPBKSecret(String algorithm) throws Exception {
+ byte[] salt = new byte[8];
+ new Random().nextBytes(salt);
+ char[] password = new char[] {'f', 'o', 'o'};
+ PBEKeySpec pbeKeySpec = new PBEKeySpec(PASS_PHRASE.toCharArray(), salt,
+ ITERATION_COUNT, KEY_SIZE);
+ SecretKeyFactory keyFac =
+ SecretKeyFactory.getInstance(algorithm, SunJCEProvider);
+
+ testCleanupSecret(algorithm, keyFac.generateSecret(pbeKeySpec));
+ }
+
+ static void testCleanupSecret(String algorithm, SecretKey key) throws Exception {
+
+ // Break into the implementation to observe the key byte array.
+ Class<?> keyClass = key.getClass();
+ Field keyField = keyClass.getDeclaredField("key");
+ keyField.setAccessible(true);
+ byte[] array = (byte[])keyField.get(key);
+
+ byte[] zeros = new byte[array.length];
+ do {
+ // Wait for array to be cleared; if not cleared test will timeout
+ System.out.printf("%s array: %s%n", algorithm, Arrays.toString(array));
+ key = null;
+ System.gc(); // attempt to reclaim the key
+ } while (Arrays.compare(zeros, array) != 0);
+ System.out.printf("%s array: %s%n", algorithm, Arrays.toString(array));
+
+ Reference.reachabilityFence(key); // Keep key alive
+ Reference.reachabilityFence(array); // Keep array alive
+ }
+}
+
+
+
--- a/jdk/test/java/lang/ClassLoader/getResource/GetResource.java Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/test/java/lang/ClassLoader/getResource/GetResource.java Thu Aug 24 16:34:26 2017 +0200
@@ -125,10 +125,9 @@
return new Object[][] {
new Object[] { List.of("-Xbootclasspath/a:."), "a"},
- // "b" is the expected result when JDK-8185540 is resolved
- new Object[] { List.of("-Xbootclasspath/a:" + dirB), "a"},
+ new Object[] { List.of("-Xbootclasspath/a:" + dirB), "b"},
// empty path in first element
- new Object[] { List.of("-Xbootclasspath/a:" + File.pathSeparator + dirB), "a"},
+ new Object[] { List.of("-Xbootclasspath/a:" + File.pathSeparator + dirB), "b"},
new Object[] { List.of("-cp", File.pathSeparator), "a"},
new Object[] { List.of("-cp", dirB), "b"},
--- a/jdk/test/java/net/httpclient/security/0.policy Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/test/java/net/httpclient/security/0.policy Thu Aug 24 16:34:26 2017 +0200
@@ -23,6 +23,7 @@
grant codeBase "jrt:/jdk.incubator.httpclient" {
permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
+ permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
--- a/jdk/test/java/net/httpclient/security/1.policy Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/test/java/net/httpclient/security/1.policy Thu Aug 24 16:34:26 2017 +0200
@@ -23,6 +23,7 @@
grant codeBase "jrt:/jdk.incubator.httpclient" {
permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
+ permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
--- a/jdk/test/java/net/httpclient/security/10.policy Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/test/java/net/httpclient/security/10.policy Thu Aug 24 16:34:26 2017 +0200
@@ -22,6 +22,7 @@
grant codeBase "jrt:/jdk.incubator.httpclient" {
permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
+ permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
--- a/jdk/test/java/net/httpclient/security/11.policy Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/test/java/net/httpclient/security/11.policy Thu Aug 24 16:34:26 2017 +0200
@@ -24,6 +24,7 @@
grant codeBase "jrt:/jdk.incubator.httpclient" {
permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
+ permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
--- a/jdk/test/java/net/httpclient/security/12.policy Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/test/java/net/httpclient/security/12.policy Thu Aug 24 16:34:26 2017 +0200
@@ -24,6 +24,7 @@
grant codeBase "jrt:/jdk.incubator.httpclient" {
permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
+ permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
--- a/jdk/test/java/net/httpclient/security/14.policy Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/test/java/net/httpclient/security/14.policy Thu Aug 24 16:34:26 2017 +0200
@@ -23,6 +23,7 @@
grant codeBase "jrt:/jdk.incubator.httpclient" {
permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
+ permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
--- a/jdk/test/java/net/httpclient/security/15.policy Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/test/java/net/httpclient/security/15.policy Thu Aug 24 16:34:26 2017 +0200
@@ -26,6 +26,7 @@
grant codeBase "jrt:/jdk.incubator.httpclient" {
permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
+ permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
--- a/jdk/test/java/net/httpclient/security/2.policy Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/test/java/net/httpclient/security/2.policy Thu Aug 24 16:34:26 2017 +0200
@@ -23,6 +23,7 @@
grant codeBase "jrt:/jdk.incubator.httpclient" {
permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
+ permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
--- a/jdk/test/java/net/httpclient/security/3.policy Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/test/java/net/httpclient/security/3.policy Thu Aug 24 16:34:26 2017 +0200
@@ -23,6 +23,7 @@
grant codeBase "jrt:/jdk.incubator.httpclient" {
permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
+ permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
--- a/jdk/test/java/net/httpclient/security/4.policy Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/test/java/net/httpclient/security/4.policy Thu Aug 24 16:34:26 2017 +0200
@@ -24,6 +24,7 @@
grant codeBase "jrt:/jdk.incubator.httpclient" {
permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
+ permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
--- a/jdk/test/java/net/httpclient/security/5.policy Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/test/java/net/httpclient/security/5.policy Thu Aug 24 16:34:26 2017 +0200
@@ -23,6 +23,7 @@
grant codeBase "jrt:/jdk.incubator.httpclient" {
permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
+ permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
--- a/jdk/test/java/net/httpclient/security/6.policy Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/test/java/net/httpclient/security/6.policy Thu Aug 24 16:34:26 2017 +0200
@@ -23,6 +23,7 @@
grant codeBase "jrt:/jdk.incubator.httpclient" {
permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
+ permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
--- a/jdk/test/java/net/httpclient/security/7.policy Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/test/java/net/httpclient/security/7.policy Thu Aug 24 16:34:26 2017 +0200
@@ -23,6 +23,7 @@
grant codeBase "jrt:/jdk.incubator.httpclient" {
permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
+ permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
--- a/jdk/test/java/net/httpclient/security/8.policy Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/test/java/net/httpclient/security/8.policy Thu Aug 24 16:34:26 2017 +0200
@@ -23,6 +23,7 @@
grant codeBase "jrt:/jdk.incubator.httpclient" {
permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
+ permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
--- a/jdk/test/java/net/httpclient/security/9.policy Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/test/java/net/httpclient/security/9.policy Thu Aug 24 16:34:26 2017 +0200
@@ -23,6 +23,7 @@
grant codeBase "jrt:/jdk.incubator.httpclient" {
permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
+ permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
--- a/jdk/test/java/net/httpclient/security/Driver.java Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/test/java/net/httpclient/security/Driver.java Thu Aug 24 16:34:26 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -34,7 +34,7 @@
* @compile ../ProxyServer.java
* @build Security
*
- * @run driver/timeout=60 Driver
+ * @run driver/timeout=90 Driver
*/
/**
--- a/jdk/test/java/nio/channels/Selector/KeySets.java Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/test/java/nio/channels/Selector/KeySets.java Thu Aug 24 16:34:26 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,34 +26,25 @@
* @summary Check various properties of key and selected-key sets
*
* @run main KeySets
- * @run main/othervm -Dsun.nio.ch.bugLevel=1.4 KeySets
*/
import java.io.*;
import java.nio.channels.*;
import java.util.*;
-
public class KeySets {
- static boolean compat;
-
static abstract class Catch {
abstract void go() throws Exception;
Catch(Class xc) throws Exception {
try {
go();
} catch (Exception x) {
- if (compat)
- throw new Exception("Exception thrown", x);
if (xc.isInstance(x))
return;
throw new Exception("Wrong exception", x);
}
- if (compat)
- return;
- throw new Exception("Not thrown as expected: "
- + xc.getName());
+ throw new Exception("Not thrown as expected: " + xc.getName());
}
}
@@ -74,7 +65,6 @@
void go() throws Exception {
sel.selectedKeys();
}};
-
}
static void testNoAddition(final Set s) throws Exception {
@@ -174,14 +164,10 @@
sel.selectedKeys().clear();
if (!sel.selectedKeys().isEmpty())
throw new Exception("clear failed");
-
}
public static void main(String[] args) throws Exception {
- String bl = System.getProperty("sun.nio.ch.bugLevel");
- compat = (bl != null) && bl.equals("1.4");
testClose();
testMutability();
}
-
}
--- a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/SystemModulesTest.java Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/SystemModulesTest.java Thu Aug 24 16:34:26 2017 +0200
@@ -111,16 +111,10 @@
private void checkAttributes(ModuleReference modRef) {
try {
- if (modRef.descriptor().name().equals("java.base")) {
- ModuleTargetHelper.ModuleTarget mt = ModuleTargetHelper.read(modRef);
- String[] values = mt.targetPlatform().split("-");
- assertTrue(checkOSName(values[0]));
- assertTrue(checkOSArch(values[1]));
- } else {
- // target platform attribute is dropped by jlink plugin for other modules
- ModuleTargetHelper.ModuleTarget mt = ModuleTargetHelper.read(modRef);
- assertTrue(mt == null || mt.targetPlatform() == null);
- }
+ ModuleTargetHelper.ModuleTarget mt = ModuleTargetHelper.read(modRef);
+ String[] values = mt.targetPlatform().split("-");
+ assertTrue(checkOSName(values[0]));
+ assertTrue(checkOSArch(values[1]));
} catch (IOException exp) {
throw new UncheckedIOException(exp);
}
--- a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/UserModuleTest.java Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/UserModuleTest.java Thu Aug 24 16:34:26 2017 +0200
@@ -284,7 +284,6 @@
Set<String> modules = Set.of("m1", "m4");
assertTrue(JLINK_TOOL.run(System.out, System.out,
"--output", dir.toString(),
- "--system-modules", "retainModuleTarget",
"--exclude-resources", "m4/p4/dummy/*",
"--add-modules", modules.stream().collect(Collectors.joining(",")),
"--module-path", mp) == 0);
--- a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m4/p4/Main.java Fri Aug 04 23:29:08 2017 +0000
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m4/p4/Main.java Thu Aug 24 16:34:26 2017 +0200
@@ -32,7 +32,7 @@
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.util.Collections;
+import java.util.Map;
import java.util.Set;
import jdk.internal.module.ClassFileAttributes;
@@ -67,8 +67,7 @@
}
private static boolean hasModuleTarget(String modName) throws IOException {
- FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"),
- Collections.emptyMap());
+ FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"), Map.of());
Path path = fs.getPath("/", "modules", modName, "module-info.class");
try (InputStream in = Files.newInputStream(path)) {
return hasModuleTarget(in);
@@ -86,8 +85,8 @@
expectModuleTarget = true;
}
- // java.base is packaged with osName/osArch/osVersion
- if (! hasModuleTarget("java.base")) {
+ // java.base is packaged with ModuleTarget
+ if (!hasModuleTarget("java.base")) {
throw new RuntimeException("ModuleTarget absent for java.base");
}
@@ -109,8 +108,7 @@
}
// verify ModuleDescriptor from module-info.class read from jimage
- FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"),
- Collections.emptyMap());
+ FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"), Map.of());
Path path = fs.getPath("/", "modules", mn, "module-info.class");
checkModuleDescriptor(ModuleDescriptor.read(Files.newInputStream(path)), packages);
}
@@ -121,16 +119,9 @@
throw new RuntimeException(md.mainClass().toString());
}
- if (expectModuleTarget) {
- // ModuleTarget attribute is retained
- if (! hasModuleTarget(md.name())) {
- throw new RuntimeException("ModuleTarget missing for " + md.name());
- }
- } else {
- // by default ModuleTarget attribute is dropped
- if (hasModuleTarget(md.name())) {
- throw new RuntimeException("ModuleTarget present for " + md.name());
- }
+ // ModuleTarget attribute should be present
+ if (!hasModuleTarget(md.name())) {
+ throw new RuntimeException("ModuleTarget missing for " + md.name());
}
Set<String> pkgs = md.packages();
--- a/jdk/test/tools/launcher/modules/patch/systemmodules/src1/java.base/jdk/internal/modules/SystemModules.java Fri Aug 04 23:29:08 2017 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.internal.module;
-
-import java.util.Collections;
-import java.util.Map;
-import java.util.Set;
-
-/*
- * Test --patch-module java.base=jdk/modules/java.base to override
- * java.base with an exploded image
- */
-public final class SystemModules {
- public static final String[] MODULE_NAMES = new String[0];
-
- public static int PACKAGES_IN_BOOT_LAYER = 1024;
-
- public static boolean hasSplitPackages() {
- return true;
- }
-
- public static Map<String, Set<String>> concealedPackagesToOpen() {
- return Collections.emptyMap();
- }
-
- public static Map<String, Set<String>> exportedPackagesToOpen() {
- return Collections.emptyMap();
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/launcher/modules/patch/systemmodules/src1/java.base/jdk/internal/modules/SystemModulesMap.java Thu Aug 24 16:34:26 2017 +0200
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.module;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+/*
+ * Test --patch-module java.base=jdk/modules/java.base to override
+ * java.base with an exploded image
+ */
+class SystemModulesMap {
+ static SystemModules allSystemModules() {
+ return null;
+ }
+ static SystemModules defaultSystemModules() {
+ return null;
+ }
+ static String[] moduleNames() {
+ return new String[0];
+ }
+ static String[] classNames() {
+ return new String[0];
+ }
+}
--- a/make/Docs.gmk Fri Aug 04 23:29:08 2017 +0000
+++ b/make/Docs.gmk Thu Aug 24 16:34:26 2017 +0200
@@ -101,9 +101,9 @@
JAVADOC_DISABLED_DOCLINT := accessibility html missing syntax reference
# The initial set of options for javadoc
-JAVADOC_OPTIONS := -XDignore.symbol.file=true -use -keywords -notimestamp \
- -serialwarn -encoding ISO-8859-1 -breakiterator -splitIndex --system none \
- -html5 -javafx --expand-requires transitive
+JAVADOC_OPTIONS := -use -keywords -notimestamp \
+ -serialwarn -encoding ISO-8859-1 -docencoding UTF-8 -breakiterator \
+ -splitIndex --system none -html5 -javafx --expand-requires transitive
# Should we add DRAFT stamps to the generated javadoc?
ifeq ($(VERSION_IS_GA), true)