8266851: Implement JEP 403: Strongly Encapsulate JDK Internals

Co-authored-by: Alan Bateman <alanb@openjdk.org>
Reviewed-by: mchung, alanb, hseigel
This commit is contained in:
Mark Reinhold 2021-05-26 20:55:53 +00:00
parent 8c4719a588
commit e63023546a
26 changed files with 50 additions and 2842 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2021, 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
@ -56,8 +56,6 @@ import jdk.internal.loader.BuiltinClassLoader;
import jdk.internal.loader.BootLoader;
import jdk.internal.loader.ClassLoaders;
import jdk.internal.misc.CDS;
import jdk.internal.misc.VM;
import jdk.internal.module.IllegalAccessLogger;
import jdk.internal.module.ModuleLoaderMap;
import jdk.internal.module.ServicesCatalog;
import jdk.internal.module.Resources;
@ -903,27 +901,8 @@ public final class Module implements AnnotatedElement {
return;
// check if the package is already exported/open to other
if (implIsExportedOrOpen(pn, other, open)) {
// if the package is exported/open for illegal access then we need
// to record that it has also been exported/opened reflectively so
// that the IllegalAccessLogger doesn't emit a warning.
boolean needToAdd = false;
if (!other.isNamed()) {
IllegalAccessLogger l = IllegalAccessLogger.illegalAccessLogger();
if (l != null) {
if (open) {
needToAdd = l.isOpenForIllegalAccess(this, pn);
} else {
needToAdd = l.isExportedForIllegalAccess(this, pn);
}
}
}
if (!needToAdd) {
// nothing to do
return;
}
}
if (implIsExportedOrOpen(pn, other, open))
return;
// can only export a package in the module
if (!descriptor.packages().contains(pn)) {

View file

@ -28,7 +28,6 @@ package java.lang.invoke;
import jdk.internal.access.SharedSecrets;
import jdk.internal.misc.Unsafe;
import jdk.internal.misc.VM;
import jdk.internal.module.IllegalAccessLogger;
import jdk.internal.org.objectweb.asm.ClassReader;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.Type;
@ -262,13 +261,6 @@ public class MethodHandles {
// M2 != M1, set previous lookup class to M1 and drop MODULE access
newPreviousClass = callerClass;
newModes &= ~Lookup.MODULE;
if (!callerModule.isNamed() && targetModule.isNamed()) {
IllegalAccessLogger logger = IllegalAccessLogger.illegalAccessLogger();
if (logger != null) {
logger.logIfOpenedForIllegalAccess(caller, targetClass);
}
}
}
return Lookup.newLookup(targetClass, newPreviousClass, newModes);
}

View file

@ -32,7 +32,6 @@ import java.security.AccessController;
import jdk.internal.access.SharedSecrets;
import jdk.internal.misc.VM;
import jdk.internal.module.IllegalAccessLogger;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;
import jdk.internal.reflect.ReflectionFactory;
@ -324,7 +323,6 @@ public class AccessibleObject implements AnnotatedElement {
if (isClassPublic && declaringModule.isExported(pn, callerModule)) {
// member is public
if (Modifier.isPublic(modifiers)) {
logIfExportedForIllegalAccess(caller, declaringClass);
return true;
}
@ -332,14 +330,12 @@ public class AccessibleObject implements AnnotatedElement {
if (Modifier.isProtected(modifiers)
&& Modifier.isStatic(modifiers)
&& isSubclassOf(caller, declaringClass)) {
logIfExportedForIllegalAccess(caller, declaringClass);
return true;
}
}
// package is open to caller
if (declaringModule.isOpen(pn, callerModule)) {
logIfOpenedForIllegalAccess(caller, declaringClass);
return true;
}
@ -373,30 +369,6 @@ public class AccessibleObject implements AnnotatedElement {
return false;
}
private void logIfOpenedForIllegalAccess(Class<?> caller, Class<?> declaringClass) {
Module callerModule = caller.getModule();
Module targetModule = declaringClass.getModule();
// callerModule is null during early startup
if (callerModule != null && !callerModule.isNamed() && targetModule.isNamed()) {
IllegalAccessLogger logger = IllegalAccessLogger.illegalAccessLogger();
if (logger != null) {
logger.logIfOpenedForIllegalAccess(caller, declaringClass, this::toShortString);
}
}
}
private void logIfExportedForIllegalAccess(Class<?> caller, Class<?> declaringClass) {
Module callerModule = caller.getModule();
Module targetModule = declaringClass.getModule();
// callerModule is null during early startup
if (callerModule != null && !callerModule.isNamed() && targetModule.isNamed()) {
IllegalAccessLogger logger = IllegalAccessLogger.illegalAccessLogger();
if (logger != null) {
logger.logIfExportedForIllegalAccess(caller, declaringClass, this::toShortString);
}
}
}
/**
* Returns a short descriptive string to describe this object in log messages.
*/
@ -743,9 +715,6 @@ public class AccessibleObject implements AnnotatedElement {
return false;
}
// access okay
logIfExportedForIllegalAccess(caller, memberClass);
// Success: Update the cache.
Object cache = (targetClass != null
&& Modifier.isProtected(modifiers)

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2021, 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
@ -68,14 +68,4 @@ class ExplodedSystemModules implements SystemModules {
public Map<String, Set<String>> moduleReads() {
throw new InternalError();
}
@Override
public Map<String, Set<String>> concealedPackagesToOpen() {
return Map.of();
}
@Override
public Map<String, Set<String>> exportedPackagesToOpen() {
return Map.of();
}
}

View file

@ -1,407 +0,0 @@
/*
* Copyright (c) 2017, 2020, 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.PrintStream;
import java.lang.invoke.MethodHandles;
import java.net.URL;
import java.security.AccessController;
import java.security.CodeSource;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.StringJoiner;
import java.util.WeakHashMap;
import java.util.function.Supplier;
import static java.util.Collections.*;
import jdk.internal.access.JavaLangAccess;
import jdk.internal.access.SharedSecrets;
/**
* Supports logging of access to members of exported and concealed packages
* that are opened to code in unnamed modules for illegal access.
*/
public final class IllegalAccessLogger {
/**
* Logger modes
*/
public enum Mode {
/**
* Prints a warning when an illegal access succeeds and then
* discards the logger so that there is no further output.
*/
ONESHOT,
/**
* Print warnings when illegal access succeeds
*/
WARN,
/**
* Prints warnings and a stack trace when illegal access succeeds
*/
DEBUG,
}
/**
* A builder for IllegalAccessLogger objects.
*/
public static class Builder {
private final Mode mode;
private final PrintStream warningStream;
private final Map<Module, Set<String>> moduleToConcealedPackages;
private final Map<Module, Set<String>> moduleToExportedPackages;
private boolean complete;
private void ensureNotComplete() {
if (complete) throw new IllegalStateException();
}
/**
* Creates a builder.
*/
public Builder(Mode mode, PrintStream warningStream) {
this.mode = mode;
this.warningStream = warningStream;
this.moduleToConcealedPackages = new HashMap<>();
this.moduleToExportedPackages = new HashMap<>();
}
/**
* Adding logging of reflective-access to any member of a type in
* otherwise concealed packages.
*/
public Builder logAccessToConcealedPackages(Module m, Set<String> packages) {
ensureNotComplete();
moduleToConcealedPackages.put(m, unmodifiableSet(packages));
return this;
}
/**
* Adding logging of reflective-access to non-public members/types in
* otherwise exported (not open) packages.
*/
public Builder logAccessToExportedPackages(Module m, Set<String> packages) {
ensureNotComplete();
moduleToExportedPackages.put(m, unmodifiableSet(packages));
return this;
}
/**
* Builds the IllegalAccessLogger and sets it as the system-wide logger.
*/
public void complete() {
Map<Module, Set<String>> map1 = unmodifiableMap(moduleToConcealedPackages);
Map<Module, Set<String>> map2 = unmodifiableMap(moduleToExportedPackages);
logger = new IllegalAccessLogger(mode, warningStream, map1, map2);
complete = true;
}
}
// need access to java.lang.Module
private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
// system-wide IllegalAccessLogger
private static volatile IllegalAccessLogger logger;
// logger mode
private final Mode mode;
// the print stream to send the warnings
private final PrintStream warningStream;
// module -> packages open for illegal access
private final Map<Module, Set<String>> moduleToConcealedPackages;
private final Map<Module, Set<String>> moduleToExportedPackages;
// caller -> usages
private final Map<Class<?>, Usages> callerToUsages = new WeakHashMap<>();
private IllegalAccessLogger(Mode mode,
PrintStream warningStream,
Map<Module, Set<String>> moduleToConcealedPackages,
Map<Module, Set<String>> moduleToExportedPackages)
{
this.mode = mode;
this.warningStream = warningStream;
this.moduleToConcealedPackages = moduleToConcealedPackages;
this.moduleToExportedPackages = moduleToExportedPackages;
}
/**
* Returns the system-wide IllegalAccessLogger or {@code null} if there is
* no logger.
*/
public static IllegalAccessLogger illegalAccessLogger() {
return logger;
}
/**
* Returns true if the module exports a concealed package for illegal
* access.
*/
public boolean isExportedForIllegalAccess(Module module, String pn) {
Set<String> packages = moduleToConcealedPackages.get(module);
if (packages != null && packages.contains(pn))
return true;
return false;
}
/**
* Returns true if the module opens a concealed or exported package for
* illegal access.
*/
public boolean isOpenForIllegalAccess(Module module, String pn) {
if (isExportedForIllegalAccess(module, pn))
return true;
Set<String> packages = moduleToExportedPackages.get(module);
if (packages != null && packages.contains(pn))
return true;
return false;
}
/**
* Logs access to the member of a target class by a caller class if the class
* is in a package that is exported for illegal access.
*
* The {@code whatSupplier} supplies the message that describes the member.
*/
public void logIfExportedForIllegalAccess(Class<?> caller,
Class<?> target,
Supplier<String> whatSupplier) {
Module targetModule = target.getModule();
String targetPackage = target.getPackageName();
if (isExportedForIllegalAccess(targetModule, targetPackage)) {
Module callerModule = caller.getModule();
if (!JLA.isReflectivelyExported(targetModule, targetPackage, callerModule)) {
log(caller, whatSupplier.get());
}
}
}
/**
* Logs access to the member of a target class by a caller class if the class
* is in a package that is opened for illegal access.
*
* The {@code what} parameter supplies the message that describes the member.
*/
public void logIfOpenedForIllegalAccess(Class<?> caller,
Class<?> target,
Supplier<String> whatSupplier) {
Module targetModule = target.getModule();
String targetPackage = target.getPackageName();
if (isOpenForIllegalAccess(targetModule, targetPackage)) {
Module callerModule = caller.getModule();
if (!JLA.isReflectivelyOpened(targetModule, targetPackage, callerModule)) {
log(caller, whatSupplier.get());
}
}
}
/**
* Logs access by caller lookup if the target class is in a package that is
* opened for illegal access.
*/
public void logIfOpenedForIllegalAccess(MethodHandles.Lookup caller, Class<?> target) {
Module targetModule = target.getModule();
String targetPackage = target.getPackageName();
if (isOpenForIllegalAccess(targetModule, targetPackage)) {
Class<?> callerClass = caller.lookupClass();
Module callerModule = callerClass.getModule();
if (!JLA.isReflectivelyOpened(targetModule, targetPackage, callerModule)) {
URL url = codeSource(callerClass);
final String source;
if (url == null) {
source = callerClass.getName();
} else {
source = callerClass.getName() + " (" + url + ")";
}
log(callerClass, target.getName(), () ->
"WARNING: Illegal reflective access using Lookup on " + source
+ " to " + target);
}
}
}
/**
* Logs access by a caller class. The {@code what} parameter describes
* the member being accessed.
*/
private void log(Class<?> caller, String what) {
log(caller, what, () -> {
URL url = codeSource(caller);
String source = caller.getName();
if (url != null)
source += " (" + url + ")";
return "WARNING: Illegal reflective access by " + source + " to " + what;
});
}
/**
* Log access by a caller. The {@code what} parameter describes the class or
* member that is being accessed. The {@code msgSupplier} supplies the log
* message.
*
* To reduce output, this method only logs the access if it hasn't been seen
* previously. "Seen previously" is implemented as a map of caller class -> Usage,
* where a Usage is the "what" and a hash of the stack trace. The map has weak
* keys so it can be expunged when the caller is GC'ed/unloaded.
*/
private void log(Class<?> caller, String what, Supplier<String> msgSupplier) {
if (mode == Mode.ONESHOT) {
synchronized (IllegalAccessLogger.class) {
// discard the system wide logger
if (logger == null)
return;
logger = null;
}
warningStream.println(loudWarning(caller, msgSupplier));
return;
}
// stack trace without the top-most frames in java.base
List<StackWalker.StackFrame> stack = StackWalkerHolder.INSTANCE.walk(s ->
s.dropWhile(this::isJavaBase)
.limit(32)
.toList()
);
// record usage if this is the first (or not recently recorded)
Usage u = new Usage(what, hash(stack));
boolean added;
synchronized (this) {
added = callerToUsages.computeIfAbsent(caller, k -> new Usages()).add(u);
}
// print warning if this is the first (or not a recent) usage
if (added) {
String msg = msgSupplier.get();
if (mode == Mode.DEBUG) {
StringBuilder sb = new StringBuilder(msg);
stack.forEach(f ->
sb.append(System.lineSeparator()).append("\tat " + f)
);
msg = sb.toString();
}
warningStream.println(msg);
}
}
/**
* Returns the code source for the given class or null if there is no code source
*/
private URL codeSource(Class<?> clazz) {
PrivilegedAction<ProtectionDomain> pa = clazz::getProtectionDomain;
CodeSource cs = AccessController.doPrivileged(pa).getCodeSource();
return (cs != null) ? cs.getLocation() : null;
}
private String loudWarning(Class<?> caller, Supplier<String> msgSupplier) {
StringJoiner sj = new StringJoiner(System.lineSeparator());
sj.add("WARNING: An illegal reflective access operation has occurred");
sj.add(msgSupplier.get());
sj.add("WARNING: Please consider reporting this to the maintainers of "
+ caller.getName());
sj.add("WARNING: Use --illegal-access=warn to enable warnings of further"
+ " illegal reflective access operations");
sj.add("WARNING: All illegal access operations will be denied in a"
+ " future release");
return sj.toString();
}
private static class StackWalkerHolder {
static final StackWalker INSTANCE;
static {
PrivilegedAction<StackWalker> pa = () ->
StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
INSTANCE = AccessController.doPrivileged(pa);
}
}
/**
* Returns true if the stack frame is for a class in java.base.
*/
private boolean isJavaBase(StackWalker.StackFrame frame) {
Module caller = frame.getDeclaringClass().getModule();
return "java.base".equals(caller.getName());
}
/**
* Computes a hash code for the give stack frames. The hash code is based
* on the class, method name, and BCI.
*/
private int hash(List<StackWalker.StackFrame> stack) {
int hash = 0;
for (StackWalker.StackFrame frame : stack) {
hash = (31 * hash) + Objects.hash(frame.getDeclaringClass(),
frame.getMethodName(),
frame.getByteCodeIndex());
}
return hash;
}
private static class Usage {
private final String what;
private final int stack;
Usage(String what, int stack) {
this.what = what;
this.stack = stack;
}
@Override
public int hashCode() {
return what.hashCode() ^ stack;
}
@Override
public boolean equals(Object ob) {
if (ob instanceof Usage) {
Usage that = (Usage)ob;
return what.equals(that.what) && stack == (that.stack);
} else {
return false;
}
}
}
@SuppressWarnings("serial")
private static class Usages extends LinkedHashMap<Usage, Boolean> {
Usages() { }
boolean add(Usage u) {
return (putIfAbsent(u, Boolean.TRUE) == null);
}
@Override
protected boolean removeEldestEntry(Map.Entry<Usage, Boolean> oldest) {
// prevent map growing too big, say where a utility class
// is used by generated code to do illegal access
return size() > 16;
}
}
}

View file

@ -1,130 +0,0 @@
/*
* Copyright (c) 2017, 2019, 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 sun.nio.cs.UTF_8;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UncheckedIOException;
import java.lang.module.ModuleDescriptor;
import java.lang.module.ModuleFinder;
import java.lang.module.ModuleReference;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* Generates the maps of concealed and exported packages to open at run-time.
*
* This is used at run-time for exploded builds, and at link-time to generate
* the maps for the system modules in the run-time image.
*/
public class IllegalAccessMaps {
private final Map<String, Set<String>> concealedPackagesToOpen;
private final Map<String, Set<String>> exportedPackagesToOpen;
private IllegalAccessMaps(Map<String, Set<String>> map1,
Map<String, Set<String>> map2) {
this.concealedPackagesToOpen = map1;
this.exportedPackagesToOpen = map2;
}
/**
* Returns the map of concealed packages to open. The map key is the
* module name, the value is the set of concealed packages to open.
*/
public Map<String, Set<String>> concealedPackagesToOpen() {
return concealedPackagesToOpen;
}
/**
* Returns the map of exported packages to open. The map key is the
* module name, the value is the set of exported packages to open.
*/
public Map<String, Set<String>> exportedPackagesToOpen() {
return exportedPackagesToOpen;
}
/**
* Generate the maps of module to concealed and exported packages for
* the system modules that are observable with the given module finder.
*/
public static IllegalAccessMaps generate(ModuleFinder finder) {
Map<String, ModuleDescriptor> map = new HashMap<>();
finder.findAll().stream()
.map(ModuleReference::descriptor)
.forEach(md -> md.packages().forEach(pn -> map.putIfAbsent(pn, md)));
Map<String, Set<String>> concealedPackagesToOpen = new HashMap<>();
Map<String, Set<String>> exportedPackagesToOpen = new HashMap<>();
String rn = "jdk8_packages.dat";
InputStream in = IllegalAccessMaps.class.getResourceAsStream(rn);
if (in == null) {
throw new InternalError(rn + " not found");
}
try (BufferedReader br = new BufferedReader(
new InputStreamReader(in, UTF_8.INSTANCE)))
{
br.lines()
.filter(line -> !line.isEmpty() && !line.startsWith("#"))
.forEach(pn -> {
ModuleDescriptor descriptor = map.get(pn);
if (descriptor != null && !isOpen(descriptor, pn)) {
String name = descriptor.name();
if (isExported(descriptor, pn)) {
exportedPackagesToOpen.computeIfAbsent(name,
k -> new HashSet<>()).add(pn);
} else {
concealedPackagesToOpen.computeIfAbsent(name,
k -> new HashSet<>()).add(pn);
}
}
});
} catch (IOException ioe) {
throw new UncheckedIOException(ioe);
}
return new IllegalAccessMaps(concealedPackagesToOpen, exportedPackagesToOpen);
}
private static boolean isExported(ModuleDescriptor descriptor, String pn) {
return descriptor.exports()
.stream()
.anyMatch(e -> e.source().equals(pn) && !e.isQualified());
}
private static boolean isOpen(ModuleDescriptor descriptor, String pn) {
return descriptor.opens()
.stream()
.anyMatch(e -> e.source().equals(pn) && !e.isQualified());
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2021, 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
@ -38,7 +38,6 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@ -147,8 +146,7 @@ public final class ModuleBootstrap {
getProperty("jdk.module.limitmods") == null && // --limit-modules
getProperty("jdk.module.addreads.0") == null && // --add-reads
getProperty("jdk.module.addexports.0") == null && // --add-exports
getProperty("jdk.module.addopens.0") == null && // --add-opens
getProperty("jdk.module.illegalAccess") == null; // --illegal-access
getProperty("jdk.module.addopens.0") == null; // --add-opens
}
/**
@ -189,7 +187,6 @@ public final class ModuleBootstrap {
String mainModule = System.getProperty("jdk.module.main");
Set<String> addModules = addModules();
Set<String> limitModules = limitModules();
String illegalAccess = getAndRemoveProperty("jdk.module.illegalAccess");
PrintStream traceOutput = null;
String trace = getAndRemoveProperty("jdk.module.showModuleResolution");
@ -221,8 +218,7 @@ public final class ModuleBootstrap {
&& !haveModulePath
&& addModules.isEmpty()
&& limitModules.isEmpty()
&& !isPatched
&& illegalAccess == null) {
&& !isPatched) {
systemModuleFinder = archivedModuleGraph.finder();
hasSplitPackages = archivedModuleGraph.hasSplitPackages();
hasIncubatorModules = archivedModuleGraph.hasIncubatorModules();
@ -455,19 +451,10 @@ public final class ModuleBootstrap {
checkIncubatingStatus(cf);
}
// --add-reads, --add-exports/--add-opens, and --illegal-access
// --add-reads, --add-exports/--add-opens
addExtraReads(bootLayer);
boolean extraExportsOrOpens = addExtraExportsAndOpens(bootLayer);
if (illegalAccess != null) {
assert systemModules != null;
addIllegalAccess(illegalAccess,
systemModules,
upgradeModulePath,
bootLayer,
extraExportsOrOpens);
}
Counters.add("jdk.module.boot.7.adjustModulesTime");
// save module finders for later use
@ -779,96 +766,6 @@ public final class ModuleBootstrap {
}
}
/**
* Process the --illegal-access option to open packages of system modules
* in the boot layer to code in unnamed modules.
*/
private static void addIllegalAccess(String illegalAccess,
SystemModules systemModules,
ModuleFinder upgradeModulePath,
ModuleLayer bootLayer,
boolean extraExportsOrOpens) {
if (illegalAccess.equals("deny"))
return; // nothing to do
IllegalAccessLogger.Mode mode = switch (illegalAccess) {
case "permit" -> IllegalAccessLogger.Mode.ONESHOT;
case "warn" -> IllegalAccessLogger.Mode.WARN;
case "debug" -> IllegalAccessLogger.Mode.DEBUG;
default -> {
fail("Value specified to --illegal-access not recognized:"
+ " '" + illegalAccess + "'");
yield null;
}
};
var builder = new IllegalAccessLogger.Builder(mode, System.err);
Map<String, Set<String>> concealedPackagesToOpen = systemModules.concealedPackagesToOpen();
Map<String, Set<String>> exportedPackagesToOpen = systemModules.exportedPackagesToOpen();
if (concealedPackagesToOpen.isEmpty() && exportedPackagesToOpen.isEmpty()) {
// need to generate (exploded build)
IllegalAccessMaps maps = IllegalAccessMaps.generate(limitedFinder());
concealedPackagesToOpen = maps.concealedPackagesToOpen();
exportedPackagesToOpen = maps.exportedPackagesToOpen();
}
// open specific packages in the system modules
Set<String> emptySet = Set.of();
for (Module m : bootLayer.modules()) {
ModuleDescriptor descriptor = m.getDescriptor();
String name = m.getName();
// skip open modules
if (descriptor.isOpen()) {
continue;
}
// skip modules loaded from the upgrade module path
if (upgradeModulePath != null
&& upgradeModulePath.find(name).isPresent()) {
continue;
}
Set<String> concealedPackages = concealedPackagesToOpen.getOrDefault(name, emptySet);
Set<String> exportedPackages = exportedPackagesToOpen.getOrDefault(name, emptySet);
// refresh the set of concealed and exported packages if needed
if (extraExportsOrOpens) {
concealedPackages = new HashSet<>(concealedPackages);
exportedPackages = new HashSet<>(exportedPackages);
Iterator<String> iterator = concealedPackages.iterator();
while (iterator.hasNext()) {
String pn = iterator.next();
if (m.isExported(pn, BootLoader.getUnnamedModule())) {
// concealed package is exported to ALL-UNNAMED
iterator.remove();
exportedPackages.add(pn);
}
}
iterator = exportedPackages.iterator();
while (iterator.hasNext()) {
String pn = iterator.next();
if (m.isOpen(pn, BootLoader.getUnnamedModule())) {
// exported package is opened to ALL-UNNAMED
iterator.remove();
}
}
}
// log reflective access to all types in concealed packages
builder.logAccessToConcealedPackages(m, concealedPackages);
// log reflective access to non-public members/types in exported packages
builder.logAccessToExportedPackages(m, exportedPackages);
// open the packages to unnamed modules
JLA.addOpensToAllUnnamed(m, concealedPackages, exportedPackages);
}
builder.complete();
}
/**
* Decodes the values of --add-reads, -add-exports, --add-opens or
* --patch-modules options that are encoded in system properties.

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2021, 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
@ -83,16 +83,4 @@ interface SystemModules {
* by this SystemModules object.
*/
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.
*/
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.
*/
Map<String, Set<String>> exportedPackagesToOpen();
}

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2007, 2021, 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
@ -185,11 +185,6 @@ java.launcher.X.usage=\n\
\ --add-opens <module>/<package>=<target-module>(,<target-module>)*\n\
\ updates <module> to open <package> to\n\
\ <target-module>, regardless of module declaration.\n\
\ --illegal-access=<value>\n\
\ permit or deny access to members of types in named modules\n\
\ by code in unnamed modules.\n\
\ <value> is one of "deny", "permit", "warn", or "debug"\n\
\ This option will be removed in a future release.\n\
\ --limit-modules <module name>[,<module name>...]\n\
\ limit the universe of observable modules\n\
\ --patch-module <module>=<file>({0}<file>)*\n\