--- old/src/java.base/share/classes/java/lang/module/SystemModuleFinder.java 2016-12-15 09:19:30.566334918 +0000 +++ /dev/null 2016-12-10 08:16:53.177999985 +0000 @@ -1,443 +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 java.lang.module; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.UncheckedIOException; -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.HashSet; -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.ModuleBootstrap; -import jdk.internal.module.ModuleHashes; -import jdk.internal.module.ModuleHashes.HashSupplier; -import jdk.internal.module.SystemModules; -import jdk.internal.module.ModulePatcher; -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. - */ - -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"); - // ImageReader used to access all modules in the image - private static final ImageReader imageReader; - - // the set of modules in the run-time image - private static final Set modules; - - // maps module name to module reference - private static final Map nameToModule; - - /** - * 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(); - imageReader = ImageReaderFactory.getImageReader(); - - String[] names = moduleNames(); - ModuleDescriptor[] descriptors = descriptors(names); - - int n = names.length; - moduleCount.add(n); - - ModuleReference[] mods = new ModuleReference[n]; - - @SuppressWarnings(value = {"rawtypes", "unchecked"}) - Entry[] map - = (Entry[])new Entry[n]; - - for (int i = 0; i < n; i++) { - ModuleDescriptor md = descriptors[i]; - - // create the ModuleReference - ModuleReference mref = toModuleReference(md, hashSupplier(i, names[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); - - initTime.addElapsedTimeFrom(t0); - } - - /* - * Returns an array of ModuleDescriptor of the given module names. - * - * This obtains ModuleDescriptors from SystemModules class that is generated - * from the jlink system-modules plugin. ModuleDescriptors have already - * been validated at link time. - * - * If java.base is patched, or fastpath is disabled for troubleshooting - * purpose, it will fall back to find system modules via jrt file system. - */ - private static ModuleDescriptor[] descriptors(String[] names) { - // fastpath is enabled by default. - // It can be disabled for troubleshooting purpose. - boolean disabled = - System.getProperty("jdk.system.module.finder.disabledFastPath") != null; - - // fast loading of ModuleDescriptor of system modules - if (isFastPathSupported() && !disabled) - return SystemModules.modules(); - - // if fast loading of ModuleDescriptors is disabled - // fallback to read module-info.class - ModuleDescriptor[] descriptors = new ModuleDescriptor[names.length]; - for (int i = 0; i < names.length; i++) { - String mn = names[i]; - ImageLocation loc = imageReader.findLocation(mn, "module-info.class"); - descriptors[i] = ModuleDescriptor.read(imageReader.getResourceBuffer(loc)); - - // add the recorded hashes of tied modules - Hashes.add(descriptors[i]); - } - return descriptors; - } - - 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 imageReader.getModuleNames(); - } - - private static ModuleReference toModuleReference(ModuleDescriptor md, - HashSupplier hash) - { - String mn = md.name(); - URI uri = JNUA.create("jrt", "/".concat(mn)); - - Supplier readerSupplier = new Supplier<>() { - @Override - public ModuleReader get() { - return new ImageModuleReader(mn, uri); - } - }; - - ModuleReference mref = - new ModuleReference(md, uri, readerSupplier, hash); - - // may need a reference to a patched module if --patch-module specified - mref = ModuleBootstrap.patcher().patchIfNeeded(mref); - - return mref; - } - - private static HashSupplier hashSupplier(int index, String name) { - if (isFastPathSupported()) { - return new HashSupplier() { - @Override - public byte[] generate(String algorithm) { - return SystemModules.MODULES_TO_HASH[index]; - } - }; - } else { - return Hashes.hashFor(name); - } - } - - /* - * This helper class is only used when SystemModules is patched. - * It will get the recorded hashes from module-info.class. - */ - private static class Hashes { - static Map hashes = new HashMap<>(); - - static void add(ModuleDescriptor descriptor) { - Optional ohashes = descriptor.hashes(); - if (ohashes.isPresent()) { - hashes.putAll(ohashes.get().hashes()); - } - } - - static HashSupplier hashFor(String name) { - if (!hashes.containsKey(name)) - return null; - - return new HashSupplier() { - @Override - public byte[] generate(String algorithm) { - return hashes.get(name); - } - }; - } - } - - SystemModuleFinder() { } - - @Override - public Optional find(String name) { - Objects.requireNonNull(name); - return Optional.ofNullable(nameToModule.get(name)); - } - - @Override - public Set findAll() { - return modules; - } - - - /** - * 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"); - if (imageReader != null) { - return imageReader.findLocation(module, name); - } else { - // not an images build - return null; - } - } - - @Override - public Optional 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 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 read(String name) throws IOException { - ImageLocation location = findImageLocation(name); - if (location != null) { - return Optional.of(imageReader.getResourceBuffer(location)); - } else { - return Optional.empty(); - } - } - - @Override - public void release(ByteBuffer bb) { - Objects.requireNonNull(bb); - ImageReader.releaseByteBuffer(bb); - } - - @Override - public Stream list() throws IOException { - if (closed) - throw new IOException("ModuleReader is closed"); - - Spliterator 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 { - final String moduleRoot; - final Deque stack; - Iterator 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 = imageReader.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 = imageReader.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 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 trySplit() { - return null; - } - - @Override - public int characteristics() { - return Spliterator.DISTINCT + Spliterator.NONNULL + Spliterator.IMMUTABLE; - } - - @Override - public long estimateSize() { - return Long.MAX_VALUE; - } - } -} --- /dev/null 2016-12-10 08:16:53.177999985 +0000 +++ new/src/java.base/share/classes/jdk/internal/module/SystemModuleFinder.java 2016-12-15 09:19:30.365321167 +0000 @@ -0,0 +1,441 @@ +/* + * 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"); + // ImageReader used to access all modules in the image + private static final ImageReader imageReader; + + // 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(); + imageReader = ImageReaderFactory.getImageReader(); + + INSTANCE = new SystemModuleFinder(); + + initTime.addElapsedTimeFrom(t0); + } + + 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 imageReader.getModuleNames(); + } + + + /** + * Helper class to use the recorded hashes to create a HashSupplier + */ + private static class Hashes { + static Map hashes = new HashMap<>(); + + static void add(ModuleHashes recordedHashes) { + if (recordedHashes != null) { + hashes.putAll(recordedHashes.hashes()); + } + } + + static HashSupplier hashSupplierFor(String name) { + if (!hashes.containsKey(name)) + return null; + + return new HashSupplier() { + @Override + public byte[] generate(String algorithm) { + return hashes.get(name); + } + }; + } + } + + // the set of modules in the run-time image + private final Set modules; + + // maps module name to module reference + private final Map nameToModule; + + 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; + ModuleHashes[] recordedHashes; + ModuleResolution[] moduleResolutions; + + // fast loading of ModuleDescriptor of system modules + if (isFastPathSupported() && !disabled) { + descriptors = SystemModules.descriptors(); + recordedHashes = SystemModules.hashes(); + moduleResolutions = SystemModules.moduleResolutions(); + } else { + // if fast loading of ModuleDescriptors is disabled + // fallback to read module-info.class + descriptors = new ModuleDescriptor[n]; + recordedHashes = new ModuleHashes[n]; + moduleResolutions = new ModuleResolution[n]; + 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(); + recordedHashes[i] = attrs.recordedHashes(); + moduleResolutions[i] = attrs.moduleResolution(); + } + } + + // record the hashes to build HashSupplier + for (ModuleHashes mh : recordedHashes) { + Hashes.add(mh); + } + + ModuleReference[] mods = new ModuleReference[n]; + + @SuppressWarnings(value = {"rawtypes", "unchecked"}) + Entry[] map + = (Entry[])new Entry[n]; + + for (int i = 0; i < n; i++) { + ModuleDescriptor md = descriptors[i]; + + // create the ModuleReference + ModuleReference mref = toModuleReference(md, + recordedHashes[i], + Hashes.hashSupplierFor(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 find(String name) { + Objects.requireNonNull(name); + return Optional.ofNullable(nameToModule.get(name)); + } + + @Override + public Set findAll() { + return modules; + } + + private ModuleReference toModuleReference(ModuleDescriptor md, + ModuleHashes recordedHashes, + HashSupplier hasher, + ModuleResolution mres) { + String mn = md.name(); + URI uri = JNUA.create("jrt", "/".concat(mn)); + + Supplier readerSupplier = new Supplier<>() { + @Override + public ModuleReader get() { + return new ImageModuleReader(mn, uri); + } + }; + + ModuleReference mref = + new ModuleReferenceImpl(md, uri, readerSupplier, null, + recordedHashes, hasher, mres); + + // may need a reference to a patched module if --patch-module specified + mref = ModuleBootstrap.patcher().patchIfNeeded(mref); + + return mref; + } + + + /** + * 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"); + if (imageReader != null) { + return imageReader.findLocation(module, name); + } else { + // not an images build + return null; + } + } + + @Override + public Optional 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 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 read(String name) throws IOException { + ImageLocation location = findImageLocation(name); + if (location != null) { + return Optional.of(imageReader.getResourceBuffer(location)); + } else { + return Optional.empty(); + } + } + + @Override + public void release(ByteBuffer bb) { + Objects.requireNonNull(bb); + ImageReader.releaseByteBuffer(bb); + } + + @Override + public Stream list() throws IOException { + if (closed) + throw new IOException("ModuleReader is closed"); + + Spliterator 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 { + final String moduleRoot; + final Deque stack; + Iterator 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 = imageReader.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 = imageReader.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 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 trySplit() { + return null; + } + + @Override + public int characteristics() { + return Spliterator.DISTINCT + Spliterator.NONNULL + Spliterator.IMMUTABLE; + } + + @Override + public long estimateSize() { + return Long.MAX_VALUE; + } + } +}